304 lines
14 KiB
PHP
304 lines
14 KiB
PHP
@extends('layouts.vertical', ['page_title' => 'Datatables'])
|
|
|
|
@section('css')
|
|
<!-- third party css -->
|
|
<link href="{{ asset('assets/libs/datatables/datatables.min.css') }}" rel="stylesheet" type="text/css" />
|
|
<link href="{{ asset('assets/libs/flatpickr/flatpickr.min.css') }}" rel="stylesheet" type="text/css" />
|
|
<script src="https://cdn.jsdelivr.net/npm/ag-grid-community@30.0.0/dist/ag-grid-community.min.js"></script>
|
|
<!-- third party css end -->
|
|
<meta name="csrf-token" content="{{ csrf_token() }}" />
|
|
<style type="text/css">
|
|
.ag-theme-alpine {
|
|
--ag-header-column-separator-display: block;
|
|
--ag-header-column-separator-height: 20%;
|
|
--ag-header-column-separator-width: 1px;
|
|
--ag-header-column-separator-color: rgb(0, 0, 0);
|
|
}
|
|
#myGrid {
|
|
height: calc(100vh - 200px);
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<!-- Start Content-->
|
|
<div class="container-fluid">
|
|
<!-- start page title -->
|
|
<div class="row">
|
|
<div class="col-md-6 p-2">
|
|
<h4 class="page-title">Form Wise RCPA Report</h4>
|
|
</div>
|
|
</div>
|
|
<!-- end page title -->
|
|
@if (session()->has('message'))
|
|
<div class="alert alert-success">
|
|
{{ session()->get('message') }}
|
|
</div>
|
|
@endif
|
|
@if (session()->has('error'))
|
|
<div class="alert alert-danger">
|
|
{{ session()->get('error') }}
|
|
</div>
|
|
@endif
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="row justify-content-between">
|
|
<div class="col-auto filter-section">
|
|
<form id="rcpaFilterForm" class="d-flex flex-wrap align-items-center gap-2" onsubmit="return false;">
|
|
<label for="form-select" class="me-2">Form:</label>
|
|
<div class="me-sm-3">
|
|
<select class="form-select my-1 my-lg-0" id="form-select" name="form_id">
|
|
<option value="">All Forms</option>
|
|
@if(isset($forms))
|
|
@foreach($forms as $f)
|
|
<option value="{{ $f->id }}">
|
|
{{ $f->title ?? $f->id }}
|
|
</option>
|
|
@endforeach
|
|
@endif
|
|
</select>
|
|
</div>
|
|
<label for="date-from" class="me-2">From:</label>
|
|
<input type="text" class="form-control datetime me-2" id="date-from" name="date_from" placeholder="YYYY-MM-DD" style="width:130px;">
|
|
<label for="date-to" class="me-2">To:</label>
|
|
<input type="text" class="form-control datetime me-2" id="date-to" name="date_to" placeholder="YYYY-MM-DD" style="width:130px;">
|
|
<button id="btn-fetch" class="btn btn-sm btn-info me-2" type="button" onclick="fetchRCPAReport()" style="font-weight:bold;">
|
|
Fetch
|
|
</button>
|
|
</form>
|
|
</div>
|
|
<div class="col-auto">
|
|
<div class="text-lg-end my-1 my-lg-0">
|
|
<div>
|
|
<button id="btn-export" class="btn btn-sm btn-primary"
|
|
style="margin-bottom: 5px; font-weight: bold">
|
|
Export to Excel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div><!-- end col-->
|
|
</div>
|
|
</div>
|
|
</div> <!-- end card -->
|
|
</div> <!-- end col-->
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div id="myGrid" style="" class="ag-theme-alpine"></div>
|
|
</div> <!-- end card body-->
|
|
</div> <!-- end card -->
|
|
</div><!-- end col-->
|
|
</div>
|
|
<!-- end row-->
|
|
</div> <!-- container -->
|
|
|
|
@endsection
|
|
|
|
@section('script')
|
|
<!-- third party js -->
|
|
<script src="{{ asset('assets/libs/flatpickr/flatpickr.min.js') }}"></script>
|
|
<script src="{{ asset('assets/libs/bootstrap-datepicker/bootstrap-datepicker.min.js') }}"></script>
|
|
|
|
<script type="text/javascript">
|
|
$('.datetime').flatpickr({
|
|
dateFormat: "Y-m-d"
|
|
});
|
|
|
|
function rowSpan(params) {
|
|
return 20;
|
|
}
|
|
|
|
// Initial static columns
|
|
const initialColumnDefs = [
|
|
{ headerName: 'User Name', field: 'user_name', width: 150, pinned: 'left', filter: 'agTextColumnFilter', floatingFilter: true },
|
|
{ headerName: 'Employee Code', field: 'employee_code', width: 120, filter: 'agTextColumnFilter', floatingFilter: true },
|
|
{ headerName: 'Submition Date', field: 'record_date', width: 120, filter: 'agTextColumnFilter', floatingFilter: true },
|
|
{ headerName: 'Doctor Name', field: 'contact_id', width: 120, filter: 'agTextColumnFilter', floatingFilter: true },
|
|
{ headerName: 'MSL Code', field: 'msl_code', width: 120, filter: 'agTextColumnFilter', floatingFilter: true },
|
|
{ headerName: 'Speciality', field: 'speciality', width: 150, filter: 'agTextColumnFilter', floatingFilter: true },
|
|
{ headerName: 'Chemist Name', field: 'chemist_name', width: 150, filter: 'agTextColumnFilter', floatingFilter: true },
|
|
{ headerName: 'Chemist Type', field: 'type_of_chemist', width: 150, filter: 'agTextColumnFilter', floatingFilter: true },
|
|
{ headerName: 'Doctors Attached to Chemist', field: 'doctors_attached_to_chemist', width: 180, filter: 'agTextColumnFilter', floatingFilter: true },
|
|
|
|
];
|
|
|
|
let rowData = []
|
|
|
|
$('#btn-export').on('click', function() {
|
|
gridOptions.api.exportDataAsCsv();
|
|
});
|
|
|
|
const gridOptions = {
|
|
columnDefs: initialColumnDefs,
|
|
pagination: true,
|
|
paginationPageSize: 50,
|
|
defaultColDef: {
|
|
resizable: true,
|
|
sortable: true,
|
|
},
|
|
rowData: rowData,
|
|
domLayout: 'normal',
|
|
};
|
|
|
|
const gridDiv = document.querySelector('#myGrid');
|
|
new agGrid.Grid(gridDiv, gridOptions);
|
|
|
|
// Function to fetch RCPA report data
|
|
function fetchRCPAReport() {
|
|
let formId = $('#form-select').val();
|
|
let dateFrom = $('#date-from').val();
|
|
let dateTo = $('#date-to').val();
|
|
|
|
// Build query params
|
|
let params = {};
|
|
if (formId) params.form_id = formId;
|
|
if (dateFrom) params.date_from = dateFrom;
|
|
if (dateTo) params.date_to = dateTo;
|
|
|
|
// Show loader
|
|
$("#pageloader").fadeIn();
|
|
|
|
// Make AJAX call
|
|
$.ajax({
|
|
type: "GET",
|
|
url: '/rcpareport/ajaxformwise',
|
|
data: params,
|
|
success: function(data) {
|
|
let final_data = [];
|
|
let brandMap = {}; // { brandName: { competitors: Set<compName> } }
|
|
|
|
if(data.response && Array.isArray(data.response)) {
|
|
data.response.forEach(row => {
|
|
// 1. Pre-process row to map brands and find unique structure
|
|
let bMap = {};
|
|
if (row.brands && Array.isArray(row.brands)) {
|
|
row.brands.forEach(b => {
|
|
let bName = b.brand_name;
|
|
if (!bName) return;
|
|
|
|
// Build the brand map for grid columns
|
|
if (!brandMap[bName]) {
|
|
brandMap[bName] = { competitors: new Set() };
|
|
}
|
|
if (b.competitors && Array.isArray(b.competitors)) {
|
|
b.competitors.forEach(comp => {
|
|
if (comp && comp.competitor_name) {
|
|
brandMap[bName].competitors.add(comp.competitor_name);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Build each row's per-brand map for Cipla and competitor data
|
|
if (!bMap[bName]) {
|
|
bMap[bName] = {
|
|
qty_cipla: b.cipla_qty,
|
|
val_cipla: b.cipla_value,
|
|
competitors: {}
|
|
};
|
|
}
|
|
|
|
// Add competitor data
|
|
if (b.competitors && Array.isArray(b.competitors)) {
|
|
b.competitors.forEach(comp => {
|
|
if (comp && comp.competitor_name) {
|
|
bMap[bName].competitors[comp.competitor_name] = {
|
|
qty: comp.competitors_qty,
|
|
val: comp.competitors_value
|
|
};
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
row.brands_map = bMap;
|
|
final_data.push(row);
|
|
});
|
|
}
|
|
|
|
// 2. Build Dynamic Column Definitions
|
|
let dynamicDefs = [];
|
|
Object.keys(brandMap).sort().forEach(brandName => {
|
|
let competitors = Array.from(brandMap[brandName].competitors).sort();
|
|
|
|
let brandChildren = [
|
|
{
|
|
headerName: 'Cipla Qty',
|
|
width: 100,
|
|
type: 'numericColumn',
|
|
valueGetter: function(params) {
|
|
return params.data.brands_map && params.data.brands_map[brandName] ? params.data.brands_map[brandName].qty_cipla : null;
|
|
}
|
|
},
|
|
{
|
|
headerName: 'Cipla Value',
|
|
width: 100,
|
|
type: 'numericColumn',
|
|
valueGetter: function(params) {
|
|
return params.data.brands_map && params.data.brands_map[brandName] ? params.data.brands_map[brandName].val_cipla : null;
|
|
}
|
|
}
|
|
];
|
|
|
|
competitors.forEach(compName => {
|
|
brandChildren.push({
|
|
headerName: compName,
|
|
children: [
|
|
{
|
|
headerName: 'Qty',
|
|
width: 100,
|
|
type: 'numericColumn',
|
|
valueGetter: function(params) {
|
|
try {
|
|
return params.data.brands_map[brandName].competitors[compName].qty;
|
|
} catch(e) { return null; }
|
|
}
|
|
},
|
|
{
|
|
headerName: 'Value',
|
|
width: 100,
|
|
type: 'numericColumn',
|
|
valueGetter: function(params) {
|
|
try {
|
|
return params.data.brands_map[brandName].competitors[compName].val;
|
|
} catch(e) { return null; }
|
|
}
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
dynamicDefs.push({
|
|
headerName: brandName,
|
|
children: brandChildren
|
|
});
|
|
});
|
|
|
|
// 3. Update Grid
|
|
let newColumnDefs = initialColumnDefs.concat(dynamicDefs);
|
|
gridOptions.api.setColumnDefs(newColumnDefs);
|
|
gridOptions.api.setRowData(final_data);
|
|
|
|
$("#pageloader").fadeOut();
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('Error loading form wise data:', error);
|
|
alert('Error loading data. Please try again.');
|
|
$("#pageloader").fadeOut();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialize grid with empty data on page load
|
|
jQuery(document).ready(function($){
|
|
gridOptions.api.setRowData([]);
|
|
})
|
|
|
|
|
|
</script>
|
|
@endsection
|