Skip to content

Commit

Permalink
Feat: Download Dataset Spreadsheet #150 (#176)
Browse files Browse the repository at this point in the history
* Adding endpoint and logic for downloading formatted data spreadhseet for uploader

* Removing missed console.log
  • Loading branch information
JulianForeman authored Feb 27, 2024
1 parent e5067fe commit 4eab603
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 0 deletions.
196 changes: 196 additions & 0 deletions django/api/services/datasheet_template_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import pandas as pd
from io import BytesIO

DATASET_COLUMNS = {
'ARC Project Tracking': [
"Funding Call", "Proponent", "Ref #", "Project Title", "Primary Location",
"Status", "ARC Funding", "Funds Issued", "Start Date", "Completion Date",
"Total Project Value", "ZEV Sub-Sector", "On-Road/Off-Road", "Fuel Type",
"Publicly Announced",
],
# Charger Rebates
'EV Charging Rebates': [
"Organization", "MLA", "Region", "City",
"Address", "Number of Fast Charging Stations", "In service date",
"Expected in service date", "Announced?",
"B.C. (EMPR) Funding Anticipated (Max $25,000 per station, excludes MOTI stations) (Not all funding paid out yet as depends on station completion)",
"Notes",
],
'Data Fleets': [
"Current Stage", "Rebate Value", "Legal Name of your Organization/Fleet: ",
"Your business Category", "City:*", "Postal Code:*", "Applicant First Name",
"Applicant Last Name", "Email Address:*", "Fleet Size All",
"Fleet Size Light-duty", "Total number of EVs?", "Total number of light-duty EVs?",
"PHEV's", "EVSE's?", "Average daily travel distance?", "Which component are you applying for?*",
"Estimated cost", "Which type of charger are you installing?",
"How many Level 2 Charging Stations are you applying for",
"How many Level 3/DC Fast Charging Stations are you applying for",
'"Application Form Fleets" completion date/time',
"Pre-Approval Date", "Deadline", "Application Number", "Potential Rebate"
],
# Hydrogen Fleets
'Hydrogen Fleets': [
"Application #",
"Fleet #",
"Application Date",
"Organization Name",
"Fleet Name",
"Street Address",
"City",
"Postal Code",
"VIN",
"Make",
"Model",
"Year",
"Purchase Date",
"Dealer Name",
"Rebate Amount"
],
# Hydrogen Fueling
'Hydrogen Fueling': [
"Station Number",
"RFP Close Date",
"Station Name",
"Street Address",
"City",
"Postal Code",
"Proponent",
"Location Partner (Shell/7-11/etc.)",
"Capital Funding Awarded",
"O&M Funding Potential",
"Daily Capacity (kg/day)",
"700 Bar",
"350 Bar",
"Status",
"# of Fuelling Positions",
"Operational Date",
"Opening Date",
"Total Capital Cost",
],
# LDV Rebates
'LDV Rebates': [
"CASL Consent",
"DATE APPROVED",
"Submission ID",
"Submission Date",
"Company Name",
"City",
"Applicant Name",
"Applicant Address 1",
"Applicant Address 2",
"Applicant City",
"Applicant Postal Code",
"Applicant Phone",
"Applicant Email",
"Applicant Use",
"Applicant Type",
"Business Name",
"Business Number",
"Drivers License",
"Province",
"MSRP",
"Other Incentives",
"Document Type",
"Vehicle",
"Incentive Amount",
"VIN#",
"Delivered",
"Consent to Contact"
],
# Public Charging
'Public Charging': [
"Applicant Name",
"Address",
"Charging Station Info",
">25kW; <50kW",
">50kW; <100kW",
">100kW",
"Level 2 (# of units/stations)",
"Level 2 (# of ports)",
"Estimated Budget",
"Adjusted Rebate",
"Rebate % Maximum",
"Pilot Project (Y/N)",
"Region",
"Organization Type",
"Project Status",
"Review Number",
"Paid out rebate amount"
],
# Scrap It
'Scrap It': [
"Approval Num",
"App Recv'd Date",
"Completion Date",
"Postal Code",
"VIN",
"App City Fuel",
"Incentive Type",
"Incentive Cost",
"Cheque #",
"Budget Code",
"Scrap Date"
],
# Specialty Use Vehicle Incetives
'Specialty Use Vehicle Incentive Program': [
"Approvals",
"Date",
"Applicant Name",
"Max Incentive Amount Requested",
"Category",
"Fleet",
"Individual",
"Incentive Paid",
"Total Purchase Price (pre-tax)",
"Manufacturer",
"Model",
],


}

def generate_template(dataset_name):
"""
Generates an Excel spreadsheet template for a specified dataset.
"""
if dataset_name not in DATASET_COLUMNS:
raise ValueError(f"Dataset '{dataset_name}' is not supported.")

columns = DATASET_COLUMNS[dataset_name]
df = pd.DataFrame(columns=columns)

excel_buffer = BytesIO()
with pd.ExcelWriter(excel_buffer, engine='xlsxwriter') as writer:
sheet_name = dataset_name
start_row = 0
if dataset_name == 'ARC Project Tracking':
sheet_name = 'Project_Tracking'

if dataset_name == 'Specialty Use Vehicle Incentive Program':
sheet_name= 'Sheet1'

if dataset_name == 'Public Charging':
sheet_name= 'Project_applications'
start_row = 2

if dataset_name == 'LDV Rebates':
sheet_name='Raw Data'

if dataset_name == 'EV Charging Rebates':
sheet_name = 'Updated'
start_row = 2

if dataset_name == 'Hydrogen Fueling':
sheet_name = 'Station_Tracking'

if dataset_name == 'Hydrogen Fleets':
sheet_name = 'Fleets'

if dataset_name == 'Scrap It':
sheet_name = 'TOP OTHER TRANSACTIONS'
start_row = 5

df.to_excel(writer, sheet_name=sheet_name, startrow=start_row, index=False)

excel_buffer.seek(0)
return excel_buffer
20 changes: 20 additions & 0 deletions django/api/viewsets/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from django.http import HttpResponse
from django.core.exceptions import ValidationError
from django.utils.decorators import method_decorator
from api.decorators.permission import check_upload_permission
Expand Down Expand Up @@ -38,6 +39,7 @@
import_public_charging
from api.services.speciality_use_vehicle_incentives import \
import_from_xls as import_suvi
from api.services.datasheet_template_generator import generate_template

class UploadViewset(GenericViewSet):
permission_classes = (AllowAny,)
Expand Down Expand Up @@ -138,3 +140,21 @@ def import_data(self, request):
return Response('There was an issue!', status=status.HTTP_400_BAD_REQUEST)
else:
return Response(records_inserted_msg, status=status.HTTP_201_CREATED)


@action(detail=False, methods=['get'])
def download_dataset(self, request):
dataset_name = request.GET.get('datasetSelected')
if not dataset_name:
return HttpResponse("Dataset name is required.", status=400)

try:
excel_file = generate_template(dataset_name)
response = HttpResponse(
excel_file.read(),
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
response['Content-Disposition'] = f'attachment; filename="{dataset_name}.xlsx"'
return response
except ValueError as e:
return HttpResponse(str(e), status=400)
22 changes: 22 additions & 0 deletions react/src/uploads/UploadContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,27 @@ const UploadContainer = () => {
showError(error);
});
});
const downloadSpreadsheet = () => {
axios.get(ROUTES_UPLOAD.DOWNLOAD_SPREADSHEET, {
params: {
datasetSelected: datasetSelected
},
responseType: 'blob'
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');

link.href = url;
link.setAttribute('download', `${datasetSelected}.xlsx`);
document.body.appendChild(link);
link.click();

link.parentNode.removeChild(link);
window.URL.revokeObjectURL(url);
}).catch((error) => {
showError(error);
});
};

useEffect(() => {
refreshList(true);
Expand Down Expand Up @@ -114,6 +135,7 @@ const UploadContainer = () => {
setReplaceData={setReplaceData}
replaceData={replaceData}
handleRadioChange={handleRadioChange}
downloadSpreadsheet={downloadSpreadsheet}
/>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions react/src/uploads/components/UploadPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const UploadPage = (props) => {
uploadFiles,
replaceData,
handleRadioChange,
downloadSpreadsheet,
} = props;
const selectionList = datasetList.map((obj, index) => (
<MenuItem key={index} value={obj.name}>
Expand All @@ -41,6 +42,7 @@ const UploadPage = (props) => {
>
{selectionList}
</Select>
<Button onClick={downloadSpreadsheet}>Download Spreadsheet</Button>

</div>
<div id="replace-data-select">
Expand Down
1 change: 1 addition & 0 deletions react/src/uploads/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const UPLOAD = {
MINIO_URL: '/api/minio/put',
UPLOAD: `${API_BASE_PATH}/import_data`,
LIST: `${API_BASE_PATH}/datasets_list`, // backend route for retrieving list of datasets (eg ldv_rebates)
DOWNLOAD_SPREADSHEET: `${API_BASE_PATH}/download_dataset`
};

export default UPLOAD;

0 comments on commit 4eab603

Please sign in to comment.