-
Notifications
You must be signed in to change notification settings - Fork 1
Bill Generation
Bill generation is a process that lives in the backend of our web app that generates bills for subscribers. It runs on a node server hosted on Heroku. It is made up of three main steps: Bill Creation, PDF Generation, and Approval.
Endpoint: https://peoplepower-node.herokuapp.com/generate
Body Parameters: [solarProjectId]
The bill creation step is initiated by a super admin from the super admin dashboard. The super admin will see a button for each solar project that exists, clicking the button will send a request with the ID of the solar project to the backend, which will start generating bills for all subscribers under that solar project.
After that the following happens in order for each subscriber within the solar project:
Every Subscriber user has a Utility API Meter ID associated with their account. The server uses this and pulls the latest PG&E bill from the Utility API.
Endpoint Docs: https://utilityapi.com/docs/api/bills/list
URL Format: https://utilityapi.com/api/v2/bills?meters=${meterId}&limit=1&order=latest_first
;
It then uses this bill to calculate the following values:
- Start and End Date
- Net PGE Usage
- EBCE Rebate
- PG&E Charges
- EBCE Charges
- Would Be Costs
Possible Error Cases:
- The server compares the start and end date against the previous bill for this subscriber. If they line up, the process aborts smoothly and sends the admin an email
- If the structure of the bills returned by Utility API changes, this process will fail
Next, the server queries the Enphase API for the production data produced by the solar system over the time frame of the subscriber's bill.
Endpoint Docs: https://developer.enphase.com/docs#api-systems
URL Format: https://api.enphaseenergy.com/api/v2/systems/${systemId}/energy_lifetime?${queryParameters}
Query Parameters for the URL include: Enphase API Key, Enphase User ID, Production Type (all), Start Date, and End Date
The information it gets back is for the entire project group. It then uses a special resolver function to convert the object it receives from the API to an array of KwH data points for just the current subscriber. These resolver functions are hardcoded into the server and need to be updated whenever there is a new subscriber.
Once the server knows day-to-day production values for the subscriber, it saves them into two variables: a string with the day-to-day values separated by commas (used for generating the chart on page 1 of the bill), and an integer summing up the total for the month (used for calculating charges).
Possible Error Cases:
- If there isn't a resolver for a subscriber, the server will abort bill generation and send the admin an email
- If the date range is empty or does not have enough data, the server will also abort bill generation
Finally, the server downloads the subscriber's rate schedule and computes three key values for the bill:
Estimated Rebate: -1 * Net PGE Usage * Rebate Rate
Current Charges: Total System Production * People Power Rate
Amount Due: Current Charges + Previous Bill Balance - Estimated Rebate
All values are rounded to 2 decimal points.
Then it creates the bill on airtable and kicks off the PDF Generation process
Endpoint: https://peoplepower-node.herokuapp.com/regenerate
Query Parameters: [subscriberId]
PDF Generation happens completely separate from Bill Generation. This is so that it is easy for the admin to regenerate a bill PDF after making changes to the bill in Airtable. It can be initiated by visiting the URL above and passing in a subscriber ID, but it also happens immediately after the bill creation process.
The PDF Generation process only receives a subscriber ID. From this subscriber ID, it downloads all associated data from Airtable: the subscriber record, the solar project record, and all subscriber bills (including the latest).
Possible Error Cases:
- If the subscriber does not have any bills, this process will fail
After downloading the data, the server generates charts. It does this using a library called HighCharts, specifically their HighCharts Export Server package. There are two charts on the Bill PDF: one on the front for the production data for that month and one on the back showing the subscriber's costs over time. The charts are generated and saved as images in the temp/
folder under the names: ${bill.id}_chart1.png
and ${bill.id}_chart2.png
Production Chart
The Production Chart uses three variables from the latest bill on Airtable: Start Date
, End Date
, and Chart Generation Data
. It expects the Chart Generation Data to be a list of comma-separated values representing the kilowatt hours generated on the days between the start and end date.
The chart is made by enumerating the dates between start date and end date, turning them into strings, and using them as labels for the X-Axis of the chart. The Y-Values are the values from Chart Generation Data
Effective Cost Chart
This chart shows how much the Subscriber has paid for their energy vs how much they would have paid if using PG&E. It uses data from all previous subscriber bills.
True costs are calculated using the formula: EBCE Charges + PG&E Charges + Current Charges - EBCE Rebate - Estimated Rebate
Would be costs are calculated during the bill creation process using the formula: PCIA Cost + EBCE Generation Cost + PGE Delivery Charges
Possible Error Cases:
- If there is a mismatch between the number of days in the date range and the number of values in
Chart Generation Data
, the chart generation process will fail for the first chart. This won't happen naturally, but can happen if you change the data and regenerate the bill
The Server then finally renders the PDF using a library called React-PDF to generate the PDF using a predefined template. All values are rounded to 2 decimal points except the people power rate for energy, which takes up to 5 decimal points if available.
The bill PDF is saved in the temp/
folder under the name: ${bill.id}-${unix timestamp}.pdf
The timestamp is included so that if the PDF is regenerated, Airtable considers the files unique when uploaded.
Possible Error Cases:
- If the Would-Be Costs are greater than the true costs, the PDF will show negative savings. Admins should take care to make sure this is expected when it happens
The server then updates the latest subscriber bill with the generated PDF. It does so by giving it a public link to the PDF hosted on the server. 20 seconds after generation finishes, the PDF and both chart images are deleted. This delay is to give Airtable the time to download the file from the server onto its own. The bill is always marked pending after a PDF is regenerated.
After a bill is created, an email will be sent to the admin email with the details of the bill, the PDF, and links to either approve the bill or regenerate.
To approve the bill, the admin simply clicks the link in the email which sends a request to the server to approve the PDF. Alternatively, the admin can approve manually using Airtable.
If the admin notices a discrepancy in the data, they can manually change the values on airtable and click the Regenerate link. This will send a request to the server to regenerate a new PDF for the latest bill. Regeneration will send a new email with a new PDF.
Approval URL Format: https://peoplepower-node.herokuapp.com/approve?id=${latestBill.id}
Regeneration URL Format: https://peoplepower-node.herokuapp.com/regenerate?subscriberId=${subscriber.id}
Any errors on the server will prompt an email being sent to the admin. If the error is accounted for (such as an existing PG&E bill), the admin will receive an email with specific instructions on what to do (if anything) to remedy the situation. If it is an unexpected error, the email will detail the error so that a developer can look into it.