feat: Card Actions and Wishlist

- Rough UI for card actions
- Wishlist doctype
- Indicators on card based on stock availability
This commit is contained in:
marination 2021-03-11 10:56:00 +05:30
parent d7130e31fe
commit 16b9c8c383
12 changed files with 315 additions and 16 deletions

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestWishlist(unittest.TestCase):
pass

View File

@ -0,0 +1,8 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Wishlist', {
// refresh: function(frm) {
// }
});

View File

@ -0,0 +1,70 @@
{
"actions": [],
"autoname": "field:user",
"creation": "2021-03-10 18:52:28.769126",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"user",
"section_break_2",
"items"
],
"fields": [
{
"fieldname": "user",
"fieldtype": "Link",
"in_list_view": 1,
"label": "User",
"options": "User",
"reqd": 1,
"unique": 1
},
{
"fieldname": "section_break_2",
"fieldtype": "Section Break"
},
{
"fieldname": "items",
"fieldtype": "Table",
"label": "Items",
"options": "Wishlist Items"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-03-10 19:05:52.373601",
"modified_by": "Administrator",
"module": "E-commerce",
"name": "Wishlist",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Stock Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class Wishlist(Document):
pass

View File

@ -0,0 +1,104 @@
{
"actions": [],
"creation": "2021-03-10 19:03:00.662714",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"item_code",
"website_item",
"column_break_3",
"item_name",
"item_details_section",
"description",
"column_break_7",
"image",
"image_view",
"warehouse_section",
"warehouse"
],
"fields": [
{
"fieldname": "item_code",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Item Code",
"options": "Item",
"reqd": 1
},
{
"fieldname": "website_item",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Website Item",
"options": "Website Item"
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fetch_from": "item_code.item_name",
"fetch_if_empty": 1,
"fieldname": "item_name",
"fieldtype": "Data",
"label": "Item Name"
},
{
"collapsible": 1,
"fieldname": "item_details_section",
"fieldtype": "Section Break",
"label": "Item Details"
},
{
"fetch_from": "item_code.description",
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Description"
},
{
"fieldname": "column_break_7",
"fieldtype": "Column Break"
},
{
"fetch_from": "item_code.image",
"fieldname": "image",
"fieldtype": "Attach",
"hidden": 1,
"label": "Image"
},
{
"fetch_from": "item_code.image",
"fieldname": "image_view",
"fieldtype": "Image",
"hidden": 1,
"label": "Image View",
"options": "image",
"print_hide": 1
},
{
"fieldname": "warehouse_section",
"fieldtype": "Section Break",
"label": "Warehouse"
},
{
"fieldname": "warehouse",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Warehouse",
"options": "Warehouse"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-03-10 19:13:41.310816",
"modified_by": "Administrator",
"module": "E-commerce",
"name": "Wishlist Items",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
# import frappe
from frappe.model.document import Document
class WishlistItems(Document):
pass

View File

@ -22,7 +22,7 @@ class ProductQuery:
self.page_length = self.settings.products_per_page or 20
self.fields = ['wi.name', 'wi.item_name', 'wi.item_code', 'wi.website_image', 'wi.variant_of',
'wi.has_variants', 'wi.item_group', 'wi.image', 'wi.web_long_description', 'wi.description',
'wi.route']
'wi.route', 'wi.website_warehouse']
self.conditions = ""
self.or_conditions = ""
self.substitutions = []
@ -62,12 +62,22 @@ class ProductQuery:
result = self.query_items(self.conditions, self.or_conditions,
self.substitutions, start=start)
# add price info in results
# add price and availability info in results
for item in result:
product_info = get_product_info_for_website(item.item_code, skip_quotation_creation=True).get('product_info')
if product_info:
item.formatted_price = (product_info.get('price') or {}).get('formatted_price')
if self.settings.show_stock_availability and item.get("website_warehouse"):
stock_qty = frappe.utils.flt(
frappe.db.get_value("Bin",
{
"item_code": item.item_code,
"warehouse": item.get("website_warehouse")
},
"actual_qty")
)
item.in_stock = "green" if stock_qty else "red"
return result
def query_items(self, conditions, or_conditions, substitutions, start=0):

View File

@ -519,3 +519,54 @@ body.product-page {
border: 1px solid var(--dark-border-color);
}
}
.card-indicator {
margin-left: 6px;
}
.like-action {
text-align: center;
margin-top: -2px;
margin-left: 12px;
}
.wish-icon {
cursor: pointer;
stroke: #F47A7A !important;
&:hover {
fill: #F47A7A;
}
}
.wished {
.wish-icon {
stroke: none;
fill: #F47A7A !important;
}
}
.list-row-checkbox {
&:before {
display: none;
}
&:checked:before {
display: block;
z-index: 1;
}
}
.btn-add-to-cart-list {
color: var(--blue-500);
background-color: white;
box-shadow: none;
border: 1px solid var(--blue-500);
margin: var(--margin-sm) 0;
flex: none;
&:hover {
background-color: var(--blue-500);
color: white;
}
}

View File

@ -59,7 +59,7 @@
{% endmacro %}
{%- macro item_card(title, image, url, description, rate, category, is_featured=False, is_full_width=False, align="Left") -%}
{%- macro item_card(title, image, url, description, rate, category, in_stock=None, is_featured=False, is_full_width=False, align="Left") -%}
{%- set align_items_class = resolve_class({
'align-items-end': align == 'Right',
'align-items-center': align == 'Center',
@ -89,35 +89,61 @@
<div class="col-sm-{{ col_size }} item-card">
<div class="card {{ align_items_class }}">
{% if image %}
<div class="card-img-container">
<img class="card-img" src="{{ image }}" alt="{{ title }}">
</div>
<div class="card-img-container">
<a href="/{{ url or '#' }}" style="text-decoration: none;">
<img class="card-img" src="{{ image }}" alt="{{ title }}">
</a>
</div>
{% else %}
<div class="card-img-top no-image">
{{ frappe.utils.get_abbr(title) }}
</div>
<a href="/{{ url or '#' }}" style="text-decoration: none;">
<div class="card-img-top no-image">
{{ frappe.utils.get_abbr(title) }}
</div>
</a>
{% endif %}
{{ item_card_body(title, description, url, rate, category, is_featured, align) }}
{{ item_card_body(title, description, url, rate, category, is_featured, align, in_stock) }}
</div>
</div>
{% endif %}
{%- endmacro -%}
{%- macro item_card_body(title, description, url, rate, category, is_featured, align) -%}
{%- macro item_card_body(title, description, url, rate, category, is_featured, align, in_stock=None) -%}
{%- set align_class = resolve_class({
'text-right': align == 'Right',
'text-center': align == 'Center' and not is_featured,
'text-left': align == 'Left' or is_featured,
}) -%}
<div class="card-body {{ align_class }}">
<div class="product-title">{{ title or '' }}</div>
<div class="card-body {{ align_class }}" style="width:100%">
<div style="margin-top: 16px; display: flex;">
<a href="/{{ url or '#' }}">
<div class="product-title">{{ title or '' }}</div>
</a>
{% if in_stock %}
<span class="indicator {{ in_stock }} card-indicator"></span>
{% endif %}
<input class="level-item list-row-checkbox hidden-xs"
type="checkbox" data-name="{{ title }}" style="display: none !important;">
<div class="like-action"
data-name="{{ title }}" data-doctype="Item">
<svg class="icon sm">
<use class="wish-icon" href="#icon-heart"></use>
</svg>
</div>
</div>
{% if is_featured %}
<div class="product-price">{{ rate or '' }}</div>
<div class="product-description ellipsis">{{ description or '' }}</div>
{% else %}
<div class="product-category">{{ category or '' }}</div>
<div class="product-price">{{ rate or '' }}</div>
<div style="display: flex;">
{% if rate %}
<div class="product-price" style="width: 60%;">{{ rate or '' }}</div>
{% endif %}
<div class="btn btn-sm btn-add-to-cart-list">
{{ _('Add to Cart') }}
</div>
</div>
{% endif %}
</div>
<a href="/{{ url or '#' }}" class="stretched-link"></a>
{%- endmacro -%}

View File

@ -2,5 +2,5 @@
{{ item_card(
item.item_name or item.name, item.website_image or item.image, item.route, item.website_description or item.description,
item.formatted_price, item.item_group
item.formatted_price, item.item_group, in_stock=item.in_stock
) }}