@@ -35,57 +35,5 @@ | |||||
"color": "#16a085", | "color": "#16a085", | ||||
"icon": "icon-globe" | "icon": "icon-globe" | ||||
} | } | ||||
}, | |||||
"web": { | |||||
"pages": { | |||||
"404": { | |||||
"template": "lib/website/templates/404.html" | |||||
}, | |||||
"error": { | |||||
"no_cache": true, | |||||
"template": "lib/website/templates/error.html" | |||||
}, | |||||
"login": { | |||||
"template": "lib/website/templates/login.html" | |||||
}, | |||||
"message": { | |||||
"no_cache": true, | |||||
"template": "lib/website/templates/message.html" | |||||
}, | |||||
"print": { | |||||
"no_cache": true, | |||||
"template": "lib/website/templates/print.html", | |||||
"args_method": "core.doctype.print_format.print_format.get_args" | |||||
}, | |||||
"index": { | |||||
"template": "lib/website/doctype/web_page/templates/index.html" | |||||
}, | |||||
"writers": { | |||||
"template": "lib/website/doctype/blogger/templates/writers.html", | |||||
"args_method": "website.doctype.blogger.blogger.get_writers_args" | |||||
}, | |||||
"blog": { | |||||
"template": "lib/website/doctype/blog_post/templates/blog_post.html", | |||||
"args_method": "website.doctype.blog_post.blog_post.get_blog_template_args" | |||||
}, | |||||
"contact": { | |||||
"template": "lib/website/doctype/contact_us_settings/templates/contact.html", | |||||
"args_doctype": "Contact Us Settings" | |||||
}, | |||||
"about": { | |||||
"template": "lib/website/doctype/about_us_settings/templates/about.html", | |||||
"args_method": "website.doctype.about_us_settings.about_us_settings.get_args" | |||||
} | |||||
}, | |||||
"generators": { | |||||
"Web Page": { | |||||
"template": "lib/website/doctype/web_page/templates/web_page.html", | |||||
"condition_field": "published" | |||||
}, | |||||
"Blog Post": { | |||||
"template": "lib/website/doctype/blog_post/templates/blog_post.html", | |||||
"condition_field": "published" | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -119,36 +119,24 @@ def send_comm_email(d, name, sent_via=None, print_html=None, attachments='[]', s | |||||
def set_portal_link(sent_via, comm): | def set_portal_link(sent_via, comm): | ||||
"""set portal link in footer""" | """set portal link in footer""" | ||||
from webnotes.webutils import is_portal_enabled, get_portal_links | |||||
from webnotes.webutils import is_signup_enabled | |||||
from webnotes.utils import get_url, cstr | from webnotes.utils import get_url, cstr | ||||
import urllib | import urllib | ||||
footer = None | footer = None | ||||
if is_portal_enabled(): | |||||
portal_opts = get_portal_links().get(sent_via.doc.doctype) | |||||
if portal_opts: | |||||
valid_recipient = cstr(sent_via.doc.email or sent_via.doc.email_id or | |||||
if is_signup_enabled() and hasattr(sent_via, "get_portal_page"): | |||||
portal_page = sent_via.get_portal_page() | |||||
if portal_page: | |||||
is_valid_recipient = cstr(sent_via.doc.email or sent_via.doc.email_id or | |||||
sent_via.doc.contact_email) in comm.recipients | sent_via.doc.contact_email) in comm.recipients | ||||
if not valid_recipient: | |||||
attach_portal_link = False | |||||
else: | |||||
attach_portal_link = True | |||||
if portal_opts.get("conditions"): | |||||
for fieldname, val in portal_opts["conditions"].items(): | |||||
if sent_via.doc.fields.get(fieldname) != val: | |||||
attach_portal_link = False | |||||
break | |||||
if attach_portal_link: | |||||
url = "%s/%s?name=%s" % (get_url(), portal_opts["page"], | |||||
urllib.quote(sent_via.doc.name)) | |||||
if is_valid_recipient: | |||||
url = "%s/%s?name=%s" % (get_url(), portal_page, urllib.quote(sent_via.doc.name)) | |||||
footer = """<!-- Portal Link --><hr> | footer = """<!-- Portal Link --><hr> | ||||
<a href="%s" target="_blank">View this on our website</a>""" % url | <a href="%s" target="_blank">View this on our website</a>""" % url | ||||
return footer | return footer | ||||
def get_user(doctype, txt, searchfield, start, page_len, filters): | def get_user(doctype, txt, searchfield, start, page_len, filters): | ||||
from controllers.queries import get_match_cond | from controllers.queries import get_match_cond | ||||
return webnotes.conn.sql("""select name, concat_ws(' ', first_name, middle_name, last_name) | return webnotes.conn.sql("""select name, concat_ws(' ', first_name, middle_name, last_name) | ||||
@@ -477,26 +477,25 @@ def get_list(doctype, filters=None, fields=None, docstatus=None, | |||||
return webnotes.widgets.reportview.execute(doctype, filters=filters, fields=fields, docstatus=docstatus, | return webnotes.widgets.reportview.execute(doctype, filters=filters, fields=fields, docstatus=docstatus, | ||||
group_by=group_by, order_by=order_by, limit_start=limit_start, limit_page_length=limit_page_length, | group_by=group_by, order_by=order_by, limit_start=limit_start, limit_page_length=limit_page_length, | ||||
as_list=as_list, debug=debug) | as_list=as_list, debug=debug) | ||||
_config = None | _config = None | ||||
def get_config(): | def get_config(): | ||||
global _config | global _config | ||||
if not _config: | if not _config: | ||||
import webnotes.utils, json | import webnotes.utils, json | ||||
_config = _dict() | |||||
def update_config(path): | def update_config(path): | ||||
try: | try: | ||||
with open(path, "r") as configfile: | with open(path, "r") as configfile: | ||||
this_config = json.loads(configfile.read()) | this_config = json.loads(configfile.read()) | ||||
for k in ("app_name", "base_template"): | |||||
_config[k] = this_config.get(k) | |||||
_config.modules.update(this_config["modules"]) | |||||
_config.web.pages.update(this_config["web"]["pages"]) | |||||
_config.web.generators.update(this_config["web"]["generators"]) | |||||
for key, val in this_config.items(): | |||||
if isinstance(val, dict): | |||||
_config.setdefault(key, _dict()).update(val) | |||||
else: | |||||
_config[key] = val | |||||
except IOError: | except IOError: | ||||
pass | pass | ||||
_config = _dict({"modules": {}, "web": _dict({"pages": {}, "generators": {}})}) | |||||
update_config(webnotes.utils.get_path("lib", "config.json")) | update_config(webnotes.utils.get_path("lib", "config.json")) | ||||
update_config(webnotes.utils.get_path("app", "config.json")) | update_config(webnotes.utils.get_path("app", "config.json")) | ||||
@@ -5,6 +5,7 @@ from __future__ import unicode_literals | |||||
import conf | import conf | ||||
import webnotes | import webnotes | ||||
from webnotes import _ | |||||
import webnotes.utils | import webnotes.utils | ||||
class PageNotFoundError(Exception): pass | class PageNotFoundError(Exception): pass | ||||
@@ -56,7 +57,6 @@ def render_page(page_name): | |||||
def build_page(page_name): | def build_page(page_name): | ||||
from jinja2 import Environment, FileSystemLoader | from jinja2 import Environment, FileSystemLoader | ||||
import os | |||||
if not webnotes.conn: | if not webnotes.conn: | ||||
webnotes.connect() | webnotes.connect() | ||||
@@ -91,7 +91,7 @@ def build_page(page_name): | |||||
else: | else: | ||||
# page | # page | ||||
context = webnotes._dict({ 'name': page_name }) | context = webnotes._dict({ 'name': page_name }) | ||||
if module: | |||||
if module and hasattr(module, "get_context"): | |||||
context.update(module.get_context()) | context.update(module.get_context()) | ||||
context.update(get_website_settings()) | context.update(get_website_settings()) | ||||
@@ -114,7 +114,6 @@ def build_sitemap(): | |||||
for g in config["generators"].values(): | for g in config["generators"].values(): | ||||
g["is_generator"] = True | g["is_generator"] = True | ||||
module = webnotes.get_module(g["controller"]) | module = webnotes.get_module(g["controller"]) | ||||
doctype = module.doctype | |||||
for name in webnotes.conn.sql_list("""select page_name from `tab%s` where | for name in webnotes.conn.sql_list("""select page_name from `tab%s` where | ||||
ifnull(%s, 0)=1""" % (module.doctype, module.condition_field)): | ifnull(%s, 0)=1""" % (module.doctype, module.condition_field)): | ||||
sitemap[name] = g | sitemap[name] = g | ||||
@@ -133,7 +132,7 @@ def get_home_page(): | |||||
return page_name | return page_name | ||||
def build_website_sitemap_config(): | def build_website_sitemap_config(): | ||||
import os, json | |||||
import os | |||||
config = {"pages": {}, "generators":{}} | config = {"pages": {}, "generators":{}} | ||||
basepath = webnotes.utils.get_base_path() | basepath = webnotes.utils.get_base_path() | ||||
@@ -167,9 +166,8 @@ def build_website_sitemap_config(): | |||||
return config | return config | ||||
def get_website_settings(): | def get_website_settings(): | ||||
from webnotes.utils import get_request_site_address | |||||
from webnotes.utils import get_request_site_address, encode, cint | |||||
from urllib import quote | from urllib import quote | ||||
from webnotes.utils import cint, encode | |||||
all_top_items = webnotes.conn.sql("""\ | all_top_items = webnotes.conn.sql("""\ | ||||
select * from `tabTop Bar Item` | select * from `tabTop Bar Item` | ||||
@@ -199,11 +197,14 @@ def get_website_settings(): | |||||
}) | }) | ||||
settings = webnotes.doc("Website Settings", "Website Settings") | settings = webnotes.doc("Website Settings", "Website Settings") | ||||
for k in ["banner_html", "brand_html", "copyright", "address", "twitter_share_via", | |||||
for k in ["banner_html", "brand_html", "copyright", "twitter_share_via", | |||||
"favicon", "facebook_share", "google_plus_one", "twitter_share", "linked_in_share", | "favicon", "facebook_share", "google_plus_one", "twitter_share", "linked_in_share", | ||||
"disable_signup"]: | "disable_signup"]: | ||||
if k in settings.fields: | if k in settings.fields: | ||||
context[k] = settings.fields.get(k) | context[k] = settings.fields.get(k) | ||||
if settings.address: | |||||
context["footer_address"] = settings.address | |||||
for k in ["facebook_share", "google_plus_one", "twitter_share", "linked_in_share", | for k in ["facebook_share", "google_plus_one", "twitter_share", "linked_in_share", | ||||
"disable_signup"]: | "disable_signup"]: | ||||
@@ -228,6 +229,8 @@ def clear_cache(page_name=None): | |||||
cache = webnotes.cache() | cache = webnotes.cache() | ||||
for p in get_all_pages(): | for p in get_all_pages(): | ||||
cache.delete_value("page:" + p) | cache.delete_value("page:" + p) | ||||
cache.delete_value("website_sitemap") | |||||
cache.delete_value("website_sitemap_config") | |||||
def get_all_pages(): | def get_all_pages(): | ||||
return webnotes.cache().get_value("website_sitemap", build_sitemap).keys() | return webnotes.cache().get_value("website_sitemap", build_sitemap).keys() | ||||
@@ -267,44 +270,25 @@ def scrub_page_name(page_name): | |||||
return page_name | return page_name | ||||
def get_portal_links(): | |||||
portal_args = {} | |||||
for page, opts in webnotes.get_config()["web"]["pages"].items(): | |||||
if opts.get("portal"): | |||||
portal_args[opts["portal"]["doctype"]] = { | |||||
"page": page, | |||||
"conditions": opts["portal"].get("conditions") | |||||
} | |||||
return portal_args | |||||
_is_portal_enabled = None | |||||
def is_portal_enabled(): | |||||
global _is_portal_enabled | |||||
if _is_portal_enabled is None: | |||||
_is_portal_enabled = True | |||||
_is_signup_enabled = None | |||||
def is_signup_enabled(): | |||||
global _is_signup_enabled | |||||
if _is_signup_enabled is None: | |||||
_is_signup_enabled = True | |||||
if webnotes.utils.cint(webnotes.conn.get_value("Website Settings", | if webnotes.utils.cint(webnotes.conn.get_value("Website Settings", | ||||
"Website Settings", "disable_signup")): | "Website Settings", "disable_signup")): | ||||
_is_portal_enabled = False | |||||
_is_signup_enabled = False | |||||
return _is_portal_enabled | |||||
return _is_signup_enabled | |||||
def update_page_name(doc, title): | def update_page_name(doc, title): | ||||
"""set page_name and check if it is unique""" | """set page_name and check if it is unique""" | ||||
webnotes.conn.set(doc, "page_name", page_name(title)) | webnotes.conn.set(doc, "page_name", page_name(title)) | ||||
if doc.page_name in get_all_pages(): | if doc.page_name in get_all_pages(): | ||||
webnotes.conn.sql("""Page Name cannot be one of %s""" % ', '.join(get_standard_pages())) | |||||
webnotes.throw("%s: %s. %s: %s" % (doc.page_name, _("Page already exists"), | |||||
_("Please change the value"), title)) | |||||
res = webnotes.conn.sql("""\ | |||||
select count(*) from `tab%s` | |||||
where page_name=%s and name!=%s""" % (doc.doctype, '%s', '%s'), | |||||
(doc.page_name, doc.name)) | |||||
if res and res[0][0] > 0: | |||||
webnotes.msgprint("""A %s with the same title already exists. | |||||
Please change the title of %s and save again.""" | |||||
% (doc.doctype, doc.name), raise_exception=1) | |||||
delete_page_cache(doc.page_name) | delete_page_cache(doc.page_name) | ||||
def page_name(title): | def page_name(title): | ||||
@@ -1,3 +1,7 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
import webnotes | import webnotes | ||||
def get_context(): | def get_context(): | ||||
@@ -144,10 +144,14 @@ def add_comment(args=None): | |||||
webnotes.webutils.clear_cache(page_name) | webnotes.webutils.clear_cache(page_name) | ||||
args['comment_date'] = webnotes.utils.global_date_format(comment.doc.creation) | args['comment_date'] = webnotes.utils.global_date_format(comment.doc.creation) | ||||
template_args = { 'comment_list': [args], 'template': 'app/website/templates/html/comment.html' } | |||||
template_args = { 'comment_list': [args]} | |||||
# get html of comment row | # get html of comment row | ||||
comment_html = webnotes.webutils.build_html(template_args) | |||||
from jinja2 import Environment, FileSystemLoader | |||||
jenv = Environment(loader = FileSystemLoader(webnotes.utils.get_base_path())) | |||||
template = jenv.get_template("lib/website/doctype/blog_post/templates/includes/comment.html") | |||||
comment_html = template.render(template_args) | |||||
# notify commentors | # notify commentors | ||||
commentors = [d[0] for d in webnotes.conn.sql("""select comment_by from tabComment where | commentors = [d[0] for d in webnotes.conn.sql("""select comment_by from tabComment where | ||||
@@ -2,13 +2,13 @@ | |||||
{% block javascript %} | {% block javascript %} | ||||
<script> | <script> | ||||
{% include "lib/website/doctype/blog_post/templates/includes/blog_page.js" %} | |||||
{% include "lib/website/doctype/blog_post/templates/includes/blog_post.js" %} | |||||
</script> | </script> | ||||
{% endblock %} | {% endblock %} | ||||
{% block css %} | {% block css %} | ||||
<style> | <style> | ||||
{% include "lib/website/doctype/blog_post/templates/includes/blog_page.css" %} | |||||
{% include "lib/website/doctype/blog_post/templates/includes/blog_post.css" %} | |||||
</style> | </style> | ||||
{% endblock %} | {% endblock %} | ||||
@@ -1,5 +1,5 @@ | |||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | ||||
// License: GNU General Public License v3. See license.txt | |||||
// MIT License. See license.txt | |||||
// js inside blog page | // js inside blog page | ||||
@@ -10,15 +10,6 @@ class DocType: | |||||
def __init__(self, d, dl): | def __init__(self, d, dl): | ||||
self.doc, self.doclist = d, dl | self.doc, self.doclist = d, dl | ||||
def onload(self): | |||||
"""load address""" | |||||
if self.doc.query_options: | |||||
self.query_options = filter(None, self.doc.query_options.replace(",", "\n").split()) | |||||
else: | |||||
self.query_options = ["Sales", "Support", "General"] | |||||
if self.doc.address: | |||||
self.address = webnotes.bean("Address", self.doc.address).doc | |||||
def on_update(self): | def on_update(self): | ||||
from webnotes.webutils import clear_cache | from webnotes.webutils import clear_cache | ||||
clear_cache("contact") | clear_cache("contact") |
@@ -10,57 +10,58 @@ | |||||
{% block content %} | {% block content %} | ||||
<div class="col-md-12"> | <div class="col-md-12"> | ||||
<h3>{{ obj.doc.heading or "Contact Us"}}</h3> | |||||
<h3>{{ heading or "Contact Us"}}</h3> | |||||
<div class="row"> | <div class="row"> | ||||
<div class="web-form col-md-8"> | |||||
<div class="col-md-8"> | |||||
<p id="contact-alert" class="alert alert-warning" | <p id="contact-alert" class="alert alert-warning" | ||||
style="display: none;"> </p> | style="display: none;"> </p> | ||||
<p> | |||||
<div class="form-group"> | |||||
<select name="subject" class="form-control"> | <select name="subject" class="form-control"> | ||||
{% if obj.query_options -%} | |||||
{% for option in obj.query_options -%} | |||||
{% if query_options -%} | |||||
{% for option in query_options -%} | |||||
<option value="{{ option }}">{{ option }}</option> | <option value="{{ option }}">{{ option }}</option> | ||||
{%- endfor %} | {%- endfor %} | ||||
{% else %} | {% else %} | ||||
<option value="General">General</option> | <option value="General">General</option> | ||||
{% endif %} | {% endif %} | ||||
</select> | </select> | ||||
</p> | |||||
<p> | |||||
</div> | |||||
<div class="form-group"> | |||||
<input class="form-control" name="email" type="text" | <input class="form-control" name="email" type="text" | ||||
placeholder="Your Email Address" /> | placeholder="Your Email Address" /> | ||||
</p> | |||||
<p> | |||||
</div> | |||||
<div class="form-group"> | |||||
<textarea rows="10" name="message" class="form-control"></textarea> | <textarea rows="10" name="message" class="form-control"></textarea> | ||||
</p> | |||||
<p> | |||||
</div> | |||||
<div class="form-group"> | |||||
<button class="btn btn-primary btn-send">Send</button> | <button class="btn btn-primary btn-send">Send</button> | ||||
</p> | |||||
</div> | |||||
</div> | </div> | ||||
{% if obj.doc.address %} | |||||
<div class="col-md-3 col-md-offset-1 alert alert-warning" style="margin-top: 20px;" itemscope itemtype="http://schema.org/PostalAddress"> | |||||
<h4><i class="icon-map-marker"></i> {{ obj.address.address_title }}</h4> | |||||
{% if obj.address.address_line1 %} | |||||
<span itemprop="streetAddress">{{ obj.address.address_line1 }}</span><br> | |||||
{% if address %} | |||||
<div class="col-md-3 col-md-offset-1 alert alert-warning" | |||||
itemscope itemtype="http://schema.org/PostalAddress"> | |||||
<h4><i class="icon-map-marker"></i> {{ address.address_title }}</h4> | |||||
{% if address.address_line1 %} | |||||
<span itemprop="streetAddress">{{ address.address_line1 }}</span><br> | |||||
{% endif %} | {% endif %} | ||||
{% if obj.address.address_line2 %} | |||||
<span itemprop="streetAddress">{{ obj.address.address_line2 }}</span><br> | |||||
{% if address.address_line2 %} | |||||
<span itemprop="streetAddress">{{ address.address_line2 }}</span><br> | |||||
{% endif %} | {% endif %} | ||||
{% if obj.address.city %} | |||||
<span itemprop="addressLocality">{{ obj.address.city }}</span><br> | |||||
{% if address.city %} | |||||
<span itemprop="addressLocality">{{ address.city }}</span><br> | |||||
{% endif %} | {% endif %} | ||||
{% if obj.address.state %} | |||||
<span itemprop="addressRegion">{{ obj.address.state }}</span><br> | |||||
{% if address.state %} | |||||
<span itemprop="addressRegion">{{ address.state }}</span><br> | |||||
{% endif %} | {% endif %} | ||||
{% if obj.address.pincode %} | |||||
<span itemprop="postalCode">{{ obj.address.pincode }}</span><br> | |||||
{% if address.pincode %} | |||||
<span itemprop="postalCode">{{ address.pincode }}</span><br> | |||||
{% endif %} | {% endif %} | ||||
{% if obj.address.country %} | |||||
<span itemprop="addressCountry">{{ obj.address.country }}</span><br> | |||||
{% if address.country %} | |||||
<span itemprop="addressCountry">{{ address.country }}</span><br> | |||||
{% endif %} | {% endif %} | ||||
</div> | </div> | ||||
{% endif %} | {% endif %} | ||||
</div> | </div> | ||||
{{ obj.doc.introduction }} | |||||
{{ introduction }} | |||||
</div> | </div> | ||||
{% endblock %} | {% endblock %} |
@@ -1,6 +1,16 @@ | |||||
import webnotes | import webnotes | ||||
def get_context(): | def get_context(): | ||||
bean = webnotes.bean("Contact Us Settings", "Contact Us Settings") | |||||
query_options = filter(None, bean.doc.query_options.replace(",", "\n").split()) if \ | |||||
bean.doc.query_options else ["Sales", "Support", "General"] | |||||
address = webnotes.bean("Address", bean.doc.address).doc if bean.doc.address else None | |||||
return { | return { | ||||
"obj": webnotes.bean("Contact Us Settings", "Contact Us Settings").get_controller() | |||||
} | |||||
"query_options": query_options, | |||||
"address": address, | |||||
"heading": bean.doc.heading, | |||||
"introduction": bean.doc.introduction | |||||
} |
@@ -1,11 +0,0 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# License: GNU General Public License v3. See license.txt | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import webnotes | |||||
class DocType: | |||||
def __init__(self, d, dl): | |||||
self.doc, self.doclist = d, dl |
@@ -1,36 +0,0 @@ | |||||
[ | |||||
{ | |||||
"creation": "2013-06-20 16:00:18", | |||||
"docstatus": 0, | |||||
"modified": "2013-08-09 14:47:12", | |||||
"modified_by": "Administrator", | |||||
"owner": "Administrator" | |||||
}, | |||||
{ | |||||
"doctype": "DocType", | |||||
"istable": 1, | |||||
"module": "Website", | |||||
"name": "__common__" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "selling_price_list", | |||||
"fieldtype": "Link", | |||||
"in_list_view": 1, | |||||
"label": "Price List", | |||||
"name": "__common__", | |||||
"options": "Price List", | |||||
"parent": "Shopping Cart Price List", | |||||
"parentfield": "fields", | |||||
"parenttype": "DocType", | |||||
"permlevel": 0, | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"doctype": "DocType", | |||||
"name": "Shopping Cart Price List" | |||||
}, | |||||
{ | |||||
"doctype": "DocField" | |||||
} | |||||
] |
@@ -1,10 +0,0 @@ | |||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
// License: GNU General Public License v3. See license.txt | |||||
$.extend(cur_frm.cscript, { | |||||
onload: function() { | |||||
if(cur_frm.doc.__quotation_series) { | |||||
cur_frm.fields_dict.quotation_series.df.options = cur_frm.doc.__quotation_series; | |||||
} | |||||
} | |||||
}); |
@@ -1,149 +0,0 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# License: GNU General Public License v3. See license.txt | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import webnotes | |||||
from webnotes import _, msgprint | |||||
from webnotes.utils import comma_and | |||||
from webnotes.model.controller import DocListController | |||||
class ShoppingCartSetupError(webnotes.ValidationError): pass | |||||
class DocType(DocListController): | |||||
def onload(self): | |||||
self.doc.fields["__quotation_series"] = webnotes.get_doctype("Quotation").get_options("naming_series") | |||||
def validate(self): | |||||
if self.doc.enabled: | |||||
self.validate_price_lists() | |||||
self.validate_tax_masters() | |||||
self.validate_exchange_rates_exist() | |||||
def on_update(self): | |||||
webnotes.conn.set_default("shopping_cart_enabled", self.doc.fields.get("enabled") or 0) | |||||
webnotes.conn.set_default("shopping_cart_quotation_series", self.doc.fields.get("quotation_series")) | |||||
def validate_overlapping_territories(self, parentfield, fieldname): | |||||
# for displaying message | |||||
doctype = self.meta.get_field(parentfield).options | |||||
# specify atleast one entry in the table | |||||
self.validate_table_has_rows(parentfield, raise_exception=ShoppingCartSetupError) | |||||
territory_name_map = self.get_territory_name_map(parentfield, fieldname) | |||||
for territory, names in territory_name_map.items(): | |||||
if len(names) > 1: | |||||
msgprint(_("Error for") + " " + _(doctype) + ": " + comma_and(names) + | |||||
" " + _("have a common territory") + ": " + territory, | |||||
raise_exception=ShoppingCartSetupError) | |||||
return territory_name_map | |||||
def validate_price_lists(self): | |||||
territory_name_map = self.validate_overlapping_territories("price_lists", | |||||
"selling_price_list") | |||||
# validate that a Shopping Cart Price List exists for the root territory | |||||
# as a catch all! | |||||
from setup.utils import get_root_of | |||||
root_territory = get_root_of("Territory") | |||||
if root_territory not in territory_name_map.keys(): | |||||
msgprint(_("Please specify a Price List which is valid for Territory") + | |||||
": " + root_territory, raise_exception=ShoppingCartSetupError) | |||||
def validate_tax_masters(self): | |||||
self.validate_overlapping_territories("sales_taxes_and_charges_masters", | |||||
"sales_taxes_and_charges_master") | |||||
def get_territory_name_map(self, parentfield, fieldname): | |||||
territory_name_map = {} | |||||
# entries in table | |||||
names = [doc.fields.get(fieldname) for doc in self.doclist.get({"parentfield": parentfield})] | |||||
if names: | |||||
# for condition in territory check | |||||
parenttype = self.meta.get_field(fieldname, parentfield=parentfield).options | |||||
# to validate territory overlap | |||||
# make a map of territory: [list of names] | |||||
# if list against each territory has more than one element, raise exception | |||||
territory_name = webnotes.conn.sql("""select `territory`, `parent` | |||||
from `tabFor Territory` | |||||
where `parenttype`=%s and `parent` in (%s)""" % | |||||
("%s", ", ".join(["%s"]*len(names))), tuple([parenttype] + names)) | |||||
for territory, name in territory_name: | |||||
territory_name_map.setdefault(territory, []).append(name) | |||||
if len(territory_name_map[territory]) > 1: | |||||
territory_name_map[territory].sort(key=lambda val: names.index(val)) | |||||
return territory_name_map | |||||
def validate_exchange_rates_exist(self): | |||||
"""check if exchange rates exist for all Price List currencies (to company's currency)""" | |||||
company_currency = webnotes.conn.get_value("Company", self.doc.company, "default_currency") | |||||
if not company_currency: | |||||
msgprint(_("Please specify currency in Company") + ": " + self.doc.company, | |||||
raise_exception=ShoppingCartSetupError) | |||||
price_list_currency_map = webnotes.conn.get_values("Price List", | |||||
[d.selling_price_list for d in self.doclist.get({"parentfield": "price_lists"})], | |||||
"currency") | |||||
expected_to_exist = [currency + "-" + company_currency | |||||
for currency in price_list_currency_map.values() | |||||
if currency != company_currency] | |||||
if expected_to_exist: | |||||
exists = webnotes.conn.sql_list("""select name from `tabCurrency Exchange` | |||||
where name in (%s)""" % (", ".join(["%s"]*len(expected_to_exist)),), | |||||
tuple(expected_to_exist)) | |||||
missing = list(set(expected_to_exist).difference(exists)) | |||||
if missing: | |||||
msgprint(_("Missing Currency Exchange Rates for" + ": " + comma_and(missing)), | |||||
raise_exception=ShoppingCartSetupError) | |||||
def get_name_from_territory(self, territory, parentfield, fieldname): | |||||
name = None | |||||
territory_name_map = self.get_territory_name_map(parentfield, fieldname) | |||||
if territory_name_map.get(territory): | |||||
name = territory_name_map.get(territory) | |||||
else: | |||||
territory_ancestry = self.get_territory_ancestry(territory) | |||||
for ancestor in territory_ancestry: | |||||
if territory_name_map.get(ancestor): | |||||
name = territory_name_map.get(ancestor) | |||||
break | |||||
return name | |||||
def get_price_list(self, billing_territory): | |||||
price_list = self.get_name_from_territory(billing_territory, "price_lists", "selling_price_list") | |||||
return price_list and price_list[0] or None | |||||
def get_tax_master(self, billing_territory): | |||||
tax_master = self.get_name_from_territory(billing_territory, "sales_taxes_and_charges_masters", | |||||
"sales_taxes_and_charges_master") | |||||
return tax_master and tax_master[0] or None | |||||
def get_shipping_rules(self, shipping_territory): | |||||
return self.get_name_from_territory(shipping_territory, "shipping_rules", "shipping_rule") | |||||
def get_territory_ancestry(self, territory): | |||||
from setup.utils import get_ancestors_of | |||||
if not hasattr(self, "_territory_ancestry"): | |||||
self._territory_ancestry = {} | |||||
if not self._territory_ancestry.get(territory): | |||||
self._territory_ancestry[territory] = get_ancestors_of("Territory", territory) | |||||
return self._territory_ancestry[territory] |
@@ -1,125 +0,0 @@ | |||||
[ | |||||
{ | |||||
"creation": "2013-06-19 15:57:32", | |||||
"docstatus": 0, | |||||
"modified": "2013-07-15 17:33:05", | |||||
"modified_by": "Administrator", | |||||
"owner": "Administrator" | |||||
}, | |||||
{ | |||||
"description": "Default settings for Shopping Cart", | |||||
"doctype": "DocType", | |||||
"icon": "icon-shopping-cart", | |||||
"issingle": 1, | |||||
"module": "Website", | |||||
"name": "__common__" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"name": "__common__", | |||||
"parent": "Shopping Cart Settings", | |||||
"parentfield": "fields", | |||||
"parenttype": "DocType", | |||||
"permlevel": 0 | |||||
}, | |||||
{ | |||||
"create": 1, | |||||
"doctype": "DocPerm", | |||||
"name": "__common__", | |||||
"parent": "Shopping Cart Settings", | |||||
"parentfield": "permissions", | |||||
"parenttype": "DocType", | |||||
"permlevel": 0, | |||||
"read": 1, | |||||
"role": "Website Manager", | |||||
"write": 1 | |||||
}, | |||||
{ | |||||
"doctype": "DocType", | |||||
"name": "Shopping Cart Settings" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "enabled", | |||||
"fieldtype": "Check", | |||||
"label": "Enable Shopping Cart" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "section_break_2", | |||||
"fieldtype": "Section Break" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "company", | |||||
"fieldtype": "Link", | |||||
"label": "Company", | |||||
"options": "Company", | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "default_territory", | |||||
"fieldtype": "Link", | |||||
"label": "Default Territory", | |||||
"options": "Territory", | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "column_break_4", | |||||
"fieldtype": "Column Break" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "default_customer_group", | |||||
"fieldtype": "Link", | |||||
"label": "Default Customer Group", | |||||
"options": "Customer Group", | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "quotation_series", | |||||
"fieldtype": "Select", | |||||
"label": "Quotation Series", | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "section_break_6", | |||||
"fieldtype": "Section Break" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "price_lists", | |||||
"fieldtype": "Table", | |||||
"label": "Shopping Cart Price Lists", | |||||
"options": "Shopping Cart Price List", | |||||
"reqd": 0 | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "shipping_rules", | |||||
"fieldtype": "Table", | |||||
"label": "Shopping Cart Shipping Rules", | |||||
"options": "Shopping Cart Shipping Rule", | |||||
"reqd": 0 | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "column_break_10", | |||||
"fieldtype": "Column Break" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "sales_taxes_and_charges_masters", | |||||
"fieldtype": "Table", | |||||
"label": "Shopping Cart Taxes and Charges Masters", | |||||
"options": "Shopping Cart Taxes and Charges Master", | |||||
"reqd": 0 | |||||
}, | |||||
{ | |||||
"doctype": "DocPerm" | |||||
} | |||||
] |
@@ -1,81 +0,0 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# License: GNU General Public License v3. See license.txt | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import webnotes | |||||
import unittest | |||||
from website.doctype.shopping_cart_settings.shopping_cart_settings import ShoppingCartSetupError | |||||
class TestShoppingCartSettings(unittest.TestCase): | |||||
def setUp(self): | |||||
webnotes.conn.sql("""delete from `tabSingles` where doctype="Shipping Cart Settings" """) | |||||
webnotes.conn.sql("""delete from `tabShopping Cart Price List`""") | |||||
webnotes.conn.sql("""delete from `tabShopping Cart Taxes and Charges Master`""") | |||||
webnotes.conn.sql("""delete from `tabShopping Cart Shipping Rule`""") | |||||
def get_cart_settings(self): | |||||
return webnotes.bean({"doctype": "Shopping Cart Settings", | |||||
"company": "_Test Company"}) | |||||
def test_price_list_territory_overlap(self): | |||||
cart_settings = self.get_cart_settings() | |||||
def _add_price_list(price_list): | |||||
cart_settings.doclist.append({ | |||||
"doctype": "Shopping Cart Price List", | |||||
"parentfield": "price_lists", | |||||
"selling_price_list": price_list | |||||
}) | |||||
for price_list in ("_Test Price List Rest of the World", "_Test Price List India", | |||||
"_Test Price List"): | |||||
_add_price_list(price_list) | |||||
controller = cart_settings.make_controller() | |||||
controller.validate_overlapping_territories("price_lists", "selling_price_list") | |||||
_add_price_list("_Test Price List 2") | |||||
controller = cart_settings.make_controller() | |||||
self.assertRaises(ShoppingCartSetupError, controller.validate_overlapping_territories, | |||||
"price_lists", "selling_price_list") | |||||
return cart_settings | |||||
def test_taxes_territory_overlap(self): | |||||
cart_settings = self.get_cart_settings() | |||||
def _add_tax_master(tax_master): | |||||
cart_settings.doclist.append({ | |||||
"doctype": "Shopping Cart Taxes and Charges Master", | |||||
"parentfield": "sales_taxes_and_charges_masters", | |||||
"sales_taxes_and_charges_master": tax_master | |||||
}) | |||||
for tax_master in ("_Test Sales Taxes and Charges Master", "_Test India Tax Master"): | |||||
_add_tax_master(tax_master) | |||||
controller = cart_settings.make_controller() | |||||
controller.validate_overlapping_territories("sales_taxes_and_charges_masters", | |||||
"sales_taxes_and_charges_master") | |||||
_add_tax_master("_Test Sales Taxes and Charges Master 2") | |||||
controller = cart_settings.make_controller() | |||||
self.assertRaises(ShoppingCartSetupError, controller.validate_overlapping_territories, | |||||
"sales_taxes_and_charges_masters", "sales_taxes_and_charges_master") | |||||
def test_exchange_rate_exists(self): | |||||
webnotes.conn.sql("""delete from `tabCurrency Exchange`""") | |||||
cart_settings = self.test_price_list_territory_overlap() | |||||
controller = cart_settings.make_controller() | |||||
self.assertRaises(ShoppingCartSetupError, controller.validate_exchange_rates_exist) | |||||
from setup.doctype.currency_exchange.test_currency_exchange import test_records as \ | |||||
currency_exchange_records | |||||
webnotes.bean(currency_exchange_records[0]).insert() | |||||
controller.validate_exchange_rates_exist() | |||||
@@ -1,11 +0,0 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# License: GNU General Public License v3. See license.txt | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import webnotes | |||||
class DocType: | |||||
def __init__(self, d, dl): | |||||
self.doc, self.doclist = d, dl |
@@ -1,36 +0,0 @@ | |||||
[ | |||||
{ | |||||
"creation": "2013-07-03 13:15:34", | |||||
"docstatus": 0, | |||||
"modified": "2013-07-10 14:54:23", | |||||
"modified_by": "Administrator", | |||||
"owner": "Administrator" | |||||
}, | |||||
{ | |||||
"doctype": "DocType", | |||||
"istable": 1, | |||||
"module": "Website", | |||||
"name": "__common__" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "shipping_rule", | |||||
"fieldtype": "Link", | |||||
"in_list_view": 1, | |||||
"label": "Shipping Rule", | |||||
"name": "__common__", | |||||
"options": "Shipping Rule", | |||||
"parent": "Shopping Cart Shipping Rule", | |||||
"parentfield": "fields", | |||||
"parenttype": "DocType", | |||||
"permlevel": 0, | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"doctype": "DocType", | |||||
"name": "Shopping Cart Shipping Rule" | |||||
}, | |||||
{ | |||||
"doctype": "DocField" | |||||
} | |||||
] |
@@ -1,11 +0,0 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# License: GNU General Public License v3. See license.txt | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import webnotes | |||||
class DocType: | |||||
def __init__(self, d, dl): | |||||
self.doc, self.doclist = d, dl |
@@ -1,36 +0,0 @@ | |||||
[ | |||||
{ | |||||
"creation": "2013-06-20 16:57:03", | |||||
"docstatus": 0, | |||||
"modified": "2013-07-10 14:54:23", | |||||
"modified_by": "Administrator", | |||||
"owner": "Administrator" | |||||
}, | |||||
{ | |||||
"doctype": "DocType", | |||||
"istable": 1, | |||||
"module": "Website", | |||||
"name": "__common__" | |||||
}, | |||||
{ | |||||
"doctype": "DocField", | |||||
"fieldname": "sales_taxes_and_charges_master", | |||||
"fieldtype": "Link", | |||||
"in_list_view": 1, | |||||
"label": "Tax Master", | |||||
"name": "__common__", | |||||
"options": "Sales Taxes and Charges Master", | |||||
"parent": "Shopping Cart Taxes and Charges Master", | |||||
"parentfield": "fields", | |||||
"parenttype": "DocType", | |||||
"permlevel": 0, | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"doctype": "DocType", | |||||
"name": "Shopping Cart Taxes and Charges Master" | |||||
}, | |||||
{ | |||||
"doctype": "DocField" | |||||
} | |||||
] |
@@ -64,12 +64,6 @@ wn.module_page["Website"] = [ | |||||
"description":wn._("Setup of fonts and background."), | "description":wn._("Setup of fonts and background."), | ||||
doctype:"Style Settings" | doctype:"Style Settings" | ||||
}, | }, | ||||
{ | |||||
"route":"Form/Shopping Cart Settings", | |||||
"label":wn._("Shopping Cart Settings"), | |||||
"description":wn._("Setup of Shopping Cart."), | |||||
doctype:"Shopping Cart Settings" | |||||
}, | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -1,5 +1,5 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | ||||
# License: GNU General Public License v3. See license.txt | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
@@ -34,7 +34,7 @@ | |||||
</ul> | </ul> | ||||
</div> | </div> | ||||
{% if copyright %}<div class="web-footer-copyright">© {{ copyright }}</div>{% endif %} | {% if copyright %}<div class="web-footer-copyright">© {{ copyright }}</div>{% endif %} | ||||
{% if address %}{{ address }}{% endif %} | |||||
{% if footer_address %}{{ footer_address }}{% endif %} | |||||
{% block extension %}{% endblock %} | {% block extension %}{% endblock %} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -1,4 +1,4 @@ | |||||
{% extends "lib/website/templates/base.html" %} | |||||
{% extends base_template %} | |||||
{% set title="Not Found" %} | {% set title="Not Found" %} | ||||
@@ -0,0 +1 @@ | |||||
from __future__ import unicode_literals |
@@ -1,4 +1,4 @@ | |||||
{% extends "lib/website/templates/base.html" %} | |||||
{% extends base_template %} | |||||
{% set title="Error" %} | {% set title="Error" %} | ||||
@@ -0,0 +1,6 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
no_cache = True |
@@ -1,4 +1,4 @@ | |||||
{% extends "lib/website/templates/base.html" %} | |||||
{% extends base_template %} | |||||
{% set title=webnotes.message_title %} | {% set title=webnotes.message_title %} | ||||
@@ -0,0 +1,6 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
no_cache = True |
@@ -0,0 +1,6 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
no_cache = True |