Mohidul Islam 3 лет назад
Родитель
Сommit
8b2897040e

+ 137 - 0
manager/analytics.py

@@ -0,0 +1,137 @@
+from django.utils import timezone
+from django.db import connection
+
+from gauth.models import Location
+
+
+def get_weeks(_year, _week):
+    if _week > 9:
+        return [[w, _year] for w in range(_week, _week-10, -1)]
+    else:
+        this_year = [[w, _year] for w in range(_week, -1, -1)]
+        this_year.extend([[_year-1, w] for w in range(52, 52-(10-len(this_year)), -1)])
+        return this_year
+
+
+def weekly_positive_review_count():
+    sql = f'''
+            select 
+                week(create_time) as week,
+                year(create_time) as year,
+                location_id,
+                count(*) as rev_count
+            from review_review
+            where 
+                create_time >= (curdate() - interval 10 week) and
+                star_rating > 3
+            group by week(create_time), location_id
+            ORDER BY week DESC;
+           '''
+    now = timezone.now()
+    location_dict = dict(Location.objects.values_list('location_id', 'care_name'))
+    with connection.cursor() as cursor:
+        cursor.execute(sql)
+        rows = cursor.fetchall()
+        row_dict = {(row[0], row[1], row[2]): row[3] for row in rows}
+        # Get all week names for graph label
+        res = list()
+        for w in get_weeks(now.year, now.isocalendar()[1]):
+            weeks_res = []
+            for loc in location_dict.keys():
+                weeks_res.append(row_dict.get(tuple(w+[loc]), 0))
+            # res[w[0]] = weeks_res
+            res.append(weeks_res)
+        return res, location_dict.values()
+
+
+def weekly_negative_review_count():
+    sql = f'''
+            select 
+                week(create_time) as week,
+                year(create_time) as year,
+                location_id,
+                count(*) as rev_count
+            from review_review
+            where 
+                create_time >= (curdate() - interval 10 week) and
+                star_rating <= 3
+            group by week(create_time), location_id
+            ORDER BY week DESC;
+           '''
+    now = timezone.now()
+    location_dict = dict(Location.objects.values_list('location_id', 'care_name'))
+    with connection.cursor() as cursor:
+        cursor.execute(sql)
+        rows = cursor.fetchall()
+        row_dict = {(row[0], row[1], row[2]): row[3] for row in rows}
+        # Get all week names for graph label
+        res = list()
+        for w in get_weeks(now.year, now.isocalendar()[1]):
+            weeks_res = []
+            for loc in location_dict.keys():
+                weeks_res.append(row_dict.get(tuple(w+[loc]), 0))
+            # res[w[0]] = weeks_res
+            res.append(weeks_res)
+        return res
+
+
+def weekly_facebook_positive_review_count():
+    sql = f'''
+            select 
+                week(create_time) as week,
+                year(create_time) as year,
+                page_id,
+                count(*) as rev_count
+            from facebook_app_facebookreview
+            where 
+                create_time >= (curdate() - interval 10 week) and
+                recommendation_type = true
+            group by week(create_time), page_id
+            ORDER BY week DESC;
+           '''
+    now = timezone.now()
+    location_dict = dict(Location.objects.values_list('location_id', 'care_name'))
+    with connection.cursor() as cursor:
+        cursor.execute(sql)
+        rows = cursor.fetchall()
+        row_dict = {(row[0], row[1], row[2]): row[3] for row in rows}
+        # Get all week names for graph label
+        res = list()
+        for w in get_weeks(now.year, now.isocalendar()[1]):
+            weeks_res = []
+            for loc in location_dict.keys():
+                weeks_res.append(row_dict.get(tuple(w+[loc]), 0))
+            # res[w[0]] = weeks_res
+            res.append(weeks_res)
+        return res, location_dict.values()
+
+
+def weekly_negative_review_count():
+    sql = f'''
+            select 
+                week(create_time) as week,
+                year(create_time) as year,
+                location_id,
+                count(*) as rev_count
+            from review_review
+            where 
+                create_time >= (curdate() - interval 10 week) and
+                star_rating <= 3
+            group by week(create_time), location_id
+            ORDER BY week DESC;
+           '''
+    now = timezone.now()
+    location_dict = dict(Location.objects.values_list('location_id', 'care_name'))
+    with connection.cursor() as cursor:
+        cursor.execute(sql)
+        rows = cursor.fetchall()
+        row_dict = {(row[0], row[1], row[2]): row[3] for row in rows}
+        # Get all week names for graph label
+        res = list()
+        for w in get_weeks(now.year, now.isocalendar()[1]):
+            weeks_res = []
+            for loc in location_dict.keys():
+                weeks_res.append(row_dict.get(tuple(w+[loc]), 0))
+            # res[w[0]] = weeks_res
+            res.append(weeks_res)
+        return res

+ 261 - 0
manager/templates/_positive_review_graph.html

@@ -0,0 +1,261 @@
+<div class="container-fluid">
+  <canvas id="myPosChart" width="960" height="320"></canvas>
+  <canvas id="myNegChart" width="960" height="120"></canvas>
+</div>
+
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js" integrity="sha256-TQq84xX6vkwR0Qs1qH5ADkP+MvH0W+9E7TdHJsoIQiM=" crossorigin="anonymous"></script>
+
+<script>
+  var ctx = document.getElementById("myPosChart");
+  var neg_ctx = document.getElementById("myNegChart");
+  var endpoint = 'http://127.0.0.1:8000/managers/graphs/review-analysis';
+  $.ajax({
+        type: "get",
+        url: endpoint,
+        dataType: 'json',
+        success: function(data) {
+          var myBarChart = new Chart(ctx, {
+          type: 'bar',
+          data: {
+              labels: data.labels,
+              datasets: [
+                  {
+                    label: data.weeks[0],
+                    data: data.pos_data[0],
+                    borderColor: 'rgb(24, 106, 59)',
+                    backgroundColor: 'rgb(24, 106, 59)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[1],
+                    data: data.pos_data[1],
+                    borderColor: 'rgb(25, 111, 61)',
+                    backgroundColor: 'rgb(25, 111, 61)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[2],
+                    data: data.pos_data[2],
+                    borderColor: 'rgb(30, 132, 73)',
+                    backgroundColor: 'rgb(30, 132, 73)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[3],
+                    data: data.pos_data[3],
+                    borderColor: 'rgb(34, 153, 84)',
+                    backgroundColor: 'rgb(34, 153, 84)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[4],
+                    data: data.pos_data[4],
+                    borderColor: 'rgb(39, 174, 96)',
+                    backgroundColor: 'rgb(39, 174, 96)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[5],
+                    data: data.pos_data[5],
+                    borderColor: 'rgb(125, 206, 160)',
+                    backgroundColor: 'rgb(125, 206, 160)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[6],
+                    data: data.pos_data[6],
+                    borderColor: 'rgb(130, 224, 170)',
+                    backgroundColor: 'rgb(130, 224, 170)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[7],
+                    data: data.pos_data[7],
+                    borderColor: 'rgb(171, 235, 198)',
+                    backgroundColor: 'rgb(171, 235, 198)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[8],
+                    data: data.pos_data[8],
+                    borderColor: 'rgb(130, 224, 170)',
+                    backgroundColor: 'rgb(130, 224, 170)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[9],
+                    data: data.pos_data[9],
+                    borderColor: 'rgb(171, 235, 198)',
+                    backgroundColor: 'rgb(171, 235, 198)',
+                    borderWidth: 1,
+                    fill: false
+                }]
+            },
+            options: {
+                scales: {
+                    yAxes: [{
+                        display: true,
+                        scaleLabel: {
+                          display: true,
+                          fontSize: 16,
+                          fontStyle: 'italic',
+                          labelString: 'Total review count'
+                        },
+                        ticks: {
+                            beginAtZero: true,
+                            stepSize: 1
+                        }
+                    }],
+                    xAxes: [{
+                        display: true,
+                            scaleLabel: {
+                              display: true,
+                              fontSize: 16,
+                              fontStyle: 'italic',
+                              labelString: 'Location'
+                            },
+                          ticks: {
+                          autoSkip: false
+                        },
+                        gridLines: {
+                            drawOnChartArea:false
+                        }
+                    }]
+                },
+                title: {
+                    display: true,
+                    fontSize: 16,
+                    text: "Review of this month in all platforms."
+                }
+            }
+        });
+
+    var myNegBarChart = new Chart(neg_ctx, {
+          type: 'bar',
+          data: {
+              labels: data.labels,
+              datasets: [
+                  {
+                    label: data.weeks[0],
+                    data: data.neg_data[0],
+                    borderColor: 'rgb(117, 3, 0)',
+                    backgroundColor: 'rgb(117, 3, 0)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[1],
+                    data: data.neg_data[1],
+                    borderColor: 'rgb(164, 8, 4)',
+                    backgroundColor: 'rgb(164, 8, 4)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[2],
+                    data: data.neg_data[2],
+                    borderColor: 'rgb(178, 5, 0)',
+                    backgroundColor: 'rgb(178, 5, 0)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[3],
+                    data: data.neg_data[3],
+                    borderColor: 'rgb(220, 6, 0)',
+                    backgroundColor: 'rgb(220, 6, 0)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[4],
+                    data: data.neg_data[4],
+                    borderColor: 'rgb(216, 59, 54)',
+                    backgroundColor: 'rgb(216, 59, 54)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[5],
+                    data: data.neg_data[5],
+                    borderColor: 'rgb(241, 8, 1)',
+                    backgroundColor: 'rgb(241, 8, 1)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[6],
+                    data: data.neg_data[6],
+                    borderColor: 'rgb(233, 61, 56)',
+                    backgroundColor: 'rgb(233, 61, 56)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[7],
+                    data: data.neg_data[7],
+                    borderColor: 'rgb(232, 83, 78)',
+                    backgroundColor: 'rgb(232, 83, 78)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[8],
+                    data: data.neg_data[8],
+                    borderColor: 'rgb(235, 119, 116)',
+                    backgroundColor: 'rgb(235, 119, 116)',
+                    borderWidth: 1,
+                    fill: false
+                },
+                {
+                    label: data.weeks[9],
+                    data: data.neg_data[9],
+                    borderColor: 'rgb(255, 157, 154)',
+                    backgroundColor: 'rgb(255, 157, 154)',
+                    borderWidth: 1,
+                    fill: false
+                }]
+            },
+            options: {
+                scales: {
+                    yAxes: [{
+                        display: true,
+                        scaleLabel: {
+                          display: true,
+                          fontSize: 16,
+                          fontStyle: 'italic',
+                          labelString: 'Total review count'
+                        },
+                        ticks: {
+                            beginAtZero: true,
+                            stepSize: 1
+                        }
+                    }],
+                    xAxes: [{
+                        display: true,
+                          ticks: {
+                          autoSkip: false
+                        },
+                        gridLines: {
+                            drawOnChartArea:false
+                        }
+                    }]
+                },
+            }
+        });
+    },
+    error: function(error_data) {
+       console.log(error_data);
+    }
+  });
+</script>

+ 68 - 0
manager/templates/review-analysis.html

@@ -0,0 +1,68 @@
+{% load static %}
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta name="description" content="">
+    <meta name="author" content="">
+    <title>SignatureCare Review Portal</title>
+    <link rel="canonical" href="https://getbootstrap.com/docs/4.0/examples/dashboard/">
+    <!-- Bootstrap core CSS -->
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
+    <!-- Custom styles for this template -->
+    <link rel="stylesheet" type="text/css" href="{% static 'user-dashboard.css' %}">
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+    <style>
+      a:link {
+        text-decoration: none;
+        color: #050608;
+      }
+
+      a:visited {
+        text-decoration: none;
+        color: #013568;
+      }
+
+      a:hover {
+        text-decoration: none;
+        color: #51585e;
+
+      }
+
+      a:active {
+        text-decoration: none;
+        color: #272727;
+
+      }
+    </style>
+  </head>
+  <body>
+    <nav class="navbar navbar-dark bg-dark">
+      <div class="container">
+        <ul class="navbar-nav px-3">
+        <li class="nav-item text-nowrap">
+          <a class="nav-link" href="{% url 'location-list' %}" style="color: white; font-size:20px">SignatureCare Review Portal</a>
+        </li>
+        </ul>
+        <ul class="navbar-nav px-3">
+          <li class="nav-item text-nowrap">
+            <a class="nav-link" href="{% url 'logout' %}">Sign out</a>
+          </li>
+        </ul>
+      </div>
+    </nav>
+    {% if messages %}
+      {% for message in messages %}
+        <div class="alert alert-{{ message.tags }} container">
+          {{ message }}
+        </div>
+      {% endfor %}
+    {% endif %}
+    {% include '_positive_review_graph.html' %}
+  </div>
+  </body>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
+  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js" integrity="sha256-TQq84xX6vkwR0Qs1qH5ADkP+MvH0W+9E7TdHJsoIQiM=" crossorigin="anonymous"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>

+ 4 - 1
manager/urls.py

@@ -1,7 +1,7 @@
 from django.urls import path
 
 from .views import LocationListView
-
+from django.views.generic import TemplateView
 from .views import (
     LocationAnalytics,
     ReviewListLocationWise,
@@ -10,6 +10,7 @@ from .views import (
     SyncStaffLeaderBoard,
     StaffDelete,
     AllLocationSummary,
+    ReviewAnalysis,
 )
 
 urlpatterns = [
@@ -18,7 +19,9 @@ urlpatterns = [
     path('reviews/<platform>/<str:location_id>', ReviewListLocationWise.as_view(), name='location-wise-review-list-man'),
     path('graph/<str:location_id>', ReviewAnalyticsGraph.as_view(), name='location-analytics-graph-man'),
     path('graphs/all_location', AllLocationSummary.as_view(), name='all-location-graph-man'),
+    path('graphs/review-analysis', ReviewAnalysis.as_view(), name='review-summary-all'),
     path('staff/<str:location_id>', StaffLeaderBoard.as_view(), name='staff-leaderboard-man'),
     path('staff/delete/<staff_id>', StaffDelete.as_view(), name='staff-delete-man'),
     path('sync-staff-list/<str:location_id>', SyncStaffLeaderBoard.as_view(), name='sync-staff-list-man'),
+    path('review-analysis/', TemplateView.as_view(template_name="review-analysis.html")),
 ]

+ 18 - 1
manager/views.py

@@ -1,3 +1,5 @@
+import datetime
+
 import openpyxl
 from rest_framework import status
 from rest_framework.views import APIView
@@ -14,7 +16,7 @@ from facebook_app.models import FacebookReview
 from name_extractor.models import Staff
 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 from django.shortcuts import get_object_or_404
-
+from .analytics import weekly_positive_review_count, get_weeks, weekly_negative_review_count
 from name_extractor.utils import extract_names_from_reviews, make_all_staffs_point_zero
 
 from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
@@ -275,3 +277,18 @@ class AllLocationSummary(APIView):
             'review_counts': review_counts,
         }
         return Response(response)
+
+
+class ReviewAnalysis(APIView):
+    def get(self, request, *args, **kwargs):
+        now = datetime.datetime.now()
+        pos_ratings, labels = weekly_positive_review_count()
+        neg_ratings = weekly_negative_review_count()
+        weeks = get_weeks(now.year, now.isocalendar()[1])
+        response = {
+            "weeks": weeks,
+            "pos_data": pos_ratings,
+            "neg_data": neg_ratings,
+            "labels": labels
+        }
+        return Response(response)