// ---------------- 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 . '
'.$nonce.'
'; }); 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 = '
'; foreach($rows as $r){ $file = esc_url($r->file_url); $out .= ''; } $out .= '
Lead IDDoc TypeFileStatusDate
#'.intval($r->lead_id).' '.esc_html($r->doc_type).' View '.esc_html(strtoupper($r->status)).' '.esc_html($r->created_at).'
'; 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 = '
'; foreach($rows as $r){ $lead_id = intval($r->id); $url = add_query_arg(['lead_id'=>$lead_id], $base) . '#uploadDocs'; $out .= ''; } $out .= '
Lead IDLoanAmountCityStatusDocuments
#'.$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
'; 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 = '
'; foreach($rows as $r){ $lead_id = intval($r->id); $url = add_query_arg(['lead_id'=>$lead_id], $base) . '#uploadDocs'; $out .= ''; } $out .= '
Lead IDNameMobileLoanAmountStatusDocuments
#'.$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
'; 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 = '
'; foreach($rows as $r){ $lead_id = intval($r->id); $url = add_query_arg(['lead_id'=>$lead_id], $base) . '#uploadDocs'; $out .= ''; } $out .= '
Lead IDNameMobileLoanAmountStatusDocuments
#'.$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
'; 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 = '
Reset
'; if(!$rows) return $notice . $form . '
No documents found for selected filters.
'; $action = esc_url(admin_url('admin-post.php')); $out = $notice . $form . '
'; 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.' '; $rejectBtn = ' '.$reject.' '; $out .= ''; } $out .= '
Doc IDLead IDTypeFileUploaded ByStatusActionDate
#'.$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).'
'; 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.'
'; }); // ---------------- 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.'
'; 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, ''); }