Apna Tax Consultant

default

/** * Plugin Name: GST Report Viewer * Description: GSTR-3B Report + Work List (Submit by 9 AM Tomorrow) + Upload Work with Auto-Close Timer. * Version: 2.0.0 * Author: Your Name * Text Domain: gst-report-viewer * License: GPL2 */ if ( ! defined( 'ABSPATH' ) ) { exit; } class GST_Report_Viewer { private $pdf_url = 'https://apnataxconsultant.com/wp-content/uploads/2025/11/Invoice_Data_July_Sept_2025.pdf'; private $menu_title = 'GST Calculator & Reports'; public function __construct() { add_action( 'admin_menu', [ $this, 'add_admin_menu' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); add_action( 'wp_ajax_gst_upload_file', [ $this, 'ajax_handle_upload' ] ); add_action( 'wp_ajax_gst_delete_file', [ $this, 'ajax_handle_delete' ] ); add_action( 'wp_ajax_gst_toggle_status', [ $this, 'ajax_toggle_status' ] ); add_action( 'admin_init', [ $this, 'maybe_create_table' ] ); register_activation_hook( __FILE__, [ $this, 'activate' ] ); } /* ------------------------------------------------------------------ */ /* Auto-create table */ /* ------------------------------------------------------------------ */ public function maybe_create_table() { if ( ! current_user_can( 'manage_options' ) ) return; global $wpdb; $table = $wpdb->prefix . 'gst_uploads'; if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) !== $table ) { $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table ( id mediumint(9) NOT NULL AUTO_INCREMENT, file_name varchar(255) NOT NULL, file_url varchar(512) NOT NULL, uploaded_on datetime NOT NULL, status varchar(10) DEFAULT 'pending', PRIMARY KEY (id) ) $charset_collate;"; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; dbDelta( $sql ); set_transient( 'gst_table_created', true, 30 ); } else { $column_exists = $wpdb->get_results( "SHOW COLUMNS FROM `$table` LIKE 'status'" ); if ( empty( $column_exists ) ) { $wpdb->query( "ALTER TABLE `$table` ADD status VARCHAR(10) DEFAULT 'pending' AFTER uploaded_on" ); } } } /* ------------------------------------------------------------------ */ /* Activation */ /* ------------------------------------------------------------------ */ public function activate() { $this->maybe_create_table(); $upload = wp_upload_dir(); $gst_dir = $upload['basedir'] . '/gst-uploads'; if ( ! file_exists( $gst_dir ) ) { wp_mkdir_p( $gst_dir ); file_put_contents( $gst_dir . '/.htaccess', "Options -Indexes\n\ndeny from all\n" ); } } /* ------------------------------------------------------------------ */ /* Admin menu – GSTR-3B + Work List + Upload */ /* ------------------------------------------------------------------ */ public function add_admin_menu() { add_menu_page( $this->menu_title, $this->menu_title, 'manage_options', 'gst-report-viewer', [ $this, 'render_main_page' ], 'dashicons-calculator', 58 ); // Submenu: GSTR-3B (was GST Reports) add_submenu_page( 'gst-report-viewer', 'GSTR-3B', 'GSTR-3B', 'manage_options', 'gst-report-viewer', [ $this, 'render_main_page' ] ); // Submenu: Work List add_submenu_page( 'gst-report-viewer', 'Work List', 'Work List', 'manage_options', 'gst-work-list', [ $this, 'render_work_list_page' ] ); // Submenu: Upload Your Work add_submenu_page( 'gst-report-viewer', 'Upload Your Work', 'Upload Your Work', 'manage_options', 'gst-report-viewer-uploads', [ $this, 'render_upload_page' ] ); // Rename first item add_action( 'admin_init', function() { global $submenu; if ( isset( $submenu['gst-report-viewer'][0] ) ) { $submenu['gst-report-viewer'][0][0] = 'GSTR-3B'; } }); } /* ------------------------------------------------------------------ */ /* Enqueue assets + CSS + JS */ /* ------------------------------------------------------------------ */ public function enqueue_assets( $hook ) { $allowed = [ 'toplevel_page_gst-report-viewer', 'gst-calculator-reports_page_gst-report-viewer', 'gst-calculator-reports_page_gst-work-list', 'gst-calculator-reports_page_gst-report-viewer-uploads', ]; if ( ! in_array( $hook, $allowed, true ) ) return; wp_enqueue_media(); wp_add_inline_style( 'wp-admin', ' .gst-pdf-wrapper {width:100%;height:calc(100vh - 100px);border:none;margin-top:20px;} .gst-download-btn {display:inline-block;margin:8px 0;padding:6px 12px;background:#0073aa;color:#fff;text-decoration:none;border-radius:3px;font-size:13px;} .gst-download-btn:hover {background:#005a87;} .gst-upload-area {border:2px dashed #ccc;padding:30px;text-align:center;margin:25px 0;background:#f9f9f9;cursor:pointer;} .gst-upload-area.dragover {border-color:#0073aa;background:#eef;} .gst-recent-uploads {margin-top:20px;padding:15px;background:#fff;border:1px solid #ccd0d4;border-radius:4px;} .gst-recent-uploads h3 {margin:0 0 10px;font-size:16px;} .gst-recent-list {list-style:none;margin:0;padding:0;} .gst-recent-list li {padding:10px 0;border-bottom:1px solid #eee;display:flex;justify-content:space-between;align-items:center;} .gst-recent-list li:last-child {border-bottom:none;} .gst-delete-btn {color:#a00;font-size:12px;cursor:pointer;} .gst-delete-btn:hover {color:#d00;} .gst-status-btn {font-size:18px;cursor:pointer;margin:0 8px;} .gst-status-btn.correct {color:green;} .gst-status-btn.wrong {color:red;} .gst-status-btn.pending {color:#999;font-style:italic;} #gst-upload-progress {margin-top:10px;font-weight:bold;} .gst-notice {padding:10px;margin:10px 0;background:#dff0d8;border:1px solid #d6e9c6;color:#3c763d;border-radius:4px;} .gst-date {color:#555;font-size:13px;} /* Work List */ .gst-work-list-container { background: #fff; border: 1px solid #c3c4c7; border-radius: 8px; padding: 24px; margin: 20px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.06); } .gst-work-list-title { margin: 0 0 10px; font-size: 20px; color: #1d2327; font-weight: 600; display: flex; align-items: center; gap: 8px; } .gst-work-list-title::before { content: "\f471"; font-family: dashicons; color: #0073aa; font-size: 22px; } .gst-work-date { margin: 0 0 24px; color: #0073aa; font-size: 15px; font-weight: 500; } .gst-work-cards { display: flex; flex-direction: column; gap: 18px; } .gst-work-card { display: flex; align-items: flex-start; background: #f8f9fa; padding: 18px; border-radius: 8px; border-left: 5px solid #0073aa; transition: all 0.25s ease; } .gst-work-card:hover { background: #eef4ff; transform: translateY(-2px); box-shadow: 0 6px 12px rgba(0,115,170,0.12); } .gst-work-icon { flex-shrink: 0; width: 36px; height: 36px; background: #0073aa; color: white; font-weight: bold; font-size: 15px; display: flex; align-items: center; justify-content: center; border-radius: 50%; margin-right: 16px; } .gst-work-content h4 { margin: 0 0 6px; font-size: 16px; color: #1d2327; font-weight: 600; } .gst-work-content p { margin: 0; font-size: 14px; color: #555; line-height: 1.5; } /* Deadline Alert */ .gst-deadline-alert { background: #fff8e1; border: 1px solid #ffeb3b; border-radius: 6px; padding: 14px 16px; margin: 16px 0; font-size: 14px; color: #333; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .gst-deadline-alert .dashicons { color: #ff8f00; font-size: 18px; } .gst-countdown { font-weight: bold; color: #d32f2f; margin-left: 6px; } .gst-countdown.warning { animation: blink 1.5s infinite; } .gst-countdown.submitted { color: #2e7d32; font-weight: bold; } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .gst-upload-reminder { margin-top: 20px; padding: 12px; background: #e3f2fd; border-left: 4px solid #0073aa; font-size: 14px; color: #1565c0; } .gst-upload-reminder a { color: #0073aa; text-decoration: underline; } .gst-upload-reminder a:hover { color: #005a87; } @media (max-width: 600px) { .gst-work-card { flex-direction: column; } .gst-work-icon { margin-bottom: 12px; margin-right: 0; } } ' ); wp_register_script( 'gst-upload-js', false, [ 'jquery' ], null, true ); wp_add_inline_script( 'gst-upload-js', ' jQuery(function($){ var uploadCount = ' . ( $this->get_upload_count_today() ) . '; // Upload Logic var $area = $(".gst-upload-area"), $input = $("#gsc-file-input"), $prog = $("#gst-upload-progress"), $msg = $("#gst-upload-msg"), $list = $("#gst-recent-list"); $area.on("dragover dragenter", function(e){ e.preventDefault(); e.stopPropagation(); $area.addClass("dragover"); }) .on("dragleave dragend drop", function(e){ e.preventDefault(); e.stopPropagation(); $area.removeClass("dragover"); }) .on("drop", function(e){ if(e.originalEvent.dataTransfer.files[0]) uploadFile(e.originalEvent.dataTransfer.files[0]); }); $area.on("click", function(){ $input.trigger("click"); }); $input.on("change", function(){ if(this.files[0]) uploadFile(this.files[0]); }); function uploadFile(file){ var ext = file.name.split(".").pop().toLowerCase(); if (!["pdf","xls","xlsx"].includes(ext)){ $msg.html("

Only PDF, XLS, XLSX allowed.

"); return; } var data = new FormData(); data.append("action", "gst_upload_file"); data.append("gst_file", file); data.append("nonce", gst_upload.nonce); $prog.show().html("Uploading…"); $.ajax({ url: ajaxurl, type: "POST", data: data, processData: false, contentType: false, success: function(r){ $prog.hide(); if (r.success){ $msg.html("

"+r.data.message+"

"); $list.prepend(r.data.row); $(".gst-recent-uploads").show(); $input.val(""); uploadCount++; if (uploadCount >= 1) { $("#gst-countdown").removeClass("warning").addClass("submitted").text("Work Submitted!"); } } else { $msg.html("

"+r.data+"

"); } }, error: function(){ $prog.hide(); $msg.html("

Server error.

"); } }); } // Delete & Status $(document).on("click", ".gst-delete-btn", function(e){ e.preventDefault(); if (!confirm("Delete this file permanently?")) return; var $btn = $(this); var id = $btn.data("id"); var nonce = $btn.data("nonce"); $.post(ajaxurl, { action: "gst_delete_file", id: id, nonce: nonce }, function(res){ if (res.success){ $btn.closest("li").fadeOut(300, function(){ $(this).remove(); }); if ($list.children().length === 0) $(".gst-recent-uploads").hide(); } else { alert("Error: " + res.data); } }); }); $(document).on("click", ".gst-status-btn", function(e){ e.preventDefault(); var $btn = $(this); var id = $btn.data("id"); var status = $btn.data("status"); var new_status = (status === "correct") ? "wrong" : (status === "wrong" ? "pending" : "correct"); $.post(ajaxurl, { action: "gst_toggle_status", id: id, status: new_status, nonce: gst_upload.status_nonce }, function(res){ if (res.success){ var $li = $btn.closest("li"); $li.find(".gst-status-btn").removeClass("correct wrong pending") .addClass(new_status) .html(new_status === "correct" ? "Correct" : (new_status === "wrong" ? "Wrong" : "Pending")) .data("status", new_status); } }); }); // COUNTDOWN TO 9 AM TOMORROW if ($("#gst-countdown").length) { var tomorrow9am = new Date(); tomorrow9am.setHours(9, 0, 0, 0); if (tomorrow9am <= new Date()) { tomorrow9am.setDate(tomorrow9am.getDate() + 1); } var deadline = tomorrow9am.getTime(); // Check if already submitted if (uploadCount >= 1) { $("#gst-countdown").addClass("submitted").text("Work Submitted!"); } else { setInterval(function() { var now = new Date().getTime(); var distance = deadline - now; if (distance < 0) { $("#gst-countdown").removeClass("warning").text("TIME EXPIRED!").addClass("warning"); return; } var hours = Math.floor(distance / (1000 * 60 * 60)); var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); var seconds = Math.floor((distance % (1000 * 60)) / 1000); var timeLeft = ""; if (hours > 0) timeLeft += hours + "h "; if (minutes > 0 || hours > 0) timeLeft += minutes + "m "; timeLeft += seconds + "s left"; var el = $("#gst-countdown"); el.text(timeLeft); if (distance < 60 * 60 * 1000) { el.addClass("warning"); } else { el.removeClass("warning"); } }, 1000); } } }); ' ); wp_localize_script( 'gst-upload-js', 'gst_upload', [ 'nonce' => wp_create_nonce( 'gst_upload_nonce' ), 'status_nonce' => wp_create_nonce( 'gst_status_nonce' ), ] ); wp_enqueue_script( 'gst-upload-js' ); } /* ------------------------------------------------------------------ */ /* Helper: Count uploads today */ /* ------------------------------------------------------------------ */ private function get_upload_count_today() { global $wpdb; $table = $wpdb->prefix . 'gst_uploads'; $today = wp_date('Y-m-d'); return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table WHERE DATE(uploaded_on) = %s", $today ) ); } /* ------------------------------------------------------------------ */ /* AJAX upload */ /* ------------------------------------------------------------------ */ public function ajax_handle_upload() { check_ajax_referer( 'gst_upload_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Permission denied.' ); if ( empty( $_FILES['gst_file'] ) ) wp_send_json_error( 'No file.' ); $file = $_FILES['gst_file']; $allowed = [ 'pdf' => 'application/pdf', 'xls' => 'application/vnd.ms-excel', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ]; $check = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], $allowed ); if ( ! $check['ext'] || ! $check['type'] ) wp_send_json_error( 'Invalid file type.' ); add_filter( 'upload_dir', [ $this, 'custom_upload_dir' ] ); $uploaded = wp_handle_upload( $file, [ 'test_form' => false ] ); remove_filter( 'upload_dir', [ $this, 'custom_upload_dir' ] ); if ( isset( $uploaded['error'] ) ) wp_send_json_error( 'Upload failed: ' . $uploaded['error'] ); global $wpdb; $table = $wpdb->prefix . 'gst_uploads'; $now = current_time( 'mysql' ); $insert = $wpdb->insert( $table, [ 'file_name' => sanitize_file_name( $file['name'] ), 'file_url' => esc_url_raw( $uploaded['url'] ), 'uploaded_on' => $now, 'status' => 'pending', ], [ '%s', '%s', '%s', '%s' ] ); if ( ! $insert ) { @unlink( $uploaded['file'] ); wp_send_json_error( 'DB insert failed.' ); } $id = $wpdb->insert_id; $date = wp_date( 'd M Y', strtotime( $now . ' UTC' ) ); $row = '
  • ' . esc_html( $file['name'] ) . ' ' . esc_html( $date ) . ' Pending Download Delete
  • '; wp_send_json_success( [ 'message' => 'File uploaded successfully.', 'row' => $row ] ); } public function custom_upload_dir( $dirs ) { $dirs['path'] = $dirs['basedir'] . '/gst-uploads'; $dirs['url'] = $dirs['baseurl'] . '/gst-uploads'; $dirs['subdir'] = ''; return $dirs; } /* ------------------------------------------------------------------ */ /* AJAX DELETE & STATUS */ /* ------------------------------------------------------------------ */ public function ajax_handle_delete() { $id = intval( $_POST['id'] ?? 0 ); check_ajax_referer( 'gst_delete_' . $id, 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Unauthorized.' ); global $wpdb; $table = $wpdb->prefix . 'gst_uploads'; $row = $wpdb->get_row( $wpdb->prepare( "SELECT file_url FROM $table WHERE id = %d", $id ) ); if ( $row ) { $file_path = str_replace( get_site_url(), ABSPATH, $row->file_url ); if ( file_exists( $file_path ) ) @unlink( $file_path ); $wpdb->delete( $table, [ 'id' => $id ], [ '%d' ] ); } wp_send_json_success(); } public function ajax_toggle_status() { check_ajax_referer( 'gst_status_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) wp_send_json_error( 'Unauthorized.' ); $id = intval( $_POST['id'] ?? 0 ); $status = sanitize_text_field( $_POST['status'] ?? 'pending' ); if ( ! in_array( $status, ['correct', 'wrong', 'pending'] ) ) $status = 'pending'; global $wpdb; $table = $wpdb->prefix . 'gst_uploads'; $updated = $wpdb->update( $table, [ 'status' => $status ], [ 'id' => $id ], [ '%s' ], [ '%d' ] ); if ( $updated !== false ) { wp_send_json_success(); } else { wp_send_json_error( 'Failed to update status.' ); } } /* ------------------------------------------------------------------ */ /* Main Page: GSTR-3B */ /* ------------------------------------------------------------------ */ public function render_main_page() { if ( ! current_user_can( 'manage_options' ) ) wp_die( 'No permission.' ); ?>

    GSTR-3B Report

    Invoice Data – July to September 2025

    Download PDF
    get_upload_count_today(); $is_submitted = $upload_count > 0; ?>

    Work List

    Today's Assigned Work

    Date:

    Deadline: Submit by 9:00 AM tomorrow ()
    1

    Financial Data Entry

    Enter all invoices, expenses, and transactions into the system accurately.

    2

    Financial Reports

    Generate Monthly P&L and Balance Sheet for review and approval.

    Go to Upload Your Work to submit files.

    Success! Database table created. You can now upload files.
    '; } global $wpdb; $table = $wpdb->prefix . 'gst_uploads'; $uploads = $wpdb->get_results( "SELECT * FROM $table ORDER BY uploaded_on DESC" ); ?>

    Upload Your Work

    Drop PDF / Excel file here or click to select.

    Uploaded Files

      uploaded_on . ' UTC' ) ); $status = $up->status ?? 'pending'; $icon = $status === 'correct' ? 'Correct' : ($status === 'wrong' ? 'Wrong' : 'Pending'); $class = $status; ?>
    • file_name ); ?> Download Delete

    No files uploaded yet.

    WhatsApp Call