mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-23 15:09:20 +00:00
feat: Customer Ratings & Reviews Full Page
- Created macros for repetitive snippets - Created Customer Reviews full page - View more button to reveal 10 more reviews at a time - Common function to get reviews with start and end
This commit is contained in:
@@ -79,13 +79,14 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-03-24 22:27:28.094535",
|
"modified": "2021-04-02 15:56:00.447950",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "Item Review",
|
"name": "Item Review",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
@@ -93,9 +94,11 @@
|
|||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"share": 1
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
@@ -103,6 +106,17 @@
|
|||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Website Manager",
|
"role": "Website Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "Customer",
|
||||||
"share": 1
|
"share": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,14 +4,48 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from six import string_types
|
||||||
|
import json
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
from frappe.contacts.doctype.contact.contact import get_contact_name
|
from frappe.contacts.doctype.contact.contact import get_contact_name
|
||||||
|
from frappe.utils import flt, cint
|
||||||
|
from erpnext.e_commerce.doctype.e_commerce_settings.e_commerce_settings import get_shopping_cart_settings
|
||||||
|
|
||||||
class ItemReview(Document):
|
class ItemReview(Document):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_item_reviews(web_item, start, end, data=None):
|
||||||
|
if not data:
|
||||||
|
data = frappe._dict()
|
||||||
|
|
||||||
|
settings = get_shopping_cart_settings()
|
||||||
|
|
||||||
|
if settings and settings.get("enable_reviews"):
|
||||||
|
data.reviews = frappe.db.get_all("Item Review", filters={"website_item": web_item},
|
||||||
|
fields=["*"], limit_start=cint(start), limit_page_length=cint(end))
|
||||||
|
|
||||||
|
rating_data = frappe.db.get_all("Item Review", filters={"website_item": web_item},
|
||||||
|
fields=["avg(rating) as average, count(*) as total"])[0]
|
||||||
|
data.average_rating = flt(rating_data.average, 1)
|
||||||
|
data.average_whole_rating = flt(data.average_rating, 0)
|
||||||
|
|
||||||
|
# get % of reviews per rating
|
||||||
|
reviews_per_rating = []
|
||||||
|
for i in range(1,6):
|
||||||
|
count = frappe.db.get_all("Item Review", filters={"website_item": web_item, "rating": i},
|
||||||
|
fields=["count(*) as count"])[0].count
|
||||||
|
|
||||||
|
percent = flt((count / rating_data.total or 1) * 100, 0) if count else 0
|
||||||
|
reviews_per_rating.append(percent)
|
||||||
|
|
||||||
|
data.reviews_per_rating = reviews_per_rating
|
||||||
|
data.total_reviews = rating_data.total
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def add_item_review(web_item, title, rating, comment=None):
|
def add_item_review(web_item, title, rating, comment=None):
|
||||||
""" Add an Item Review by a user if non-existent. """
|
""" Add an Item Review by a user if non-existent. """
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from frappe.utils import cstr, random_string, cint, flt
|
|||||||
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
|
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
|
||||||
|
|
||||||
from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for)
|
from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for)
|
||||||
|
from erpnext.e_commerce.doctype.item_review.item_review import get_item_reviews
|
||||||
|
|
||||||
class WebsiteItem(WebsiteGenerator):
|
class WebsiteItem(WebsiteGenerator):
|
||||||
website = frappe._dict(
|
website = frappe._dict(
|
||||||
@@ -176,7 +177,7 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
self.set_metatags(context)
|
self.set_metatags(context)
|
||||||
self.set_shopping_cart_data(context)
|
self.set_shopping_cart_data(context)
|
||||||
self.get_product_details_section(context)
|
self.get_product_details_section(context)
|
||||||
self.get_reviews(context)
|
get_item_reviews(self.name, 0, 4, context)
|
||||||
|
|
||||||
context.wished = False
|
context.wished = False
|
||||||
if frappe.db.exists("Wishlist Items", {"item_code": self.item_code, "parent": frappe.session.user}):
|
if frappe.db.exists("Wishlist Items", {"item_code": self.item_code, "parent": frappe.session.user}):
|
||||||
@@ -362,28 +363,6 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
|
|
||||||
return tab_values
|
return tab_values
|
||||||
|
|
||||||
def get_reviews(self, context):
|
|
||||||
if context.shopping_cart.cart_settings.enable_reviews:
|
|
||||||
context.reviews = frappe.db.get_all("Item Review", filters={"item": self.item_code},
|
|
||||||
fields=["*"], limit=4)
|
|
||||||
|
|
||||||
rating_data = frappe.db.get_all("Item Review", filters={"item": self.item_code},
|
|
||||||
fields=["avg(rating) as average, count(*) as total"])[0]
|
|
||||||
context.average_rating = rating_data.average
|
|
||||||
context.average_whole_rating = flt(context.average_rating, 0)
|
|
||||||
|
|
||||||
# get % of reviews per rating
|
|
||||||
reviews_per_rating = []
|
|
||||||
for i in range(1,6):
|
|
||||||
count = frappe.db.get_all("Item Review", filters={"item": self.item_code, "rating": i},
|
|
||||||
fields=["count(*) as count"])[0].count
|
|
||||||
|
|
||||||
percent = flt((count / rating_data.total or 1) * 100, 0) if count else 0
|
|
||||||
reviews_per_rating.append(percent)
|
|
||||||
|
|
||||||
context.reviews_per_rating = reviews_per_rating
|
|
||||||
context.total_reviews = rating_data.total
|
|
||||||
|
|
||||||
def invalidate_cache_for_web_item(doc):
|
def invalidate_cache_for_web_item(doc):
|
||||||
"""Invalidate Website Item Group cache and rebuild ItemVariantsCacheManager."""
|
"""Invalidate Website Item Group cache and rebuild ItemVariantsCacheManager."""
|
||||||
from erpnext.stock.doctype.item.item import invalidate_item_variants_cache_for_website
|
from erpnext.stock.doctype.item.item import invalidate_item_variants_cache_for_website
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class ProductQuery:
|
|||||||
product_info = get_product_info_for_website(item.item_code, skip_quotation_creation=True).get('product_info')
|
product_info = get_product_info_for_website(item.item_code, skip_quotation_creation=True).get('product_info')
|
||||||
if product_info:
|
if product_info:
|
||||||
item.formatted_price = (product_info.get('price') or {}).get('formatted_price')
|
item.formatted_price = (product_info.get('price') or {}).get('formatted_price')
|
||||||
item.price = product_info['price'].get('price_list_rate')
|
item.price = (product_info.get('price') or {}).get('price_list_rate')
|
||||||
|
|
||||||
if self.settings.show_stock_availability:
|
if self.settings.show_stock_availability:
|
||||||
if item.get("website_warehouse"):
|
if item.get("website_warehouse"):
|
||||||
|
|||||||
@@ -705,7 +705,6 @@ body.product-page {
|
|||||||
|
|
||||||
.ratings-reviews-section {
|
.ratings-reviews-section {
|
||||||
border-top: 1px solid #E2E6E9;
|
border-top: 1px solid #E2E6E9;
|
||||||
display: flex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.reviews-header {
|
.reviews-header {
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ def get_item_for_list_in_html(context):
|
|||||||
def get_parent_item_groups(item_group_name, from_item=False):
|
def get_parent_item_groups(item_group_name, from_item=False):
|
||||||
base_nav_page = {"name": frappe._("Shop by Category"), "route":"/shop-by-category"}
|
base_nav_page = {"name": frappe._("Shop by Category"), "route":"/shop-by-category"}
|
||||||
|
|
||||||
if from_item:
|
if from_item and frappe.request.environ.get("HTTP_REFERER"):
|
||||||
# base page after 'Home' will vary on Item page
|
# base page after 'Home' will vary on Item page
|
||||||
last_page = frappe.request.environ["HTTP_REFERER"].split('/')[-1]
|
last_page = frappe.request.environ["HTTP_REFERER"].split('/')[-1]
|
||||||
if last_page and last_page in ("shop-by-category", "all-products"):
|
if last_page and last_page in ("shop-by-category", "all-products"):
|
||||||
|
|||||||
@@ -1,47 +1,16 @@
|
|||||||
{% from "erpnext/templates/includes/macros.html" import ratings_with_title %}
|
{% from "erpnext/templates/includes/macros.html" import user_review, ratings_summary %}
|
||||||
|
|
||||||
<div class="mt-8 ratings-reviews-section">
|
<div class="mt-8 ratings-reviews-section" style="display: flex;">
|
||||||
<!-- Ratings Summary -->
|
|
||||||
<div class="col-md-4 order-md-1 mt-8" style="max-width: 300px;">
|
<div class="col-md-4 order-md-1 mt-8" style="max-width: 300px;">
|
||||||
<h2 class="reviews-header">
|
{{ ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating) }}
|
||||||
{{ _("Customer Ratings") }}
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
{% if reviews %}
|
|
||||||
{% set rating_title = frappe.utils.cstr(average_rating) + " " + _("out of 5") %}
|
|
||||||
{{ ratings_with_title(average_whole_rating, rating_title, "lg", "rating-summary-title") }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Rating Progress Bars -->
|
|
||||||
<div class="rating-progress-bar-section">
|
|
||||||
{% for percent in reviews_per_rating %}
|
|
||||||
<div class="mt-4 col-sm-4 small rating-bar-title">
|
|
||||||
{{ loop.index }} star
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-7">
|
|
||||||
<div class="progress rating-progress-bar" title="{{ percent }} % of reviews are {{ loop.index }} star">
|
|
||||||
<div class="progress-bar" role="progressbar"
|
|
||||||
aria-valuenow="{{ percent }}"
|
|
||||||
aria-valuemin="0" aria-valuemax="100"
|
|
||||||
style="width: {{ percent }}%; background-color: var(--text-on-green);">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-1 small">
|
|
||||||
{{ percent }}%
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Write a Review for legitimate users -->
|
<!-- Write a Review for legitimate users -->
|
||||||
{% if frappe.session.user != "Guest" %}
|
{% if frappe.session.user != "Guest" %}
|
||||||
<button class="btn btn-light btn-write-review mr-2 mt-4 mb-4 w-100">
|
<button class="btn btn-light btn-write-review mr-2 mt-4 mb-4 w-100"
|
||||||
|
data-web-item="{{ doc.name }}">
|
||||||
{{ _("Write a Review") }}
|
{{ _("Write a Review") }}
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Reviews and Comments -->
|
<!-- Reviews and Comments -->
|
||||||
@@ -50,28 +19,14 @@
|
|||||||
{{ _("Reviews") }}
|
{{ _("Reviews") }}
|
||||||
</h2>
|
</h2>
|
||||||
{% if reviews %}
|
{% if reviews %}
|
||||||
{% for review in reviews %}
|
{{ user_review(reviews) }}
|
||||||
<!-- User review -->
|
|
||||||
<div class="mb-3 review">
|
|
||||||
{{ ratings_with_title(review.rating, _(review.review_title), "md", "user-review-title") }}
|
|
||||||
|
|
||||||
<div class="review-signature">
|
|
||||||
<span class="reviewer">{{ _(review.customer) }}</span>
|
|
||||||
<span>{{ review.published_on }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="product-description mb-4 mt-4">
|
|
||||||
<p>
|
|
||||||
{{ _(review.comment) }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% if total_reviews > 4 %}
|
{% if total_reviews > 4 %}
|
||||||
<div class="mt-6 mb-6"style="color: var(--primary);">
|
<div class="mt-6 mb-6"style="color: var(--primary);">
|
||||||
<a href="/reviews">{{ _("View all reviews") }}</a>
|
<a href="/customer_reviews?item_code={{ doc.item_code }}">{{ _("View all reviews") }}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<h6 class="text-muted mt-6">
|
<h6 class="text-muted mt-6">
|
||||||
{{ _("No Reviews") }}
|
{{ _("No Reviews") }}
|
||||||
@@ -96,7 +51,6 @@
|
|||||||
],
|
],
|
||||||
primary_action: function() {
|
primary_action: function() {
|
||||||
var data = d.get_values();
|
var data = d.get_values();
|
||||||
$btn.prop('hidden', true);
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.e_commerce.doctype.item_review.item_review.add_item_review",
|
method: "erpnext.e_commerce.doctype.item_review.item_review.add_item_review",
|
||||||
args: {
|
args: {
|
||||||
@@ -115,6 +69,7 @@
|
|||||||
indicator: "green"
|
indicator: "green"
|
||||||
});
|
});
|
||||||
d.hide();
|
d.hide();
|
||||||
|
location.reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -236,3 +236,59 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{%- endmacro -%}
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
{%- macro ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating)-%}
|
||||||
|
<!-- Ratings Summary -->
|
||||||
|
<h2 class="reviews-header">
|
||||||
|
{{ _("Customer Ratings") }}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{% if reviews %}
|
||||||
|
{% set rating_title = frappe.utils.cstr(average_rating) + " " + _("out of 5") %}
|
||||||
|
{{ ratings_with_title(average_whole_rating, rating_title, "lg", "rating-summary-title") }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Rating Progress Bars -->
|
||||||
|
<div class="rating-progress-bar-section">
|
||||||
|
{% for percent in reviews_per_rating %}
|
||||||
|
<div class="mt-4 col-sm-4 small rating-bar-title">
|
||||||
|
{{ loop.index }} star
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-7">
|
||||||
|
<div class="progress rating-progress-bar" title="{{ percent }} % of reviews are {{ loop.index }} star">
|
||||||
|
<div class="progress-bar" role="progressbar"
|
||||||
|
aria-valuenow="{{ percent }}"
|
||||||
|
aria-valuemin="0" aria-valuemax="100"
|
||||||
|
style="width: {{ percent }}%; background-color: var(--text-on-green);">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-1 small">
|
||||||
|
{{ percent }}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
{%- macro user_review(reviews)-%}
|
||||||
|
<!-- User Reviews -->
|
||||||
|
<div class="user-reviews">
|
||||||
|
{% for review in reviews %}
|
||||||
|
<div class="mb-3 review">
|
||||||
|
{{ ratings_with_title(review.rating, _(review.review_title), "md", "user-review-title") }}
|
||||||
|
|
||||||
|
<div class="review-signature">
|
||||||
|
<span class="reviewer">{{ _(review.customer) }}</span>
|
||||||
|
<span>{{ review.published_on }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="product-description mb-4 mt-4">
|
||||||
|
<p>
|
||||||
|
{{ _(review.comment) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{%- endmacro -%}
|
||||||
|
|||||||
45
erpnext/templates/pages/customer_reviews.html
Normal file
45
erpnext/templates/pages/customer_reviews.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{% extends "templates/web.html" %}
|
||||||
|
{% from "erpnext/templates/includes/macros.html" import user_review, ratings_summary %}
|
||||||
|
|
||||||
|
{% block title %} {{ _("Customer Reviews") }} {% endblock %}
|
||||||
|
|
||||||
|
{% block page_content %}
|
||||||
|
<div class="product-container col-md-12">
|
||||||
|
<div style="display: flex;">
|
||||||
|
<div class="col-md-4 order-md-1 mt-8" style="max-width: 300px;">
|
||||||
|
{{ ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating) }}
|
||||||
|
|
||||||
|
<!-- Write a Review for legitimate users -->
|
||||||
|
{% if frappe.session.user != "Guest" %}
|
||||||
|
<button class="btn btn-light btn-write-review mr-2 mt-4 mb-4 w-100"
|
||||||
|
data-web-item="{{ web_item }}">
|
||||||
|
{{ _("Write a Review") }}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Reviews and Comments -->
|
||||||
|
<div class="col-12 order-2 col-md-9 order-md-2 mt-8 ml-16">
|
||||||
|
<h2 class="reviews-header">
|
||||||
|
{{ _("Reviews") }}
|
||||||
|
</h2>
|
||||||
|
{% if reviews %}
|
||||||
|
{{ user_review(reviews) }}
|
||||||
|
|
||||||
|
{% if not reviews | len >= total_reviews %}
|
||||||
|
<button class="btn btn-light btn-view-more mr-2 mt-4 mb-4 w-30"
|
||||||
|
data-web-item="{{ web_item }}">
|
||||||
|
{{ _("View More") }}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<h6 class="text-muted mt-6">
|
||||||
|
{{ _("No Reviews") }}
|
||||||
|
</h6>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
135
erpnext/templates/pages/customer_reviews.js
Normal file
135
erpnext/templates/pages/customer_reviews.js
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
$(() => {
|
||||||
|
class CustomerReviews {
|
||||||
|
constructor() {
|
||||||
|
this.bind_button_actions();
|
||||||
|
this.start = 0;
|
||||||
|
this.page_length = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_button_actions() {
|
||||||
|
this.write_review();
|
||||||
|
this.view_more();
|
||||||
|
}
|
||||||
|
|
||||||
|
write_review() {
|
||||||
|
//TODO: make dialog popup on stray page
|
||||||
|
$('.page_content').on('click', '.btn-write-review', (e) => {
|
||||||
|
// Bind action on write a review button
|
||||||
|
const $btn = $(e.currentTarget);
|
||||||
|
|
||||||
|
let d = new frappe.ui.Dialog({
|
||||||
|
title: __("Write a Review"),
|
||||||
|
fields: [
|
||||||
|
{fieldname: "title", fieldtype: "Data", label: "Headline", reqd: 1},
|
||||||
|
{fieldname: "rating", fieldtype: "Rating", label: "Overall Rating", reqd: 1},
|
||||||
|
{fieldtype: "Section Break"},
|
||||||
|
{fieldname: "comment", fieldtype: "Small Text", label: "Your Review"}
|
||||||
|
],
|
||||||
|
primary_action: function() {
|
||||||
|
let me = this;
|
||||||
|
let data = d.get_values();
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.e_commerce.doctype.item_review.item_review.add_item_review",
|
||||||
|
args: {
|
||||||
|
web_item: $btn.attr('data-web-item'),
|
||||||
|
title: data.title,
|
||||||
|
rating: data.rating,
|
||||||
|
comment: data.comment
|
||||||
|
},
|
||||||
|
freeze: true,
|
||||||
|
freeze_message: __("Submitting Review ..."),
|
||||||
|
callback: (r) => {
|
||||||
|
if(!r.exc) {
|
||||||
|
frappe.msgprint({
|
||||||
|
message: __("Thank you for submitting your review"),
|
||||||
|
title: __("Review Submitted"),
|
||||||
|
indicator: "green"
|
||||||
|
});
|
||||||
|
d.hide();
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
primary_action_label: __('Submit')
|
||||||
|
});
|
||||||
|
d.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
view_more() {
|
||||||
|
$('.page_content').on('click', '.btn-view-more', (e) => {
|
||||||
|
// Bind action on view more button
|
||||||
|
const $btn = $(e.currentTarget);
|
||||||
|
$btn.prop('disabled', true);
|
||||||
|
|
||||||
|
this.start += this.page_length;
|
||||||
|
let me = this;
|
||||||
|
|
||||||
|
frappe.call({
|
||||||
|
method: "erpnext.e_commerce.doctype.item_review.item_review.get_item_reviews",
|
||||||
|
args: {
|
||||||
|
web_item: $btn.attr('data-web-item'),
|
||||||
|
start: me.start,
|
||||||
|
end: me.page_length
|
||||||
|
},
|
||||||
|
callback: (result) => {
|
||||||
|
if(result.message) {
|
||||||
|
let res = result.message;
|
||||||
|
me.get_user_review_html(res.reviews);
|
||||||
|
|
||||||
|
$btn.prop('disabled', false);
|
||||||
|
if (res.total_reviews <= (me.start + me.page_length)) {
|
||||||
|
$btn.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
get_user_review_html(reviews) {
|
||||||
|
let me = this;
|
||||||
|
let $content = $('.user-reviews');
|
||||||
|
|
||||||
|
reviews.forEach((review) => {
|
||||||
|
$content.append(`
|
||||||
|
<div class="mb-3 review">
|
||||||
|
<div style="display: flex;">
|
||||||
|
<div class="rating">
|
||||||
|
${me.get_review_stars(review.rating)}
|
||||||
|
</div>
|
||||||
|
<p class="ml-4 user-review-title">
|
||||||
|
<span>${__(review.review_title)}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="review-signature">
|
||||||
|
<span class="reviewer">${__(review.customer)}</span>
|
||||||
|
<span>${__(review.published_on)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="product-description mb-4 mt-4">
|
||||||
|
<p>
|
||||||
|
${__(review.comment)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get_review_stars(rating) {
|
||||||
|
let stars = ``;
|
||||||
|
for(let i = 1; i < 6; i++) {
|
||||||
|
let fill_class = i <= rating ? 'star-click' : '';
|
||||||
|
stars += `<svg class="icon icon-md ${fill_class}">
|
||||||
|
<use href="#icon-star"></use>
|
||||||
|
</svg>`;
|
||||||
|
}
|
||||||
|
return stars;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new CustomerReviews();
|
||||||
|
});
|
||||||
16
erpnext/templates/pages/customer_reviews.py
Normal file
16
erpnext/templates/pages/customer_reviews.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
no_cache = 1
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from erpnext.e_commerce.doctype.item_review.item_review import get_item_reviews
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
context.full_page = True
|
||||||
|
context.reviews = None
|
||||||
|
if frappe.form_dict and frappe.form_dict.get("item_code"):
|
||||||
|
context.item_code = frappe.form_dict.get("item_code")
|
||||||
|
context.web_item = frappe.db.get_value("Website Item", {"item_code": context.item_code}, "name")
|
||||||
|
get_item_reviews(context.web_item, 0, 10, context)
|
||||||
Reference in New Issue
Block a user