mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	chore: Add an option to download CSAT Reports (#4694)
This commit is contained in:
		@@ -5,7 +5,7 @@ class Api::V1::Accounts::CsatSurveyResponsesController < Api::V1::Accounts::Base
 | 
				
			|||||||
  RESULTS_PER_PAGE = 25
 | 
					  RESULTS_PER_PAGE = 25
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  before_action :check_authorization
 | 
					  before_action :check_authorization
 | 
				
			||||||
  before_action :set_csat_survey_responses, only: [:index, :metrics]
 | 
					  before_action :set_csat_survey_responses, only: [:index, :metrics, :download]
 | 
				
			||||||
  before_action :set_current_page, only: [:index]
 | 
					  before_action :set_current_page, only: [:index]
 | 
				
			||||||
  before_action :set_current_page_surveys, only: [:index]
 | 
					  before_action :set_current_page_surveys, only: [:index]
 | 
				
			||||||
  before_action :set_total_sent_messages_count, only: [:metrics]
 | 
					  before_action :set_total_sent_messages_count, only: [:metrics]
 | 
				
			||||||
@@ -19,6 +19,12 @@ class Api::V1::Accounts::CsatSurveyResponsesController < Api::V1::Accounts::Base
 | 
				
			|||||||
    @ratings_count = @csat_survey_responses.group(:rating).count
 | 
					    @ratings_count = @csat_survey_responses.group(:rating).count
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def download
 | 
				
			||||||
 | 
					    response.headers['Content-Type'] = 'text/csv'
 | 
				
			||||||
 | 
					    response.headers['Content-Disposition'] = 'attachment; filename=csat_report.csv'
 | 
				
			||||||
 | 
					    render layout: false, template: 'api/v1/accounts/csat_survey_responses/download.csv.erb', format: 'csv'
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def set_total_sent_messages_count
 | 
					  def set_total_sent_messages_count
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,17 @@ class CSATReportsAPI extends ApiClient {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  download({ from, to, user_ids } = {}) {
 | 
				
			||||||
 | 
					    return axios.get(`${this.url}/download`, {
 | 
				
			||||||
 | 
					      params: {
 | 
				
			||||||
 | 
					        since: from,
 | 
				
			||||||
 | 
					        until: to,
 | 
				
			||||||
 | 
					        sort: '-created_at',
 | 
				
			||||||
 | 
					        user_ids,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getMetrics({ from, to, user_ids } = {}) {
 | 
					  getMetrics({ from, to, user_ids } = {}) {
 | 
				
			||||||
    return axios.get(`${this.url}/metrics`, {
 | 
					    return axios.get(`${this.url}/metrics`, {
 | 
				
			||||||
      params: { since: from, until: to, user_ids },
 | 
					      params: { since: from, until: to, user_ids },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,5 +33,23 @@ describe('#Reports API', () => {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    it('#download', () => {
 | 
				
			||||||
 | 
					      csatReportsAPI.download({
 | 
				
			||||||
 | 
					        from: 1622485800,
 | 
				
			||||||
 | 
					        to: 1623695400,
 | 
				
			||||||
 | 
					        user_ids: 1,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      expect(context.axiosMock.get).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					        '/api/v1/csat_survey_responses/download',
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          params: {
 | 
				
			||||||
 | 
					            since: 1622485800,
 | 
				
			||||||
 | 
					            until: 1623695400,
 | 
				
			||||||
 | 
					            user_ids: 1,
 | 
				
			||||||
 | 
					            sort: '-created_at',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,12 @@
 | 
				
			|||||||
 | 
					import fromUnixTime from 'date-fns/fromUnixTime';
 | 
				
			||||||
 | 
					import format from 'date-fns/format';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const downloadCsvFile = (fileName, fileContent) => {
 | 
					export const downloadCsvFile = (fileName, fileContent) => {
 | 
				
			||||||
  const link = document.createElement('a');
 | 
					  const link = document.createElement('a');
 | 
				
			||||||
  link.download = fileName;
 | 
					  link.download = fileName;
 | 
				
			||||||
  link.href = `data:text/csv;charset=utf-8,` + encodeURI(fileContent);
 | 
					  link.href = `data:text/csv;charset=utf-8,` + encodeURI(fileContent);
 | 
				
			||||||
  link.click();
 | 
					  link.click();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const generateFileName = ({ type, to }) =>
 | 
				
			||||||
 | 
					  `${type}-report-${format(fromUnixTime(to), 'dd-MM-yyyy')}.csv`;
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import { downloadCsvFile } from '../downloadCsvFile';
 | 
					import { downloadCsvFile, generateFileName } from '../downloadHelper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const fileName = 'test.csv';
 | 
					const fileName = 'test.csv';
 | 
				
			||||||
const fileData = `Agent name,Conversations count,Avg first response time (Minutes),Avg resolution time (Minutes)
 | 
					const fileData = `Agent name,Conversations count,Avg first response time (Minutes),Avg resolution time (Minutes)
 | 
				
			||||||
@@ -19,3 +19,11 @@ describe('#downloadCsvFile', () => {
 | 
				
			|||||||
    expect(link.click).toHaveBeenCalledTimes(1);
 | 
					    expect(link.click).toHaveBeenCalledTimes(1);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('#generateFileName', () => {
 | 
				
			||||||
 | 
					  it('should generate the correct file name', () => {
 | 
				
			||||||
 | 
					    expect(generateFileName({ type: 'csat', to: 1652812199 })).toEqual(
 | 
				
			||||||
 | 
					      'csat-report-17-05-2022.csv'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -354,6 +354,7 @@
 | 
				
			|||||||
  "CSAT_REPORTS": {
 | 
					  "CSAT_REPORTS": {
 | 
				
			||||||
    "HEADER": "CSAT Reports",
 | 
					    "HEADER": "CSAT Reports",
 | 
				
			||||||
    "NO_RECORDS": "There are no CSAT survey responses available.",
 | 
					    "NO_RECORDS": "There are no CSAT survey responses available.",
 | 
				
			||||||
 | 
					    "DOWNLOAD": "Download CSAT Reports",
 | 
				
			||||||
    "FILTERS": {
 | 
					    "FILTERS": {
 | 
				
			||||||
      "AGENTS": {
 | 
					      "AGENTS": {
 | 
				
			||||||
        "PLACEHOLDER": "Choose Agents"
 | 
					        "PLACEHOLDER": "Choose Agents"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,18 @@
 | 
				
			|||||||
    <report-filter-selector
 | 
					    <report-filter-selector
 | 
				
			||||||
      agents-filter
 | 
					      agents-filter
 | 
				
			||||||
      :agents-filter-items-list="agentList"
 | 
					      :agents-filter-items-list="agentList"
 | 
				
			||||||
 | 
					      :show-business-hours-switch="false"
 | 
				
			||||||
      @date-range-change="onDateRangeChange"
 | 
					      @date-range-change="onDateRangeChange"
 | 
				
			||||||
      @agents-filter-change="onAgentsFilterChange"
 | 
					      @agents-filter-change="onAgentsFilterChange"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
 | 
					    <woot-button
 | 
				
			||||||
 | 
					      color-scheme="success"
 | 
				
			||||||
 | 
					      class-names="button--fixed-right-top"
 | 
				
			||||||
 | 
					      icon="arrow-download"
 | 
				
			||||||
 | 
					      @click="downloadReports"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {{ $t('CSAT_REPORTS.DOWNLOAD') }}
 | 
				
			||||||
 | 
					    </woot-button>
 | 
				
			||||||
    <csat-metrics />
 | 
					    <csat-metrics />
 | 
				
			||||||
    <csat-table :page-index="pageIndex" @page-change="onPageNumberChange" />
 | 
					    <csat-table :page-index="pageIndex" @page-change="onPageNumberChange" />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
@@ -15,6 +24,7 @@ import CsatMetrics from './components/CsatMetrics';
 | 
				
			|||||||
import CsatTable from './components/CsatTable';
 | 
					import CsatTable from './components/CsatTable';
 | 
				
			||||||
import ReportFilterSelector from './components/FilterSelector';
 | 
					import ReportFilterSelector from './components/FilterSelector';
 | 
				
			||||||
import { mapGetters } from 'vuex';
 | 
					import { mapGetters } from 'vuex';
 | 
				
			||||||
 | 
					import { generateFileName } from '../../../../helper/downloadHelper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  name: 'CsatResponses',
 | 
					  name: 'CsatResponses',
 | 
				
			||||||
@@ -24,7 +34,7 @@ export default {
 | 
				
			|||||||
    ReportFilterSelector,
 | 
					    ReportFilterSelector,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
    return { pageIndex: 1, from: 0, to: 0, user_ids: [] };
 | 
					    return { pageIndex: 1, from: 0, to: 0, userIds: [] };
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
    ...mapGetters({
 | 
					    ...mapGetters({
 | 
				
			||||||
@@ -39,7 +49,7 @@ export default {
 | 
				
			|||||||
      this.$store.dispatch('csat/getMetrics', {
 | 
					      this.$store.dispatch('csat/getMetrics', {
 | 
				
			||||||
        from: this.from,
 | 
					        from: this.from,
 | 
				
			||||||
        to: this.to,
 | 
					        to: this.to,
 | 
				
			||||||
        user_ids: this.user_ids,
 | 
					        user_ids: this.userIds,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      this.getResponses();
 | 
					      this.getResponses();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@@ -48,7 +58,7 @@ export default {
 | 
				
			|||||||
        page: this.pageIndex,
 | 
					        page: this.pageIndex,
 | 
				
			||||||
        from: this.from,
 | 
					        from: this.from,
 | 
				
			||||||
        to: this.to,
 | 
					        to: this.to,
 | 
				
			||||||
        user_ids: this.user_ids,
 | 
					        user_ids: this.userIds,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    onPageNumberChange(pageIndex) {
 | 
					    onPageNumberChange(pageIndex) {
 | 
				
			||||||
@@ -61,9 +71,18 @@ export default {
 | 
				
			|||||||
      this.getAllData();
 | 
					      this.getAllData();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    onAgentsFilterChange(agents) {
 | 
					    onAgentsFilterChange(agents) {
 | 
				
			||||||
      this.user_ids = agents.map(el => el.id);
 | 
					      this.userIds = agents.map(el => el.id);
 | 
				
			||||||
      this.getAllData();
 | 
					      this.getAllData();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    downloadReports() {
 | 
				
			||||||
 | 
					      const type = 'csat';
 | 
				
			||||||
 | 
					      this.$store.dispatch('csat/downloadCSATReports', {
 | 
				
			||||||
 | 
					        from: this.from,
 | 
				
			||||||
 | 
					        to: this.to,
 | 
				
			||||||
 | 
					        user_ids: this.userIds,
 | 
				
			||||||
 | 
					        fileName: generateFileName({ type, to: this.to }),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,7 +61,10 @@
 | 
				
			|||||||
        @input="handleAgentsFilterSelection"
 | 
					        @input="handleAgentsFilterSelection"
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="small-12 medium-3 business-hours">
 | 
					    <div
 | 
				
			||||||
 | 
					      v-if="showBusinessHoursSwitch"
 | 
				
			||||||
 | 
					      class="small-12 medium-3 business-hours"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
      <span class="business-hours-text margin-right-small">
 | 
					      <span class="business-hours-text margin-right-small">
 | 
				
			||||||
        {{ $t('REPORT.BUSINESS_HOURS') }}
 | 
					        {{ $t('REPORT.BUSINESS_HOURS') }}
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
@@ -105,6 +108,10 @@ export default {
 | 
				
			|||||||
      type: Boolean,
 | 
					      type: Boolean,
 | 
				
			||||||
      default: false,
 | 
					      default: false,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    showBusinessHoursSwitch: {
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,6 +61,7 @@ import format from 'date-fns/format';
 | 
				
			|||||||
import { GROUP_BY_FILTER, METRIC_CHART } from '../constants';
 | 
					import { GROUP_BY_FILTER, METRIC_CHART } from '../constants';
 | 
				
			||||||
import reportMixin from '../../../../../mixins/reportMixin';
 | 
					import reportMixin from '../../../../../mixins/reportMixin';
 | 
				
			||||||
import { formatTime } from '@chatwoot/utils';
 | 
					import { formatTime } from '@chatwoot/utils';
 | 
				
			||||||
 | 
					import { generateFileName } from '../../../../../helper/downloadHelper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const REPORTS_KEYS = {
 | 
					const REPORTS_KEYS = {
 | 
				
			||||||
  CONVERSATIONS: 'conversations_count',
 | 
					  CONVERSATIONS: 'conversations_count',
 | 
				
			||||||
@@ -250,26 +251,17 @@ export default {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    downloadReports() {
 | 
					    downloadReports() {
 | 
				
			||||||
      const { from, to } = this;
 | 
					      const { from, to, type } = this;
 | 
				
			||||||
      const fileName = `${this.type}-report-${format(
 | 
					      const dispatchMethods = {
 | 
				
			||||||
        fromUnixTime(to),
 | 
					        agent: 'downloadAgentReports',
 | 
				
			||||||
        'dd-MM-yyyy'
 | 
					        label: 'downloadLabelReports',
 | 
				
			||||||
      )}.csv`;
 | 
					        inbox: 'downloadInboxReports',
 | 
				
			||||||
      switch (this.type) {
 | 
					        team: 'downloadTeamReports',
 | 
				
			||||||
        case 'agent':
 | 
					      };
 | 
				
			||||||
          this.$store.dispatch('downloadAgentReports', { from, to, fileName });
 | 
					      if (dispatchMethods[type]) {
 | 
				
			||||||
          break;
 | 
					        const fileName = generateFileName({ type, to });
 | 
				
			||||||
        case 'label':
 | 
					        const params = { from, to, fileName };
 | 
				
			||||||
          this.$store.dispatch('downloadLabelReports', { from, to, fileName });
 | 
					        this.$store.dispatch(dispatchMethods[type], params);
 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        case 'inbox':
 | 
					 | 
				
			||||||
          this.$store.dispatch('downloadInboxReports', { from, to, fileName });
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        case 'team':
 | 
					 | 
				
			||||||
          this.$store.dispatch('downloadTeamReports', { from, to, fileName });
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        default:
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    changeSelection(index) {
 | 
					    changeSelection(index) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
 | 
					import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
 | 
				
			||||||
import types from '../mutation-types';
 | 
					import types from '../mutation-types';
 | 
				
			||||||
import CSATReports from '../../api/csatReports';
 | 
					import CSATReports from '../../api/csatReports';
 | 
				
			||||||
 | 
					import { downloadCsvFile } from '../../helper/downloadHelper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const computeDistribution = (value, total) =>
 | 
					const computeDistribution = (value, total) =>
 | 
				
			||||||
  ((value * 100) / total).toFixed(2);
 | 
					  ((value * 100) / total).toFixed(2);
 | 
				
			||||||
@@ -107,6 +108,11 @@ export const actions = {
 | 
				
			|||||||
      commit(types.SET_CSAT_RESPONSE_UI_FLAG, { isFetchingMetrics: false });
 | 
					      commit(types.SET_CSAT_RESPONSE_UI_FLAG, { isFetchingMetrics: false });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  downloadCSATReports(_, params) {
 | 
				
			||||||
 | 
					    return CSATReports.download(params).then(response => {
 | 
				
			||||||
 | 
					      downloadCsvFile(params.fileName, response.data);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const mutations = {
 | 
					export const mutations = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ import * as types from '../mutation-types';
 | 
				
			|||||||
import Report from '../../api/reports';
 | 
					import Report from '../../api/reports';
 | 
				
			||||||
import Vue from 'vue';
 | 
					import Vue from 'vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { downloadCsvFile } from '../../helper/downloadCsvFile';
 | 
					import { downloadCsvFile } from '../../helper/downloadHelper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state = {
 | 
					const state = {
 | 
				
			||||||
  fetchingStatus: false,
 | 
					  fetchingStatus: false,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,8 @@ class CsatSurveyResponsePolicy < ApplicationPolicy
 | 
				
			|||||||
  def metrics?
 | 
					  def metrics?
 | 
				
			||||||
    @account_user.administrator?
 | 
					    @account_user.administrator?
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def download?
 | 
				
			||||||
 | 
					    @account_user.administrator?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					<%=
 | 
				
			||||||
 | 
					  CSV.generate_line([
 | 
				
			||||||
 | 
					    I18n.t('reports.csat.headers.agent_name'),
 | 
				
			||||||
 | 
					    I18n.t('reports.csat.headers.rating'),
 | 
				
			||||||
 | 
					    I18n.t('reports.csat.headers.feedback'),
 | 
				
			||||||
 | 
					    I18n.t('reports.csat.headers.contact_name'),
 | 
				
			||||||
 | 
					    I18n.t('reports.csat.headers.contact_email_address'),
 | 
				
			||||||
 | 
					    I18n.t('reports.csat.headers.contact_phone_number'),
 | 
				
			||||||
 | 
					    I18n.t('reports.csat.headers.link_to_the_conversation'),
 | 
				
			||||||
 | 
					    I18n.t('reports.csat.headers.recorded_at')
 | 
				
			||||||
 | 
					  ])
 | 
				
			||||||
 | 
					-%>
 | 
				
			||||||
 | 
					<% @csat_survey_responses.each do |csat_response| %>
 | 
				
			||||||
 | 
					<% assigned_agent = csat_response.assigned_agent %>
 | 
				
			||||||
 | 
					<% contact = csat_response.contact %>
 | 
				
			||||||
 | 
					<% conversation = csat_response.conversation %>
 | 
				
			||||||
 | 
					<%=
 | 
				
			||||||
 | 
					  CSV.generate_line([
 | 
				
			||||||
 | 
					    assigned_agent ? "#{assigned_agent.name} (#{assigned_agent.email})" : nil,
 | 
				
			||||||
 | 
					    csat_response.rating,
 | 
				
			||||||
 | 
					    csat_response.feedback_message.present? ? csat_response.feedback_message : nil,
 | 
				
			||||||
 | 
					    contact&.name.present? ? contact&.name: nil,
 | 
				
			||||||
 | 
					    contact&.email.present? ? contact&.email: nil,
 | 
				
			||||||
 | 
					    contact&.phone_number.present? ? contact&.phone_number: nil,
 | 
				
			||||||
 | 
					    conversation ? app_account_conversation_url(account_id: Current.account.id, id: conversation.display_id): nil,
 | 
				
			||||||
 | 
					    csat_response.created_at,
 | 
				
			||||||
 | 
					  ])
 | 
				
			||||||
 | 
					-%>
 | 
				
			||||||
 | 
					<% end %>
 | 
				
			||||||
 | 
					<%=
 | 
				
			||||||
 | 
					  CSV.generate_line([
 | 
				
			||||||
 | 
					    I18n.t(
 | 
				
			||||||
 | 
					      'reports.period',
 | 
				
			||||||
 | 
					      since: Date.strptime(params[:since], '%s'),
 | 
				
			||||||
 | 
					      until: Date.strptime(params[:until], '%s')
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  ])
 | 
				
			||||||
 | 
					-%>
 | 
				
			||||||
@@ -60,6 +60,16 @@ en:
 | 
				
			|||||||
      avg_first_response_time: Avg first response time (Minutes)
 | 
					      avg_first_response_time: Avg first response time (Minutes)
 | 
				
			||||||
      avg_resolution_time: Avg resolution time (Minutes)
 | 
					      avg_resolution_time: Avg resolution time (Minutes)
 | 
				
			||||||
    default_group_by: day
 | 
					    default_group_by: day
 | 
				
			||||||
 | 
					    csat:
 | 
				
			||||||
 | 
					      headers:
 | 
				
			||||||
 | 
					        contact_name: Contact Name
 | 
				
			||||||
 | 
					        contact_email_address: Contact Email Address
 | 
				
			||||||
 | 
					        contact_phone_number: Contact Phone Number
 | 
				
			||||||
 | 
					        link_to_the_conversation: Link to the conversation
 | 
				
			||||||
 | 
					        agent_name: Agent Name
 | 
				
			||||||
 | 
					        rating: Rating
 | 
				
			||||||
 | 
					        feedback: Feedback Comment
 | 
				
			||||||
 | 
					        recorded_at: Recorded date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  notifications:
 | 
					  notifications:
 | 
				
			||||||
    notification_title:
 | 
					    notification_title:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,6 +106,7 @@ Rails.application.routes.draw do
 | 
				
			|||||||
          resources :csat_survey_responses, only: [:index] do
 | 
					          resources :csat_survey_responses, only: [:index] do
 | 
				
			||||||
            collection do
 | 
					            collection do
 | 
				
			||||||
              get :metrics
 | 
					              get :metrics
 | 
				
			||||||
 | 
					              get :download
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
          end
 | 
					          end
 | 
				
			||||||
          resources :custom_attribute_definitions, only: [:index, :show, :create, :update, :destroy]
 | 
					          resources :custom_attribute_definitions, only: [:index, :show, :create, :update, :destroy]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -148,4 +148,38 @@ RSpec.describe 'CSAT Survey Responses API', type: :request do
 | 
				
			|||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe 'GET /api/v1/accounts/{account.id}/csat_survey_responses/download' do
 | 
				
			||||||
 | 
					    context 'when it is an unauthenticated user' do
 | 
				
			||||||
 | 
					      it 'returns unauthorized' do
 | 
				
			||||||
 | 
					        get "/api/v1/accounts/#{account.id}/csat_survey_responses/download"
 | 
				
			||||||
 | 
					        expect(response).to have_http_status(:unauthorized)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'when it is an authenticated user' do
 | 
				
			||||||
 | 
					      let(:params) { { since: 5.days.ago.to_time.to_i.to_s, until: Time.zone.tomorrow.to_time.to_i.to_s } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns unauthorized for agents' do
 | 
				
			||||||
 | 
					        get "/api/v1/accounts/#{account.id}/csat_survey_responses/download",
 | 
				
			||||||
 | 
					            params: params,
 | 
				
			||||||
 | 
					            headers: agent.create_new_auth_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(response).to have_http_status(:unauthorized)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'returns summary' do
 | 
				
			||||||
 | 
					        get "/api/v1/accounts/#{account.id}/csat_survey_responses/download",
 | 
				
			||||||
 | 
					            params: params,
 | 
				
			||||||
 | 
					            headers: administrator.create_new_auth_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(response).to have_http_status(:success)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        content = CSV.parse(response.body)
 | 
				
			||||||
 | 
					        # Check rating from CSAT Row
 | 
				
			||||||
 | 
					        expect(content[1][1]).to eq '1'
 | 
				
			||||||
 | 
					        expect(content.length).to eq 3
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user