mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-27 08:54:45 +00:00
Item, Item Group and Partner Web Page generators moved from Shopping Cart to ERPNext
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
"email_id": "test_lead@example.com",
|
"email_id": "test_lead@example.com",
|
||||||
"lead_name": "_Test Lead",
|
"lead_name": "_Test Lead",
|
||||||
"status": "Open",
|
"status": "Open",
|
||||||
"territory": "_Test Territory Rest Of The World"
|
"territory": "_Test Territory"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "Lead",
|
"doctype": "Lead",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import frappe
|
|||||||
|
|
||||||
from frappe.utils.nestedset import NestedSet
|
from frappe.utils.nestedset import NestedSet
|
||||||
from frappe.website.website_generator import WebsiteGenerator
|
from frappe.website.website_generator import WebsiteGenerator
|
||||||
|
from frappe.website.render import clear_cache
|
||||||
|
|
||||||
class ItemGroup(NestedSet, WebsiteGenerator):
|
class ItemGroup(NestedSet, WebsiteGenerator):
|
||||||
nsm_parent_field = 'parent_item_group'
|
nsm_parent_field = 'parent_item_group'
|
||||||
@@ -19,7 +20,9 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
|||||||
self.parent_item_group)
|
self.parent_item_group)
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
super(ItemGroup, self).on_update()
|
NestedSet.on_update(self)
|
||||||
|
WebsiteGenerator.on_update(self)
|
||||||
|
invalidate_cache_for(self)
|
||||||
self.validate_name_with_item()
|
self.validate_name_with_item()
|
||||||
self.validate_one_root()
|
self.validate_one_root()
|
||||||
|
|
||||||
@@ -32,3 +35,18 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
|||||||
def validate_name_with_item(self):
|
def validate_name_with_item(self):
|
||||||
if frappe.db.exists("Item", self.name):
|
if frappe.db.exists("Item", self.name):
|
||||||
frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name))
|
frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name))
|
||||||
|
|
||||||
|
def get_parent_item_groups(item_group_name):
|
||||||
|
item_group = frappe.get_doc("Item Group", item_group_name)
|
||||||
|
return frappe.db.sql("""select name, page_name from `tabItem Group`
|
||||||
|
where lft <= %s and rgt >= %s
|
||||||
|
and ifnull(show_in_website,0)=1
|
||||||
|
order by lft asc""", (item_group.lft, item_group.rgt), as_dict=True)
|
||||||
|
|
||||||
|
def invalidate_cache_for(doc, item_group=None):
|
||||||
|
if not item_group:
|
||||||
|
item_group = doc.name
|
||||||
|
|
||||||
|
for i in get_parent_item_groups(item_group):
|
||||||
|
if i.page_name:
|
||||||
|
clear_cache(i.page_name)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import frappe
|
|||||||
from frappe import msgprint, _
|
from frappe import msgprint, _
|
||||||
from frappe.utils import cstr, flt, getdate, now_datetime, formatdate
|
from frappe.utils import cstr, flt, getdate, now_datetime, formatdate
|
||||||
from frappe.website.website_generator import WebsiteGenerator
|
from frappe.website.website_generator import WebsiteGenerator
|
||||||
|
from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for
|
||||||
|
from frappe.website.render import clear_cache
|
||||||
|
|
||||||
class WarehouseNotSet(frappe.ValidationError): pass
|
class WarehouseNotSet(frappe.ValidationError): pass
|
||||||
|
|
||||||
@@ -46,6 +48,7 @@ class Item(WebsiteGenerator):
|
|||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
super(Item, self).on_update()
|
super(Item, self).on_update()
|
||||||
|
invalidate_cache_for_item(self)
|
||||||
self.validate_name_with_item_group()
|
self.validate_name_with_item_group()
|
||||||
self.update_item_price()
|
self.update_item_price()
|
||||||
|
|
||||||
@@ -230,6 +233,9 @@ class Item(WebsiteGenerator):
|
|||||||
|
|
||||||
def after_rename(self, olddn, newdn, merge):
|
def after_rename(self, olddn, newdn, merge):
|
||||||
super(Item, self).after_rename(olddn, newdn, merge)
|
super(Item, self).after_rename(olddn, newdn, merge)
|
||||||
|
if self.page_name:
|
||||||
|
invalidate_cache_for_item(self)
|
||||||
|
clear_cache(self.page_name)
|
||||||
|
|
||||||
frappe.db.set_value("Item", newdn, "item_code", newdn)
|
frappe.db.set_value("Item", newdn, "item_code", newdn)
|
||||||
if merge:
|
if merge:
|
||||||
@@ -344,3 +350,8 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0):
|
|||||||
})
|
})
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def invalidate_cache_for_item(doc):
|
||||||
|
invalidate_cache_for(doc, doc.item_group)
|
||||||
|
for d in doc.get({"doctype":"Website Item Group"}):
|
||||||
|
invalidate_cache_for(doc, d.item_group)
|
||||||
|
|||||||
0
erpnext/templates/generators/__init__.py
Normal file
0
erpnext/templates/generators/__init__.py
Normal file
84
erpnext/templates/generators/item.html
Normal file
84
erpnext/templates/generators/item.html
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
{% block title %} {{ title }} {% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h2>{{ title }}</h2>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="item-content">
|
||||||
|
{% include 'templates/includes/product_search_box.html' %}
|
||||||
|
{% include 'templates/includes/product_breadcrumbs.html' %}
|
||||||
|
<div class="product-page-content" itemscope itemtype="http://schema.org/Product">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{% if slideshow %}
|
||||||
|
{% include "templates/includes/slideshow.html" %}
|
||||||
|
{% else %}
|
||||||
|
{% if website_image %}
|
||||||
|
<image itemprop="image" class="item-main-image"
|
||||||
|
src="{{ website_image }}" />
|
||||||
|
{% else %}
|
||||||
|
<div class="img-area">
|
||||||
|
{% include 'templates/includes/product_missing_image.html' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h3 itemprop="name" style="margin-top: 0px;">{{ item_name }}</h3>
|
||||||
|
<p class="help">Item Code: <span itemprop="productID">{{ name }}</span></p>
|
||||||
|
<h4>Product Description</h4>
|
||||||
|
<div itemprop="description">
|
||||||
|
{{ web_long_description or description or "[No description given]" }}
|
||||||
|
</div>
|
||||||
|
<div style="min-height: 100px; margin: 10px 0;">
|
||||||
|
<div class="item-price-info" style="display: none;">
|
||||||
|
<h4 class="item-price" itemprop="price"></h4>
|
||||||
|
<div class="item-stock" itemprop="availablity"></div>
|
||||||
|
<div id="item-add-to-cart">
|
||||||
|
<button class="btn btn-primary">
|
||||||
|
<i class="icon-shopping-cart"></i> Add to Cart</button>
|
||||||
|
</div>
|
||||||
|
<div id="item-update-cart" class="input-group col-md-4" style="display: none;
|
||||||
|
padding-left: 0px; padding-right: 0px;">
|
||||||
|
<input class="form-control" type="text">
|
||||||
|
<div class="input-group-btn">
|
||||||
|
<button class="btn btn-primary">
|
||||||
|
<i class="icon-ok"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if doc.get({"doctype":"Item Website Specification"}) -%}
|
||||||
|
<div class="row" style="margin-top: 20px">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h4>Specifications</h4>
|
||||||
|
<table class="table table-bordered" style="width: 100%">
|
||||||
|
{% for d in doc.get(
|
||||||
|
{"doctype":"Item Website Specification"}) -%}
|
||||||
|
<tr>
|
||||||
|
<td style="width: 30%;">{{ d.label }}</td>
|
||||||
|
<td>{{ d.description }}</td>
|
||||||
|
</tr>
|
||||||
|
{%- endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
{% include "templates/includes/product_page.js" %}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
if(window.logged_in && getCookie("system_user")==="yes") {
|
||||||
|
frappe.has_permission("Item", "{{ name }}", "write", function(r) {
|
||||||
|
frappe.require("/assets/frappe/js/frappe/website/editable.js");
|
||||||
|
frappe.make_editable($('[itemprop="description"]'), "Item", "{{ name }}", "web_long_description");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %}
|
||||||
20
erpnext/templates/generators/item.py
Normal file
20
erpnext/templates/generators/item.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups
|
||||||
|
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
|
||||||
|
|
||||||
|
doctype = "Item"
|
||||||
|
condition_field = "show_in_website"
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
item_context = context.doc.as_dict()
|
||||||
|
item_context["parent_groups"] = get_parent_item_groups(context.doc.item_group) + \
|
||||||
|
[{"name":context.doc.name}]
|
||||||
|
if context.doc.slideshow:
|
||||||
|
item_context.update(get_slideshow(context.doc))
|
||||||
|
|
||||||
|
return item_context
|
||||||
58
erpnext/templates/generators/item_group.html
Normal file
58
erpnext/templates/generators/item_group.html
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{% block title %} {{ title }} {% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h2>{{ title }}</h2>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="item-group-content">
|
||||||
|
{% include 'templates/includes/product_search_box.html' %}
|
||||||
|
{% include 'templates/includes/product_breadcrumbs.html' %}
|
||||||
|
<div>
|
||||||
|
{% if slideshow %}<!-- slideshow -->
|
||||||
|
{% include "templates/includes/slideshow.html" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if description %}<!-- description -->
|
||||||
|
<div itemprop="description">{{ description or ""}}</div>
|
||||||
|
{% else %}
|
||||||
|
<h3>{{ name }}</h3>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{% if sub_groups %}
|
||||||
|
<hr />
|
||||||
|
<div class="row">
|
||||||
|
{% for d in sub_groups %}
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<a href="{{ d.page_name }}">{{ d.name }} ({{ d.count }})</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
{% endif %}
|
||||||
|
{% if items %}
|
||||||
|
<div id="search-list" class="row">
|
||||||
|
{% for item in items %}
|
||||||
|
{{ item }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% if (items|length)==100 %}
|
||||||
|
<div class="alert alert-info info">Showing top 100 items.</div>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-warning">No items listed.</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
if(window.logged_in && getCookie("system_user")==="yes") {
|
||||||
|
frappe.has_permission("Item Group", "{{ name }}", "write", function(r) {
|
||||||
|
frappe.require("/assets/frappe/js/frappe/website/editable.js");
|
||||||
|
frappe.make_editable($('[itemprop="description"]'), "Item Group", "{{ name }}", "description");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %}
|
||||||
64
erpnext/templates/generators/item_group.py
Normal file
64
erpnext/templates/generators/item_group.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
|
||||||
|
from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups
|
||||||
|
|
||||||
|
doctype = "Item Group"
|
||||||
|
condition_field = "show_in_website"
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
item_group_context = context.doc.as_dict()
|
||||||
|
item_group_context.update({
|
||||||
|
"sub_groups": frappe.db.sql("""select name, page_name
|
||||||
|
from `tabItem Group` where parent_item_group=%s
|
||||||
|
and ifnull(show_in_website,0)=1""", context.docname, as_dict=1),
|
||||||
|
"items": get_product_list_for_group(product_group = context.docname, limit=100),
|
||||||
|
"parent_groups": get_parent_item_groups(context.docname),
|
||||||
|
"title": context.docname
|
||||||
|
})
|
||||||
|
|
||||||
|
if context.doc.slideshow:
|
||||||
|
item_group_context.update(get_slideshow(context.doc))
|
||||||
|
|
||||||
|
for d in item_group_context.sub_groups:
|
||||||
|
d.count = get_group_item_count(d.name)
|
||||||
|
|
||||||
|
return item_group_context
|
||||||
|
|
||||||
|
def get_product_list_for_group(product_group=None, start=0, limit=10):
|
||||||
|
child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(product_group)])
|
||||||
|
|
||||||
|
# base query
|
||||||
|
query = """select name, item_name, page_name, website_image, item_group,
|
||||||
|
web_long_description as website_description
|
||||||
|
from `tabItem` where docstatus = 0 and show_in_website = 1
|
||||||
|
and (item_group in (%s)
|
||||||
|
or name in (select parent from `tabWebsite Item Group` where item_group in (%s))) """ % (child_groups, child_groups)
|
||||||
|
|
||||||
|
query += """order by weightage desc, modified desc limit %s, %s""" % (start, limit)
|
||||||
|
|
||||||
|
data = frappe.db.sql(query, {"product_group": product_group}, as_dict=1)
|
||||||
|
|
||||||
|
return [get_item_for_list_in_html(r) for r in data]
|
||||||
|
|
||||||
|
def get_child_groups(item_group_name):
|
||||||
|
item_group = frappe.get_doc("Item Group", item_group_name)
|
||||||
|
return frappe.db.sql("""select name
|
||||||
|
from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
|
||||||
|
and show_in_website = 1""", item_group.as_dict())
|
||||||
|
|
||||||
|
def get_item_for_list_in_html(context):
|
||||||
|
return frappe.get_template("templates/includes/product_in_grid.html").render(context)
|
||||||
|
|
||||||
|
def get_group_item_count(item_group):
|
||||||
|
child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(item_group)])
|
||||||
|
return frappe.db.sql("""select count(*) from `tabItem`
|
||||||
|
where docstatus = 0 and show_in_website = 1
|
||||||
|
and (item_group in (%s)
|
||||||
|
or name in (select parent from `tabWebsite Item Group`
|
||||||
|
where item_group in (%s))) """ % (child_groups, child_groups))[0][0]
|
||||||
|
|
||||||
29
erpnext/templates/generators/partner.html
Normal file
29
erpnext/templates/generators/partner.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{% block title %} {{ title }} {% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h2>{{ title }}</h2>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="partner-content" itemscope itemtype="http://schema.org/Organization">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
{% if logo -%}
|
||||||
|
<img itemprop="brand" src="{{ logo }}" class="partner-logo"
|
||||||
|
alt="{{ partner_name }}" title="{{ partner_name }}" />
|
||||||
|
<br><br>
|
||||||
|
{%- endif %}
|
||||||
|
<address>
|
||||||
|
{% if partner_website -%}<p><a href="{{ partner_website }}"
|
||||||
|
target="_blank">{{ partner_website }}</a></p>{%- endif %}
|
||||||
|
{% if partner_address -%}<p itemprop="address">{{ partner_address }}</p>{%- endif %}
|
||||||
|
{% if phone -%}<p itemprop="telephone">{{ phone }}</p>{%- endif %}
|
||||||
|
{% if email -%}<p itemprop="email"><span class="icon-envelope"></span> {{ email }}</p>{%- endif %}
|
||||||
|
</address>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<p>{{ description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %}
|
||||||
28
erpnext/templates/generators/partner.py
Normal file
28
erpnext/templates/generators/partner.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.utils import filter_strip_join
|
||||||
|
|
||||||
|
doctype = "Sales Partner"
|
||||||
|
condition_field = "show_in_website"
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
partner_context = context.doc.as_dict()
|
||||||
|
|
||||||
|
address = frappe.db.get_value("Address",
|
||||||
|
{"sales_partner": context.doc.name, "is_primary_address": 1},
|
||||||
|
"*", as_dict=True)
|
||||||
|
if address:
|
||||||
|
city_state = ", ".join(filter(None, [address.city, address.state]))
|
||||||
|
address_rows = [address.address_line1, address.address_line2,
|
||||||
|
city_state, address.pincode, address.country]
|
||||||
|
|
||||||
|
partner_context.update({
|
||||||
|
"email": address.email_id,
|
||||||
|
"partner_address": filter_strip_join(address_rows, "\n<br>"),
|
||||||
|
"phone": filter_strip_join(cstr(address.phone).split(","), "\n<br>")
|
||||||
|
})
|
||||||
|
|
||||||
|
return partner_context
|
||||||
0
erpnext/templates/includes/__init__.py
Normal file
0
erpnext/templates/includes/__init__.py
Normal file
10
erpnext/templates/includes/product_breadcrumbs.html
Normal file
10
erpnext/templates/includes/product_breadcrumbs.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{% if parent_groups and (parent_groups|length) > 1 %}
|
||||||
|
<div class="container">
|
||||||
|
<ul class="breadcrumb">
|
||||||
|
{% for ig in parent_groups[:-1] %}
|
||||||
|
<li><a href="{{ ig.page_name }}.html">{{ ig.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
<li class="active">{{ parent_groups[-1].name }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
14
erpnext/templates/includes/product_in_grid.html
Normal file
14
erpnext/templates/includes/product_in_grid.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<div class="col-sm-3">
|
||||||
|
<div style="height: 120px; overflow: hidden;">
|
||||||
|
<a href="{{ page_name }}">
|
||||||
|
{%- if website_image -%}
|
||||||
|
<img class="product-image" style="width: 80%; margin: auto;" src="{{ website_image }}">
|
||||||
|
{%- else -%}
|
||||||
|
{% include 'templates/includes/product_missing_image.html' %}
|
||||||
|
{%- endif -%}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div style="height: 100px; overflow: hidden; font-size: 80%;">
|
||||||
|
<h4 style="margin-bottom: 2px;"><a href="{{ page_name }}">{{ item_name }}</a></h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
15
erpnext/templates/includes/product_in_list.html
Normal file
15
erpnext/templates/includes/product_in_list.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<!-- TODO product listing -->
|
||||||
|
<div class="container content">
|
||||||
|
<div style="height: 120px; overflow: hidden;">
|
||||||
|
<a href="{{ page_name }}">
|
||||||
|
{%- if website_image -%}
|
||||||
|
<img class="product-image" style="width: 80%; margin: auto;" src="{{ website_image }}">
|
||||||
|
{%- else -%}
|
||||||
|
{% include 'templates/includes/product_missing_image.html' %}
|
||||||
|
{%- endif -%}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div style="height: 100px; overflow: hidden; font-size: 80%;">
|
||||||
|
<h4 style="margin-bottom: 2px;"><a href="{{ page_name }}">{{ item_name }}</a></h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
52
erpnext/templates/includes/product_list.js
Normal file
52
erpnext/templates/includes/product_list.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
window.get_product_list = function() {
|
||||||
|
$(".more-btn .btn").click(function() {
|
||||||
|
window.get_product_list()
|
||||||
|
});
|
||||||
|
|
||||||
|
if(window.start==undefined) {
|
||||||
|
throw "product list not initialized (no start)"
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
cmd: "erpnext.templates.pages.product_search.get_product_list",
|
||||||
|
start: window.start,
|
||||||
|
search: window.search,
|
||||||
|
product_group: window.product_group
|
||||||
|
},
|
||||||
|
dataType: "json",
|
||||||
|
success: function(data) {
|
||||||
|
window.render_product_list(data.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
window.render_product_list = function(data) {
|
||||||
|
if(data.length) {
|
||||||
|
var table = $("#search-list .table");
|
||||||
|
if(!table.length)
|
||||||
|
var table = $("<table class='table'>").appendTo("#search-list");
|
||||||
|
|
||||||
|
$.each(data, function(i, d) {
|
||||||
|
$(d).appendTo(table);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(data.length < 10) {
|
||||||
|
if(!table) {
|
||||||
|
$(".more-btn")
|
||||||
|
.replaceWith("<div class='alert alert-warning'>No products found.</div>");
|
||||||
|
} else {
|
||||||
|
$(".more-btn")
|
||||||
|
.replaceWith("<div class='text-muted'>Nothing more to show.</div>");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(".more-btn").toggle(true)
|
||||||
|
}
|
||||||
|
window.start += (data.length || 0);
|
||||||
|
}
|
||||||
1
erpnext/templates/includes/product_missing_image.html
Normal file
1
erpnext/templates/includes/product_missing_image.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<div class="missing-image"><i class="icon-camera"></i></div>
|
||||||
78
erpnext/templates/includes/product_page.js
Normal file
78
erpnext/templates/includes/product_page.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
var item_code = $('[itemscope] [itemprop="productID"]').text().trim();
|
||||||
|
var qty = 0;
|
||||||
|
|
||||||
|
frappe.call({
|
||||||
|
type: "POST",
|
||||||
|
method: "shopping_cart.shopping_cart.product.get_product_info",
|
||||||
|
args: {
|
||||||
|
item_code: "{{ name }}"
|
||||||
|
},
|
||||||
|
callback: function(r) {
|
||||||
|
if(r.message && r.message.price) {
|
||||||
|
$(".item-price")
|
||||||
|
.html(r.message.price.formatted_price + " per " + r.message.uom);
|
||||||
|
|
||||||
|
if(r.message.stock==0) {
|
||||||
|
$(".item-stock").html("<div class='help'>Not in stock</div>");
|
||||||
|
}
|
||||||
|
else if(r.message.stock==1) {
|
||||||
|
$(".item-stock").html("<div style='color: green'>\
|
||||||
|
<i class='icon-check'></i> Available (in stock)</div>");
|
||||||
|
}
|
||||||
|
|
||||||
|
$(".item-price-info").toggle(true);
|
||||||
|
|
||||||
|
if(r.message.qty) {
|
||||||
|
qty = r.message.qty;
|
||||||
|
toggle_update_cart(qty);
|
||||||
|
$("#item-update-cart input").val(qty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$("#item-add-to-cart button").on("click", function() {
|
||||||
|
shopping_cart.update_cart({
|
||||||
|
item_code: item_code,
|
||||||
|
qty: 1,
|
||||||
|
callback: function(r) {
|
||||||
|
if(!r.exc) {
|
||||||
|
toggle_update_cart(1);
|
||||||
|
qty = 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
btn: this,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#item-update-cart button").on("click", function() {
|
||||||
|
shopping_cart.update_cart({
|
||||||
|
item_code: item_code,
|
||||||
|
qty: $("#item-update-cart input").val(),
|
||||||
|
btn: this,
|
||||||
|
callback: function(r) {
|
||||||
|
if(r.exc) {
|
||||||
|
$("#item-update-cart input").val(qty);
|
||||||
|
} else {
|
||||||
|
qty = $("#item-update-cart input").val();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if(localStorage && localStorage.getItem("pending_add_to_cart") && full_name) {
|
||||||
|
localStorage.removeItem("pending_add_to_cart");
|
||||||
|
$("#item-add-to-cart button").trigger("click");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var toggle_update_cart = function(qty) {
|
||||||
|
$("#item-add-to-cart").toggle(qty ? false : true);
|
||||||
|
$("#item-update-cart")
|
||||||
|
.toggle(qty ? true : false)
|
||||||
|
.find("input").val(qty);
|
||||||
|
}
|
||||||
28
erpnext/templates/includes/product_search_box.html
Normal file
28
erpnext/templates/includes/product_search_box.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<div class="container" style="margin-bottom: 7px;">
|
||||||
|
<form class="form-inline form-search row">
|
||||||
|
<div class="input-group col-md-4 col-md-offset-8">
|
||||||
|
<input class="form-control" type="text" id="product-search" placeholder="Product Search...">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-default" type="button" id="btn-product-search">
|
||||||
|
<i class="icon-search"></i></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<script>
|
||||||
|
// redirect to product search page
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('.dropdown-toggle').dropdown();
|
||||||
|
$("#btn-product-search").click(function() {
|
||||||
|
var txt = $("#product-search").val();
|
||||||
|
if(txt) {
|
||||||
|
window.location.href="product_search?q=" + txt;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
$("#product-search").keypress(function(e) {
|
||||||
|
if(e.which==13) $("#btn-product-search").click();
|
||||||
|
});
|
||||||
|
$(".form-search").on("submit", function() { return false; });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
0
erpnext/templates/pages/__init__.py
Normal file
0
erpnext/templates/pages/__init__.py
Normal file
30
erpnext/templates/pages/partners.html
Normal file
30
erpnext/templates/pages/partners.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{% block title %} {{ title }} {% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h2>{{ title }}</h2>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="partners-content">
|
||||||
|
{% for partner_info in partners %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
{% if partner_info.logo -%}
|
||||||
|
<a href="{{ partner_info.page_name }}">
|
||||||
|
<img itemprop="brand" src="{{ partner_info.logo }}" class="partner-logo"
|
||||||
|
alt="{{ partner_info.partner_name }}" title="{{ partner_info.partner_name }}" />
|
||||||
|
</a>
|
||||||
|
{%- endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<a href="{{ partner_info.page_name }}">
|
||||||
|
<h4>{{ partner_info.partner_name }}</h4>
|
||||||
|
</a>
|
||||||
|
<p style="color: #999">{{ partner_info.territory }} - {{ partner_info.partner_type }}</p>
|
||||||
|
<p>{{ partner_info.introduction }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %}
|
||||||
13
erpnext/templates/pages/partners.py
Normal file
13
erpnext/templates/pages/partners.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
import frappe.website.render
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
return {
|
||||||
|
"partners": frappe.db.sql("""select * from `tabSales Partner`
|
||||||
|
where show_in_website=1 order by name asc""", as_dict=True),
|
||||||
|
"title": "Partners"
|
||||||
|
}
|
||||||
33
erpnext/templates/pages/product_search.html
Normal file
33
erpnext/templates/pages/product_search.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{% block title %} {{ "Product Search" }} {% endblock %}
|
||||||
|
|
||||||
|
{% block header %}<h2>Product Search</h2>{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<script>{% include "templates/includes/product_list.js" %}</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
var txt = get_url_arg("q");
|
||||||
|
$(".search-results").html("Search results for: " + txt);
|
||||||
|
window.search = txt;
|
||||||
|
window.start = 0;
|
||||||
|
window.get_product_list();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% include "templates/includes/product_search_box.html" %}
|
||||||
|
<div class="product-search-content">
|
||||||
|
<h3 class="search-results">Search Results</h3>
|
||||||
|
<div id="search-list" class="row">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div class="more-btn"
|
||||||
|
style="display: none; text-align: center;">
|
||||||
|
<button class="btn">More...</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %}
|
||||||
33
erpnext/templates/pages/product_search.py
Normal file
33
erpnext/templates/pages/product_search.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.utils import cstr
|
||||||
|
from erpnext.templates.generators.item_group import get_item_for_list_in_html
|
||||||
|
|
||||||
|
no_cache = 1
|
||||||
|
no_sitemap = 1
|
||||||
|
|
||||||
|
@frappe.whitelist(allow_guest=True)
|
||||||
|
def get_product_list(search=None, start=0, limit=10):
|
||||||
|
# base query
|
||||||
|
query = """select name, item_name, page_name, website_image, item_group,
|
||||||
|
web_long_description as website_description
|
||||||
|
from `tabItem` where docstatus = 0 and show_in_website = 1 """
|
||||||
|
|
||||||
|
# search term condition
|
||||||
|
if search:
|
||||||
|
query += """and (web_long_description like %(search)s or
|
||||||
|
item_name like %(search)s or name like %(search)s)"""
|
||||||
|
search = "%" + cstr(search) + "%"
|
||||||
|
|
||||||
|
# order by
|
||||||
|
query += """order by weightage desc, modified desc limit %s, %s""" % (start, limit)
|
||||||
|
|
||||||
|
data = frappe.db.sql(query, {
|
||||||
|
"search": search,
|
||||||
|
}, as_dict=1)
|
||||||
|
|
||||||
|
return [get_item_for_list_in_html(r) for r in data]
|
||||||
|
|
||||||
Reference in New Issue
Block a user