# New Reporting Flow This is a technical content, if you want to learn how to use the reporting feature, please read: [Understanding your Analytics dashboard and reports](https://support.simplepractice.com/hc/en-us/articles/7796201723789-Understanding-your-Analytics-dashboard-and-reports) We are changing the pattern of creating reports at Simple Practice. This document's goal is to provide the technical implementation details of the new reporting flow. These are some examples of reports which already follow the new pattern: - Client Attendance Report - Client Demographics Report - Client Details Report - Clinician Documents Report - Outstanding Balances Report Feel free to use one of them as example, when implementing a new report. ## What exactly happens, when we click on a report? The following diagram, describes a high level step by step explanation of the application's behavior, when we run a report which follows the new pattern. ![Reporting diagram](https://i.imgur.com/QOo2cVZ.png) ## Summary line Some reports contain a summary line at the top of the results, which is responsible for showing the totals values, these values come from the query, and the frontend receives as metadata from the api request. ![Report summary line example](https://i.imgur.com/mY5gOmj.png) ### Let's check how they work behind the scenes First of all, the query should return the summary line. We use rollup queries for it (e.g. [ClientAttendanceReportQuery](https://github.com/simplepractice/simplepractice/blob/staging/app/queries/reports/client_attendance_report_query.rb)). Once our query class is already able to provide the totals, we should have a totals method in the report class (e.g. [ClientAttendanceReport](https://github.com/simplepractice/simplepractice/blob/staging/app/reports/client_attendance_report.rb)): ```ruby= def totals # it should return a hash with string keys {"appointments"=>"99 appointments"} #e.g. # the string "99 appointments comes from the query" end ``` When the `totals` method is defined, the report rows controller sends its return as metadata to the frontend, which displays the summary line. ## Pagination The `BaseReportQuery` is already prepared to receive `page`, and `per_page` attributes, which should be sent by the report class, as well as other specific parameters for the report, when instantiating the query class. e.g. from `ClientAttendanceReport` ```ruby= def report_query @report_query ||= Reports::ClientAttendanceReportQuery.new({ practice_id: practice.id, starts_at: starts_at, ends_at: ends_at(scoped_to_current_time: true), primary_clinician_id: filter_clinician_id, client_id: filter_client_id, office_id: filter_office_id, appointment_status: filter_appointment_status, per_page: per_page, page: page, sort: sort }).call end ``` The pagination attributes should be handled by the query to make the pagination works. e.g. [Pagination query lines](https://github.com/simplepractice/simplepractice/blob/411f9c4c445ff5a0409a34982e194a17a92e63f0/app/queries/reports/client_attendance_report_query.rb#L136). > *Attention > Some reports don't have the summary line. Which ends up requiring different approaches when it comes to pagination. > For example: If the user wants to see 10 lines, we should show 11, because the first one is not a real record, but the summary line* ## Sorting The sorting feature works similar to the pagination. The query class also receives the attribute from the report class(`sort` attribute in this case). But the sorting feature, is already abtracted through the `sort_by` method ```ruby= def report_query @report_query ||= Reports::ClientAttendanceReportQuery.new({ practice_id: practice.id, starts_at: starts_at, ends_at: ends_at(scoped_to_current_time: true), primary_clinician_id: filter_clinician_id, client_id: filter_client_id, office_id: filter_office_id, appointment_status: filter_appointment_status, per_page: per_page, page: page, sort: sort }).call end ``` ## Reporting classes(Lower level) Pattern classes to follow when creating a new report, and explanations about their responsibilities. ### Report query class The Report query class is responsible for running the query in the database. It inherits from BaseReportQuery class, which already has some abstractions for filtering and the call method(responsible for effectively connect to the database and run the query). So we just need to create the `sql` method, which should contain the SQL query we need to run for the report, and some variable sql methods if needed. #### Patterns: - It should live in `app/queries/reports` path. - It should live in the Reports module. - It should inherit from [BaseReportQuery](https://github.com/simplepractice/simplepractice/blob/staging/app/queries/reports/base_report_query.rb) lass. - It should implement the private `sql` method. - It should be named as your report name followed by the `ReportQuery` sufix. Example file: [Reports::ClientAttendanceReportQuery](https://github.com/simplepractice/simplepractice/blob/staging/app/queries/reports/client_attendance_report_query.rb). ### Report class The Report class is responsible for calling the report query, and besides that, it also handles filtering logics, defines the columns which should be present on the report lines and defines the summay line through the total method, which is not present in all reports. #### Patterns - It should live in `app/reports` path. - It shoud inherit from [ReportBase](https://github.com/simplepractice/simplepractice/blob/staging/app/reports/report_base.rb) class. - It should be named as your report name followed by the `Report` sufix. Example file: [ClientAttendanceReport](https://github.com/simplepractice/simplepractice/blob/staging/app/reports/client_attendance_report.rb). ### Report policy class The Report policy class is responsible for handling the report permissions. #### Patterns - It should live in `app/policies/reports` - It should inherit from [Reports::BaseReportPolicy](https://github.com/simplepractice/simplepractice/blob/staging/app/policies/reports/base_report_policy.rb). - It should live in `Reports` module. - It should be named as your report name followed by the `ReportPolicy` sufix. Example file: [ClientAttendanceReportPolicy](https://github.com/simplepractice/simplepractice/blob/staging/app/policies/reports/client_attendance_report_policy.rb).