Merge pull request #1254 from anandpdoshi/4.0.0-shopping-cart-wip

Moved Portal and Shopping Cart to Shopping Cart app, and some minor fixe...
This commit is contained in:
Anand Doshi 2013-12-31 04:14:15 -08:00
commit 2511aa2b14
90 changed files with 35 additions and 3091 deletions

View File

@ -74,5 +74,5 @@ cur_frm.fields_dict['select_print_heading'].get_query = function(doc, cdt, cdn)
cur_frm.fields_dict.user.get_query = function(doc,cdt,cdn) { cur_frm.fields_dict.user.get_query = function(doc,cdt,cdn) {
return{ query:"core.doctype.profile.profile.profile_query"} return{ query:"webnotes.core.doctype.profile.profile.profile_query"}
} }

View File

@ -15,8 +15,3 @@ class DocType(DocListController):
# at least one territory # at least one territory
self.validate_table_has_rows("valid_for_territories") self.validate_table_has_rows("valid_for_territories")
def on_update(self):
cart_settings = webnotes.get_obj("Shopping Cart Settings")
if cint(cart_settings.doc.enabled):
cart_settings.validate_tax_masters()

View File

@ -21,7 +21,6 @@ update_website_context = erpnext.startup.webutils.update_website_context
mail_footer = erpnext.startup.mail_footer mail_footer = erpnext.startup.mail_footer
on_session_creation = erpnext.startup.event_handlers.on_session_creation on_session_creation = erpnext.startup.event_handlers.on_session_creation
on_logout = erpnext.startup.event_handlers.on_logut
# Boot Events # Boot Events
# ------------------------- # -------------------------
@ -37,7 +36,6 @@ bean_event = *:on_trash:webnotes.core.doctype.notification_count.notification_co
bean_event = Stock Entry:on_submit:erpnext.stock.doctype.material_request.material_request.update_completed_qty bean_event = Stock Entry:on_submit:erpnext.stock.doctype.material_request.material_request.update_completed_qty
bean_event = Stock Entry:on_cancel:erpnext.stock.doctype.material_request.material_request.update_completed_qty bean_event = Stock Entry:on_cancel:erpnext.stock.doctype.material_request.material_request.update_completed_qty
standard_queries = Warehouse:erpnext.stock.utils.get_warehouse_list
standard_queries = Customer:erpnext.selling.utils.get_customer_list standard_queries = Customer:erpnext.selling.utils.get_customer_list
# Schedulers # Schedulers

View File

@ -5,7 +5,7 @@ wn.provide("erpnext.hr");
erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({ erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({
setup: function() { setup: function() {
this.frm.fields_dict.user_id.get_query = function(doc,cdt,cdn) { this.frm.fields_dict.user_id.get_query = function(doc,cdt,cdn) {
return { query:"core.doctype.profile.profile.profile_query"} } return { query:"webnotes.core.doctype.profile.profile.profile_query"} }
this.frm.fields_dict.reports_to.get_query = function(doc,cdt,cdn) { this.frm.fields_dict.reports_to.get_query = function(doc,cdt,cdn) {
return{ query: "erpnext.controllers.queries.employee_query"} } return{ query: "erpnext.controllers.queries.employee_query"} }
}, },

View File

@ -1,14 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import webnotes
def execute():
webnotes.reload_doc("selling", "doctype", "shopping_cart_settings")
# create two default territories, one for home country and one named Rest of the World
from erpnext.setup.page.setup_wizard.setup_wizard import create_territories
create_territories()
webnotes.conn.set_value("Shopping Cart Settings", None, "default_territory", "Rest of the World")

View File

@ -161,7 +161,6 @@ patch_list = [
"execute:webnotes.delete_doc('Report', 'Sales Orders Pending To Be Delivered')", "execute:webnotes.delete_doc('Report', 'Sales Orders Pending To Be Delivered')",
"patches.june_2013.p05_remove_unused_doctypes", "patches.june_2013.p05_remove_unused_doctypes",
"patches.june_2013.p06_drop_unused_tables", "patches.june_2013.p06_drop_unused_tables",
"patches.june_2013.p08_shopping_cart_settings",
"patches.june_2013.p09_update_global_defaults", "patches.june_2013.p09_update_global_defaults",
"patches.june_2013.p10_lead_address", "patches.june_2013.p10_lead_address",
"patches.july_2013.p01_remove_doctype_mappers", "patches.july_2013.p01_remove_doctype_mappers",

View File

@ -8,7 +8,7 @@ cur_frm.cscript.account_head = function(doc, cdt, cdn) {
} else if(d.account_head && d.charge_type!=="Actual") { } else if(d.account_head && d.charge_type!=="Actual") {
wn.call({ wn.call({
type:"GET", type:"GET",
method: "controllers.accounts_controller.get_tax_rate", method: "erpnext.controllers.accounts_controller.get_tax_rate",
args: {"account_head":d.account_head}, args: {"account_head":d.account_head},
callback: function(r) { callback: function(r) {
wn.model.set_value(cdt, cdn, "rate", r.message || 0); wn.model.set_value(cdt, cdn, "rate", r.message || 0);

View File

@ -5,7 +5,7 @@
wn.provide("erpnext.queries"); wn.provide("erpnext.queries");
$.extend(erpnext.queries, { $.extend(erpnext.queries, {
profile: function() { profile: function() {
return { query: "core.doctype.profile.profile.profile_query" }; return { query: "webnotes.core.doctype.profile.profile.profile_query" };
}, },
lead: function() { lead: function() {

View File

@ -1,14 +1,14 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt // License: GNU General Public License v3. See license.txt
if(!window.erpnext) erpnext = {}; if(!window.erpnext) window.erpnext = {};
// Add / update a new Lead / Communication // Add / update a new Lead / Communication
// subject, sender, description // subject, sender, description
wn.send_message = function(opts, btn) { wn.send_message = function(opts, btn) {
return wn.call({ return wn.call({
type: "POST", type: "POST",
method: "erpnext.portal.utils.send_message", method: "erpnext.templates.utils.send_message",
btn: btn, btn: btn,
args: opts, args: opts,
callback: opts.callback callback: opts.callback
@ -17,70 +17,3 @@ wn.send_message = function(opts, btn) {
// for backward compatibility // for backward compatibility
erpnext.send_message = wn.send_message; erpnext.send_message = wn.send_message;
// Setup the user tools
//
$(document).ready(function() {
// update login
erpnext.cart.set_cart_count();
// update profile
if(full_name) {
$('.navbar li[data-label="Profile"] a')
.html('<i class="icon-fixed-width icon-user"></i> ' + full_name);
}
});
// shopping cart
if(!erpnext.cart) erpnext.cart = {};
$.extend(erpnext.cart, {
update_cart: function(opts) {
if(!full_name) {
if(localStorage) {
localStorage.setItem("last_visited", window.location.href.split("/").slice(-1)[0]);
localStorage.setItem("pending_add_to_cart", opts.item_code);
}
window.location.href = "login";
} else {
return wn.call({
type: "POST",
method: "erpnext.selling.utils.cart.update_cart",
args: {
item_code: opts.item_code,
qty: opts.qty,
with_doclist: opts.with_doclist
},
btn: opts.btn,
callback: function(r) {
if(opts.callback)
opts.callback(r);
erpnext.cart.set_cart_count();
}
});
}
},
set_cart_count: function() {
var cart_count = getCookie("cart_count");
var $cart = $("#website-post-login").find('[data-label="Cart"]');
var $badge = $cart.find(".badge");
var $cog = $("#website-post-login").find(".dropdown-toggle");
var $cog_count = $cog.find(".cart-count");
if(cart_count) {
if($badge.length === 0) {
var $badge = $('<span class="badge pull-right"></span>').appendTo($cart.find("a"));
}
$badge.html(cart_count);
if($cog_count.length === 0) {
var $cog_count = $('<sup class="cart-count"></span>').insertAfter($cog.find(".icon-cog"));
}
$cog_count.html(cart_count);
} else {
$badge.remove();
$cog_count.remove();
}
}
});

View File

@ -14,12 +14,12 @@ erpnext.LeadController = wn.ui.form.Controller.extend({
onload: function() { onload: function() {
if(cur_frm.fields_dict.lead_owner.df.options.match(/^Profile/)) { if(cur_frm.fields_dict.lead_owner.df.options.match(/^Profile/)) {
cur_frm.fields_dict.lead_owner.get_query = function(doc,cdt,cdn) { cur_frm.fields_dict.lead_owner.get_query = function(doc,cdt,cdn) {
return { query:"core.doctype.profile.profile.profile_query" } } return { query:"webnotes.core.doctype.profile.profile.profile_query" } }
} }
if(cur_frm.fields_dict.contact_by.df.options.match(/^Profile/)) { if(cur_frm.fields_dict.contact_by.df.options.match(/^Profile/)) {
cur_frm.fields_dict.contact_by.get_query = function(doc,cdt,cdn) { cur_frm.fields_dict.contact_by.get_query = function(doc,cdt,cdn) {
return { query:"core.doctype.profile.profile.profile_query" } } return { query:"webnotes.core.doctype.profile.profile.profile_query" } }
} }
if(in_list(user_roles,'System Manager')) { if(in_list(user_roles,'System Manager')) {

View File

@ -1,5 +0,0 @@
{% extends "templates/sale.html" %}
{% block status -%}
{% if doc.status %}{{ doc.status }}{% endif %}
{%- endblock %}

View File

@ -1,32 +0,0 @@
# 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 webnotes
from webnotes import _
no_cache = True
def get_context():
from erpnext.templates.utils import get_transaction_context
context = get_transaction_context("Sales Order", webnotes.form_dict.name)
modify_status(context.get("doc"))
context.update({
"parent_link": "orders",
"parent_title": "My Orders"
})
return context
def modify_status(doc):
doc.status = []
if 0 < doc.per_billed < 100:
doc.status.append(("label-warning", "icon-ok", _("Partially Billed")))
elif doc.per_billed == 100:
doc.status.append(("label-success", "icon-ok", _("Billed")))
if 0 < doc.per_delivered < 100:
doc.status.append(("label-warning", "icon-truck", _("Partially Delivered")))
elif doc.per_delivered == 100:
doc.status.append(("label-success", "icon-truck", _("Delivered")))
doc.status = " " + " ".join(('<span class="label %s"><i class="icon-fixed-width %s"></i> %s</span>' % s
for s in doc.status))

View File

@ -1 +0,0 @@
{% extends "templates/sales_transactions.html" %}

View File

@ -1,30 +0,0 @@
# 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 webnotes
no_cache = True
def get_context():
from erpnext.templates.utils import get_currency_context
context = get_currency_context()
context.update({
"title": "My Orders",
"method": "selling.doctype.sales_order.templates.pages.orders.get_orders",
"icon": "icon-list",
"empty_list_message": "No Orders Yet",
"page": "order",
})
return context
@webnotes.whitelist()
def get_orders(start=0):
from erpnext.templates.utils import get_transaction_list
from erpnext.selling.doctype.sales_order.templates.pages.order import modify_status
orders = get_transaction_list("Sales Order", start, ["per_billed", "per_delivered"])
for d in orders:
modify_status(d)
return orders

View File

@ -1,11 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# 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

View File

@ -1,36 +0,0 @@
[
{
"creation": "2013-06-20 16:00:18",
"docstatus": 0,
"modified": "2013-12-20 19:21:47",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "DocType",
"istable": 1,
"module": "Selling",
"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"
}
]

View File

@ -1,10 +0,0 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// 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;
}
}
});

View File

@ -1,154 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# 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 erpnext.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 `tabApplicable 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")
# check if all price lists have a currency
for price_list, currency in price_list_currency_map.items():
if not currency:
webnotes.throw("%s: %s" % (_("Currency is missing for Price List"), price_list))
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 erpnext.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]

View File

@ -1,129 +0,0 @@
[
{
"creation": "2013-06-19 15:57:32",
"docstatus": 0,
"modified": "2013-12-20 19:21:47",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"description": "Default settings for Shopping Cart",
"doctype": "DocType",
"icon": "icon-shopping-cart",
"issingle": 1,
"module": "Selling",
"name": "__common__"
},
{
"doctype": "DocField",
"name": "__common__",
"parent": "Shopping Cart Settings",
"parentfield": "fields",
"parenttype": "DocType",
"permlevel": 0
},
{
"create": 1,
"doctype": "DocPerm",
"email": 1,
"name": "__common__",
"parent": "Shopping Cart Settings",
"parentfield": "permissions",
"parenttype": "DocType",
"permlevel": 0,
"print": 1,
"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
},
{
"description": "<a href=\"#Sales Browser/Territory\">Add / Edit</a>",
"doctype": "DocField",
"fieldname": "default_territory",
"fieldtype": "Link",
"label": "Default Territory",
"options": "Territory",
"reqd": 1
},
{
"doctype": "DocField",
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"description": "<a href=\"#Sales Browser/Customer Group\">Add / Edit</a>",
"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"
}
]

View File

@ -1,81 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# 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 erpnext.selling.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 erpnext.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()

View File

@ -1,11 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# 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

View File

@ -1,36 +0,0 @@
[
{
"creation": "2013-07-03 13:15:34",
"docstatus": 0,
"modified": "2013-12-20 19:21:47",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "DocType",
"istable": 1,
"module": "Selling",
"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"
}
]

View File

@ -1,11 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# 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

View File

@ -1,36 +0,0 @@
[
{
"creation": "2013-06-20 16:57:03",
"docstatus": 0,
"modified": "2013-12-20 19:21:47",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"doctype": "DocType",
"istable": 1,
"module": "Selling",
"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"
}
]

View File

@ -65,12 +65,6 @@ wn.module_page["Selling"] = [
"doctype":"Selling Settings", "doctype":"Selling Settings",
"description": wn._("Settings for Selling Module") "description": wn._("Settings for Selling Module")
}, },
{
"route":"Form/Shopping Cart Settings",
"label":wn._("Shopping Cart Settings"),
"description":wn._("Setup of Shopping Cart."),
doctype:"Shopping Cart Settings"
},
{ {
label: wn._("Sales Taxes and Charges Master"), label: wn._("Sales Taxes and Charges Master"),
description: wn._("Sales taxes template."), description: wn._("Sales taxes template."),

View File

@ -1,462 +0,0 @@
# 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 webnotes, json
from webnotes import msgprint, _
import webnotes.defaults
from webnotes.utils import flt, get_fullname, fmt_money, cstr
class WebsitePriceListMissingError(webnotes.ValidationError): pass
def set_cart_count(quotation=None):
if not quotation:
quotation = _get_cart_quotation()
cart_count = cstr(len(quotation.doclist.get({"parentfield": "quotation_details"})))
webnotes._response.set_cookie("cart_count", cart_count)
@webnotes.whitelist()
def get_cart_quotation(doclist=None):
party = get_lead_or_customer()
if not doclist:
quotation = _get_cart_quotation(party)
doclist = quotation.doclist
set_cart_count(quotation)
return {
"doclist": decorate_quotation_doclist(doclist),
"addresses": [{"name": address.name, "display": address.display}
for address in get_address_docs(party)],
"shipping_rules": get_applicable_shipping_rules(party)
}
@webnotes.whitelist()
def place_order():
quotation = _get_cart_quotation()
controller = quotation.make_controller()
for fieldname in ["customer_address", "shipping_address_name"]:
if not quotation.doc.fields.get(fieldname):
msgprint(_("Please select a") + " " + _(controller.meta.get_label(fieldname)), raise_exception=True)
quotation.ignore_permissions = True
quotation.submit()
from erpnext.selling.doctype.quotation.quotation import _make_sales_order
sales_order = webnotes.bean(_make_sales_order(quotation.doc.name, ignore_permissions=True))
sales_order.ignore_permissions = True
sales_order.insert()
sales_order.submit()
webnotes._response.set_cookie("cart_count", "")
return sales_order.doc.name
@webnotes.whitelist()
def update_cart(item_code, qty, with_doclist=0):
quotation = _get_cart_quotation()
qty = flt(qty)
if qty == 0:
quotation.set_doclist(quotation.doclist.get({"item_code": ["!=", item_code]}))
if not quotation.doclist.get({"parentfield": "quotation_details"}) and \
not quotation.doc.fields.get("__islocal"):
quotation.__delete = True
else:
quotation_items = quotation.doclist.get({"item_code": item_code})
if not quotation_items:
quotation.doclist.append({
"doctype": "Quotation Item",
"parentfield": "quotation_details",
"item_code": item_code,
"qty": qty
})
else:
quotation_items[0].qty = qty
apply_cart_settings(quotation=quotation)
if hasattr(quotation, "__delete"):
webnotes.delete_doc("Quotation", quotation.doc.name, ignore_permissions=True)
quotation = _get_cart_quotation()
else:
quotation.ignore_permissions = True
quotation.save()
set_cart_count(quotation)
if with_doclist:
return get_cart_quotation(quotation.doclist)
else:
return quotation.doc.name
@webnotes.whitelist()
def update_cart_address(address_fieldname, address_name):
from erpnext.utilities.transaction_base import get_address_display
quotation = _get_cart_quotation()
address_display = get_address_display(webnotes.doc("Address", address_name).fields)
if address_fieldname == "shipping_address_name":
quotation.doc.shipping_address_name = address_name
quotation.doc.shipping_address = address_display
if not quotation.doc.customer_address:
address_fieldname == "customer_address"
if address_fieldname == "customer_address":
quotation.doc.customer_address = address_name
quotation.doc.address_display = address_display
apply_cart_settings(quotation=quotation)
quotation.ignore_permissions = True
quotation.save()
return get_cart_quotation(quotation.doclist)
@webnotes.whitelist()
def get_addresses():
return [d.fields for d in get_address_docs()]
@webnotes.whitelist()
def save_address(fields, address_fieldname=None):
party = get_lead_or_customer()
fields = json.loads(fields)
if fields.get("name"):
bean = webnotes.bean("Address", fields.get("name"))
else:
bean = webnotes.bean({"doctype": "Address", "__islocal": 1})
bean.doc.fields.update(fields)
party_fieldname = party.doctype.lower()
bean.doc.fields.update({
party_fieldname: party.name,
(party_fieldname + "_name"): party.fields[party_fieldname + "_name"]
})
bean.ignore_permissions = True
bean.save()
if address_fieldname:
update_cart_address(address_fieldname, bean.doc.name)
return bean.doc.name
def get_address_docs(party=None):
from webnotes.model.doclist import objectify
from erpnext.utilities.transaction_base import get_address_display
if not party:
party = get_lead_or_customer()
address_docs = objectify(webnotes.conn.sql("""select * from `tabAddress`
where `%s`=%s order by name""" % (party.doctype.lower(), "%s"), party.name,
as_dict=True, update={"doctype": "Address"}))
for address in address_docs:
address.display = get_address_display(address.fields)
address.display = (address.display).replace("\n", "<br>\n")
return address_docs
def get_lead_or_customer():
customer = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user}, "customer")
if customer:
return webnotes.doc("Customer", customer)
lead = webnotes.conn.get_value("Lead", {"email_id": webnotes.session.user})
if lead:
return webnotes.doc("Lead", lead)
else:
lead_bean = webnotes.bean({
"doctype": "Lead",
"email_id": webnotes.session.user,
"lead_name": get_fullname(webnotes.session.user),
"territory": guess_territory(),
"status": "Open" # TODO: set something better???
})
if webnotes.session.user != "Guest":
lead_bean.ignore_permissions = True
lead_bean.insert()
return lead_bean.doc
def guess_territory():
territory = None
geoip_country = webnotes.session.get("session_country")
if geoip_country:
territory = webnotes.conn.get_value("Territory", geoip_country)
return territory or \
webnotes.conn.get_value("Shopping Cart Settings", None, "territory") or \
"All Territories"
def decorate_quotation_doclist(doclist):
for d in doclist:
if d.item_code:
d.fields.update(webnotes.conn.get_value("Item", d.item_code,
["website_image", "description", "page_name"], as_dict=True))
d.formatted_rate = fmt_money(d.export_rate, currency=doclist[0].currency)
d.formatted_amount = fmt_money(d.export_amount, currency=doclist[0].currency)
elif d.charge_type:
d.formatted_tax_amount = fmt_money(d.tax_amount / doclist[0].conversion_rate,
currency=doclist[0].currency)
doclist[0].formatted_grand_total_export = fmt_money(doclist[0].grand_total_export,
currency=doclist[0].currency)
return [d.fields for d in doclist]
def _get_cart_quotation(party=None):
if not party:
party = get_lead_or_customer()
quotation = webnotes.conn.get_value("Quotation",
{party.doctype.lower(): party.name, "order_type": "Shopping Cart", "docstatus": 0})
if quotation:
qbean = webnotes.bean("Quotation", quotation)
else:
qbean = webnotes.bean({
"doctype": "Quotation",
"naming_series": webnotes.defaults.get_user_default("shopping_cart_quotation_series") or "QTN-CART-",
"quotation_to": party.doctype,
"company": webnotes.defaults.get_user_default("company"),
"order_type": "Shopping Cart",
"status": "Draft",
"docstatus": 0,
"__islocal": 1,
(party.doctype.lower()): party.name
})
if party.doctype == "Customer":
qbean.doc.contact_person = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user,
"customer": party.name})
qbean.run_method("set_contact_fields")
qbean.run_method("onload_post_render")
apply_cart_settings(party, qbean)
return qbean
def update_party(fullname, company_name=None, mobile_no=None, phone=None):
party = get_lead_or_customer()
if party.doctype == "Lead":
party.company_name = company_name
party.lead_name = fullname
party.mobile_no = mobile_no
party.phone = phone
else:
party.customer_name = company_name or fullname
party.customer_type == "Company" if company_name else "Individual"
contact_name = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user,
"customer": party.name})
contact = webnotes.bean("Contact", contact_name)
contact.doc.first_name = fullname
contact.doc.last_name = None
contact.doc.customer_name = party.customer_name
contact.doc.mobile_no = mobile_no
contact.doc.phone = phone
contact.ignore_permissions = True
contact.save()
party_bean = webnotes.bean(party.fields)
party_bean.ignore_permissions = True
party_bean.save()
qbean = _get_cart_quotation(party)
if not qbean.doc.fields.get("__islocal"):
qbean.doc.customer_name = company_name or fullname
qbean.run_method("set_contact_fields")
qbean.ignore_permissions = True
qbean.save()
def apply_cart_settings(party=None, quotation=None):
if not party:
party = get_lead_or_customer()
if not quotation:
quotation = _get_cart_quotation(party)
cart_settings = webnotes.get_obj("Shopping Cart Settings")
billing_territory = get_address_territory(quotation.doc.customer_address) or \
party.territory or "All Territories"
set_price_list_and_rate(quotation, cart_settings, billing_territory)
quotation.run_method("calculate_taxes_and_totals")
set_taxes(quotation, cart_settings, billing_territory)
_apply_shipping_rule(party, quotation, cart_settings)
def set_price_list_and_rate(quotation, cart_settings, billing_territory):
"""set price list based on billing territory"""
quotation.doc.selling_price_list = cart_settings.get_price_list(billing_territory)
# reset values
quotation.doc.price_list_currency = quotation.doc.currency = \
quotation.doc.plc_conversion_rate = quotation.doc.conversion_rate = None
for item in quotation.doclist.get({"parentfield": "quotation_details"}):
item.ref_rate = item.adj_rate = item.export_rate = item.export_amount = None
# refetch values
quotation.run_method("set_price_list_and_item_details")
# set it in cookies for using in product page
webnotes.local._response.set_cookie("selling_price_list", quotation.doc.selling_price_list)
def set_taxes(quotation, cart_settings, billing_territory):
"""set taxes based on billing territory"""
quotation.doc.charge = cart_settings.get_tax_master(billing_territory)
# clear table
quotation.set_doclist(quotation.doclist.get({"parentfield": ["!=", "other_charges"]}))
# append taxes
controller = quotation.make_controller()
controller.append_taxes_from_master("other_charges", "charge")
quotation.set_doclist(controller.doclist)
@webnotes.whitelist()
def apply_shipping_rule(shipping_rule):
quotation = _get_cart_quotation()
quotation.doc.shipping_rule = shipping_rule
apply_cart_settings(quotation=quotation)
quotation.ignore_permissions = True
quotation.save()
return get_cart_quotation(quotation.doclist)
def _apply_shipping_rule(party=None, quotation=None, cart_settings=None):
shipping_rules = get_shipping_rules(party, quotation, cart_settings)
if not shipping_rules:
return
elif quotation.doc.shipping_rule not in shipping_rules:
quotation.doc.shipping_rule = shipping_rules[0]
quotation.run_method("apply_shipping_rule")
quotation.run_method("calculate_taxes_and_totals")
def get_applicable_shipping_rules(party=None, quotation=None):
shipping_rules = get_shipping_rules(party, quotation)
if shipping_rules:
rule_label_map = webnotes.conn.get_values("Shipping Rule", shipping_rules, "label")
# we need this in sorted order as per the position of the rule in the settings page
return [[rule, rule_label_map.get(rule)] for rule in shipping_rules]
def get_shipping_rules(party=None, quotation=None, cart_settings=None):
if not party:
party = get_lead_or_customer()
if not quotation:
quotation = _get_cart_quotation()
if not cart_settings:
cart_settings = webnotes.get_obj("Shopping Cart Settings")
# set shipping rule based on shipping territory
shipping_territory = get_address_territory(quotation.doc.shipping_address_name) or \
party.territory
shipping_rules = cart_settings.get_shipping_rules(shipping_territory)
return shipping_rules
def get_address_territory(address_name):
"""Tries to match city, state and country of address to existing territory"""
territory = None
if address_name:
address_fields = webnotes.conn.get_value("Address", address_name,
["city", "state", "country"])
for value in address_fields:
territory = webnotes.conn.get_value("Territory", value)
if territory:
break
return territory
import unittest
test_dependencies = ["Item", "Price List", "Contact", "Shopping Cart Settings"]
class TestCart(unittest.TestCase):
def tearDown(self):
return
cart_settings = webnotes.bean("Shopping Cart Settings")
cart_settings.ignore_permissions = True
cart_settings.doc.enabled = 0
cart_settings.save()
def enable_shopping_cart(self):
return
if not webnotes.conn.get_value("Shopping Cart Settings", None, "enabled"):
cart_settings = webnotes.bean("Shopping Cart Settings")
cart_settings.ignore_permissions = True
cart_settings.doc.enabled = 1
cart_settings.save()
def test_get_lead_or_customer(self):
webnotes.session.user = "test@example.com"
party1 = get_lead_or_customer()
party2 = get_lead_or_customer()
self.assertEquals(party1.name, party2.name)
self.assertEquals(party1.doctype, "Lead")
webnotes.session.user = "test_contact_customer@example.com"
party = get_lead_or_customer()
self.assertEquals(party.name, "_Test Customer")
def test_add_to_cart(self):
self.enable_shopping_cart()
webnotes.session.user = "test@example.com"
update_cart("_Test Item", 1)
quotation = _get_cart_quotation()
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
self.assertTrue(quotation_items)
self.assertEquals(quotation_items[0].qty, 1)
return quotation
def test_update_cart(self):
self.test_add_to_cart()
update_cart("_Test Item", 5)
quotation = _get_cart_quotation()
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
self.assertTrue(quotation_items)
self.assertEquals(quotation_items[0].qty, 5)
return quotation
def test_remove_from_cart(self):
quotation0 = self.test_add_to_cart()
update_cart("_Test Item", 0)
quotation = _get_cart_quotation()
self.assertEquals(quotation0.doc.name, quotation.doc.name)
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
self.assertEquals(quotation_items, [])
def test_place_order(self):
quotation = self.test_update_cart()
sales_order_name = place_order()
sales_order = webnotes.bean("Sales Order", sales_order_name)
self.assertEquals(sales_order.doclist.getone({"item_code": "_Test Item"}).prevdoc_docname, quotation.doc.name)

View File

@ -1,128 +0,0 @@
# 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 webnotes
from webnotes.utils import cstr, cint, fmt_money
from webnotes.webutils import delete_page_cache
from erpnext.selling.utils.cart import _get_cart_quotation
@webnotes.whitelist(allow_guest=True)
def get_product_info(item_code):
"""get product price / stock info"""
if not cint(webnotes.conn.get_default("shopping_cart_enabled")):
return {}
cart_quotation = _get_cart_quotation()
price_list = webnotes.local.request.cookies.get("selling_price_list")
warehouse = webnotes.conn.get_value("Item", item_code, "website_warehouse")
if warehouse:
in_stock = webnotes.conn.sql("""select actual_qty from tabBin where
item_code=%s and warehouse=%s""", (item_code, warehouse))
if in_stock:
in_stock = in_stock[0][0] > 0 and 1 or 0
else:
in_stock = -1
price = price_list and webnotes.conn.sql("""select ref_rate, currency from
`tabItem Price` where item_code=%s and price_list=%s""",
(item_code, price_list), as_dict=1) or []
price = price and price[0] or None
qty = 0
if price:
price["formatted_price"] = fmt_money(price["ref_rate"], currency=price["currency"])
price["currency"] = not cint(webnotes.conn.get_default("hide_currency_symbol")) \
and (webnotes.conn.get_value("Currency", price.currency, "symbol") or price.currency) \
or ""
if webnotes.session.user != "Guest":
item = cart_quotation.doclist.get({"item_code": item_code})
if item:
qty = item[0].qty
return {
"price": price,
"stock": in_stock,
"uom": webnotes.conn.get_value("Item", item_code, "stock_uom"),
"qty": qty
}
@webnotes.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 = webnotes.conn.sql(query, {
"search": search,
}, as_dict=1)
return [get_item_for_list_in_html(r) for r in data]
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 = webnotes.conn.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 = webnotes.doc("Item Group", item_group_name)
return webnotes.conn.sql("""select name
from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s
and show_in_website = 1""", item_group.fields)
def get_group_item_count(item_group):
child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(item_group)])
return webnotes.conn.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]
def get_item_for_list_in_html(context):
return webnotes.get_template("templates/includes/product_in_grid.html").render(context)
def scrub_item_for_list(r):
if not r.website_description:
r.website_description = "No description given"
if len(r.website_description.split(" ")) > 24:
r.website_description = " ".join(r.website_description.split(" ")[:24]) + "..."
def get_parent_item_groups(item_group_name):
item_group = webnotes.doc("Item Group", item_group_name)
return webnotes.conn.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(item_group):
for i in get_parent_item_groups(item_group):
if i.page_name:
delete_page_cache(i.page_name)

View File

@ -69,10 +69,10 @@ cur_frm.cscript.transaction = function(doc,cdt,cdn){
cur_frm.fields_dict.system_user.get_query = function(doc,cdt,cdn) { cur_frm.fields_dict.system_user.get_query = function(doc,cdt,cdn) {
return{ query:"core.doctype.profile.profile.profile_query" } } return{ query:"webnotes.core.doctype.profile.profile.profile_query" } }
cur_frm.fields_dict.approving_user.get_query = function(doc,cdt,cdn) { cur_frm.fields_dict.approving_user.get_query = function(doc,cdt,cdn) {
return{ query:"core.doctype.profile.profile.profile_query" } } return{ query:"webnotes.core.doctype.profile.profile.profile_query" } }
cur_frm.fields_dict['approving_role'].get_query = cur_frm.fields_dict['system_role'].get_query; cur_frm.fields_dict['approving_role'].get_query = cur_frm.fields_dict['system_role'].get_query;

View File

@ -6,6 +6,7 @@ import webnotes
from webnotes.utils.nestedset import DocTypeNestedSet from webnotes.utils.nestedset import DocTypeNestedSet
from webnotes.webutils import WebsiteGenerator from webnotes.webutils import WebsiteGenerator
from webnotes.webutils import delete_page_cache
class DocType(DocTypeNestedSet, WebsiteGenerator): class DocType(DocTypeNestedSet, WebsiteGenerator):
def __init__(self, doc, doclist=[]): def __init__(self, doc, doclist=[]):
@ -19,7 +20,6 @@ class DocType(DocTypeNestedSet, WebsiteGenerator):
self.validate_name_with_item() self.validate_name_with_item()
from erpnext.selling.utils.product import invalidate_cache_for
invalidate_cache_for(self.doc.name) invalidate_cache_for(self.doc.name)
self.validate_one_root() self.validate_one_root()
@ -29,22 +29,22 @@ class DocType(DocTypeNestedSet, WebsiteGenerator):
webnotes.msgprint("An item exists with same name (%s), please change the \ webnotes.msgprint("An item exists with same name (%s), please change the \
item group name or rename the item" % self.doc.name, raise_exception=1) item group name or rename the item" % self.doc.name, raise_exception=1)
def get_context(self): def get_group_item_count(item_group):
from erpnext.selling.utils.product import get_product_list_for_group, \ child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(item_group)])
get_parent_item_groups, get_group_item_count return webnotes.conn.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]
self.doc.sub_groups = webnotes.conn.sql("""select name, page_name def get_parent_item_groups(item_group_name):
from `tabItem Group` where parent_item_group=%s item_group = webnotes.doc("Item Group", item_group_name)
and ifnull(show_in_website,0)=1""", self.doc.name, as_dict=1) return webnotes.conn.sql("""select name, page_name from `tabItem Group`
where lft <= %s and rgt >= %s
for d in self.doc.sub_groups: and ifnull(show_in_website,0)=1
d.count = get_group_item_count(d.name) order by lft asc""", (item_group.lft, item_group.rgt), as_dict=True)
self.doc.items = get_product_list_for_group(product_group = self.doc.name, limit=100)
self.parent_groups = get_parent_item_groups(self.doc.name)
self.doc.title = self.doc.name
if self.doc.slideshow:
from webnotes.website.doctype.website_slideshow.website_slideshow import get_slideshow
get_slideshow(self)
def invalidate_cache_for(item_group):
for i in get_parent_item_groups(item_group):
if i.page_name:
delete_page_cache(i.page_name)

View File

@ -26,18 +26,3 @@ class DocType(WebsiteGenerator):
return contact_details return contact_details
else: else:
return '' return ''
def get_context(self):
address = webnotes.conn.get_value("Address",
{"sales_partner": self.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]
self.doc.fields.update({
"email": address.email_id,
"partner_address": filter_strip_join(address_rows, "\n<br>"),
"phone": filter_strip_join(cstr(address.phone).split(","), "\n<br>")
})

View File

@ -1,26 +0,0 @@
{% extends base_template %}
{% block content %}
<div class="container 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">
<h3 itemprop="name" style="margin-top: 0px;">{{ partner_name }}</h3>
<p>{{ description }}</p>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,2 +0,0 @@
doctype = "Sales Partner"
condition_field = "show_in_website"

View File

@ -1,30 +0,0 @@
{% extends base_template %}
{% set title="Partners" %}
{% block content %}
<div class="container content">
<h2 id="blog-title">{{ title }}</h2>
<hr>
{% 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 %}

View File

@ -1,7 +0,0 @@
import webnotes
def get_context():
return {
"partners": webnotes.conn.sql("""select * from `tabSales Partner`
where show_in_website=1 order by name asc""", as_dict=True),
}

View File

@ -29,13 +29,6 @@ def on_session_creation(login_manager):
login_manager.user=='Administrator' and '#8CA2B3' or '#1B750D') login_manager.user=='Administrator' and '#8CA2B3' or '#1B750D')
webnotes.conn.commit() webnotes.conn.commit()
if webnotes.conn.get_value("Profile", webnotes.session.user, "user_type") == "Website User":
from erpnext.selling.utils.cart import set_cart_count
set_cart_count()
def on_logout(login_manager):
webnotes._response.set_cookie("cart_count", "")
def check_if_expired(): def check_if_expired():
"""check if account is expired. If expired, do not allow login""" """check if account is expired. If expired, do not allow login"""
from webnotes import conf from webnotes import conf

View File

@ -1,29 +1,10 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import cint
def update_website_context(context): def update_website_context(context):
post_login = []
cart_enabled = cint(webnotes.conn.get_default("shopping_cart_enabled"))
if cart_enabled:
post_login += [{"label": "Cart", "url": "cart", "icon": "icon-shopping-cart", "class": "cart-count"},
{"class": "divider"}]
post_login += [
{"label": "Profile", "url": "profile", "icon": "icon-user"},
{"label": "Addresses", "url": "addresses", "icon": "icon-map-marker"},
{"label": "My Orders", "url": "orders", "icon": "icon-list"},
{"label": "My Tickets", "url": "tickets", "icon": "icon-tags"},
{"label": "Invoices", "url": "invoices", "icon": "icon-file-text"},
{"label": "Shipments", "url": "shipments", "icon": "icon-truck"},
{"class": "divider"}
]
context.update({
"shopping_cart_enabled": cart_enabled,
"post_login": post_login + context.get("post_login", [])
})
if not context.get("favicon"): if not context.get("favicon"):
context["favicon"] = "app/images/favicon.ico" context["favicon"] = "app/images/favicon.ico"

View File

@ -198,7 +198,7 @@ class DocType(DocListController, WebsiteGenerator):
self.doc.name, raise_exception=1) self.doc.name, raise_exception=1)
def update_website(self): def update_website(self):
from erpnext.selling.utils.product import invalidate_cache_for from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for
invalidate_cache_for(self.doc.item_group) invalidate_cache_for(self.doc.item_group)
[invalidate_cache_for(d.item_group) for d in \ [invalidate_cache_for(d.item_group) for d in \
self.doclist.get({"doctype":"Website Item Group"})] self.doclist.get({"doctype":"Website Item Group"})]
@ -221,15 +221,6 @@ class DocType(DocListController, WebsiteGenerator):
def get_tax_rate(self, tax_type): def get_tax_rate(self, tax_type):
return { "tax_rate": webnotes.conn.get_value("Account", tax_type, "tax_rate") } return { "tax_rate": webnotes.conn.get_value("Account", tax_type, "tax_rate") }
def get_context(self):
from erpnext.selling.utils.product import get_parent_item_groups
self.parent_groups = get_parent_item_groups(self.doc.item_group) + [{"name":self.doc.name}]
self.doc.title = self.doc.item_name
if self.doc.slideshow:
from webnotes.website.doctype.website_slideshow.website_slideshow import get_slideshow
get_slideshow(self)
def get_file_details(self, arg = ''): def get_file_details(self, arg = ''):
file = webnotes.conn.sql("select file_group, description from tabFile where name = %s", eval(arg)['file_name'], as_dict = 1) file = webnotes.conn.sql("select file_group, description from tabFile where name = %s", eval(arg)['file_name'], as_dict = 1)

View File

@ -29,9 +29,6 @@ class DocType(DocListController):
def on_update(self): def on_update(self):
self.set_default_if_missing() self.set_default_if_missing()
self.update_item_price() self.update_item_price()
cart_settings = webnotes.get_obj("Shopping Cart Settings")
if cint(cart_settings.doc.enabled):
cart_settings.validate_price_lists()
def set_default_if_missing(self): def set_default_if_missing(self):
if self.doc.buying_or_selling=="Selling": if self.doc.buying_or_selling=="Selling":

View File

@ -1,87 +0,0 @@
{% extends base_template %}
{% block javascript %}
<script>
{% include "templates/includes/product_page.js" %}
$(function() {
if(window.logged_in && getCookie("system_user")==="yes") {
wn.has_permission("Item", "{{ name }}", "write", function(r) {
wn.require("assets/webnotes/js/wn/website/editable.js");
wn.make_editable($('[itemprop="description"]'), "Item", "{{ name }}", "web_long_description");
});
}
});
</script>
{% endblock %}
{% block css %}
<style>
{% include "templates/includes/product_page.css" %}
</style>
{% endblock %}
{% block content %}
{% include 'templates/includes/product_search_box.html' %}
{% include 'templates/includes/product_breadcrumbs.html' %}
<div class="container content 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 obj.doclist.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 obj.doclist.get(
{"doctype":"Item Website Specification"}) -%}
<tr>
<td style="width: 30%;">{{ d.label }}</td>
<td>{{ d.description }}</td>
</tr>
{%- endfor %}
</table>
</div>
</div>
{%- endif %}
</div>
{% endblock %}

View File

@ -1,2 +0,0 @@
doctype = "Item"
condition_field = "show_in_website"

View File

@ -1,52 +0,0 @@
{% extends base_template %}
{% block content %}
{% include 'templates/includes/product_search_box.html' %}
{% include 'templates/includes/product_breadcrumbs.html' %}
<div class="container content">
{% 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 class="container content">
{% if sub_groups %}
<hr />
<div class="row">
{% for d in sub_groups %}
<div class="col-md-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>
<script>
$(function() {
if(window.logged_in && getCookie("system_user")==="yes") {
wn.has_permission("Item Group", "{{ name }}", "write", function(r) {
wn.require("assets/webnotes/js/wn/website/editable.js");
wn.make_editable($('[itemprop="description"]'), "Item Group", "{{ name }}", "description");
});
}
});
</script>
{% endblock %}

View File

@ -1,2 +0,0 @@
doctype = "Item Group"
condition_field = "show_in_website"

View File

@ -1,294 +0,0 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
// js inside blog page
$(document).ready(function() {
erpnext.cart.bind_events();
return wn.call({
type: "POST",
method: "erpnext.selling.utils.cart.get_cart_quotation",
callback: function(r) {
$("#cart-container").removeClass("hide");
$(".progress").remove();
if(r.exc) {
if(r.exc.indexOf("WebsitePriceListMissingError")!==-1) {
erpnext.cart.show_error("Oops!", wn._("Price List not configured."));
} else if(r["403"]) {
erpnext.cart.show_error("Hey!", wn._("You need to be logged in to view your cart."));
} else {
erpnext.cart.show_error("Oops!", wn._("Something went wrong."));
}
} else {
erpnext.cart.set_cart_count();
erpnext.cart.render(r.message);
}
}
});
});
// shopping cart
if(!erpnext.cart) erpnext.cart = {};
$.extend(erpnext.cart, {
show_error: function(title, text) {
$("#cart-container").html('<div class="well"><h4>' + title + '</h4> ' + text + '</div>');
},
bind_events: function() {
// bind update button
$(document).on("click", ".item-update-cart button", function() {
var item_code = $(this).attr("data-item-code");
erpnext.cart.update_cart({
item_code: item_code,
qty: $('input[data-item-code="'+item_code+'"]').val(),
with_doclist: 1,
btn: this,
callback: function(r) {
if(!r.exc) {
erpnext.cart.render(r.message);
var $button = $('button[data-item-code="'+item_code+'"]').addClass("btn-success");
setTimeout(function() { $button.removeClass("btn-success"); }, 1000);
}
},
});
});
$("#cart-add-shipping-address").on("click", function() {
window.location.href = "address?address_fieldname=shipping_address_name";
});
$("#cart-add-billing-address").on("click", function() {
window.location.href = "address?address_fieldname=customer_address";
});
$(".btn-place-order").on("click", function() {
erpnext.cart.place_order(this);
});
},
render: function(out) {
var doclist = out.doclist;
var addresses = out.addresses;
var $cart_items = $("#cart-items").empty();
var $cart_taxes = $("#cart-taxes").empty();
var $cart_totals = $("#cart-totals").empty();
var $cart_billing_address = $("#cart-billing-address").empty();
var $cart_shipping_address = $("#cart-shipping-address").empty();
var no_items = $.map(doclist, function(d) { return d.item_code || null;}).length===0;
if(no_items) {
erpnext.cart.show_error("Empty :-(", wn._("Go ahead and add something to your cart."));
$("#cart-addresses").toggle(false);
return;
}
var shipping_rule_added = false;
var taxes_exist = false;
var shipping_rule_labels = $.map(out.shipping_rules || [], function(rule) { return rule[1]; });
$.each(doclist, function(i, doc) {
if(doc.doctype === "Quotation Item") {
erpnext.cart.render_item_row($cart_items, doc);
} else if (doc.doctype === "Sales Taxes and Charges") {
if(out.shipping_rules && out.shipping_rules.length &&
shipping_rule_labels.indexOf(doc.description)!==-1) {
shipping_rule_added = true;
erpnext.cart.render_tax_row($cart_taxes, doc, out.shipping_rules);
} else {
erpnext.cart.render_tax_row($cart_taxes, doc);
}
taxes_exist = true;
}
});
if(out.shipping_rules && out.shipping_rules.length && !shipping_rule_added) {
erpnext.cart.render_tax_row($cart_taxes, {description: "", formatted_tax_amount: ""},
out.shipping_rules);
taxes_exist = true;
}
if(taxes_exist)
$('<hr>').appendTo($cart_taxes);
erpnext.cart.render_tax_row($cart_totals, {
description: "<strong>Total</strong>",
formatted_tax_amount: "<strong>" + doclist[0].formatted_grand_total_export + "</strong>"
});
if(!(addresses && addresses.length)) {
$cart_shipping_address.html('<div class="well">'+wn._("Hey! Go ahead and add an address")+'</div>');
} else {
erpnext.cart.render_address($cart_shipping_address, addresses, doclist[0].shipping_address_name);
erpnext.cart.render_address($cart_billing_address, addresses, doclist[0].customer_address);
}
},
render_item_row: function($cart_items, doc) {
doc.image_html = doc.website_image ?
'<div style="height: 120px; overflow: hidden;"><img src="' + doc.website_image + '" /></div>' :
'{% include "stock/doctype/item/templates/includes/product_missing_image.html" %}';
if(doc.description === doc.item_name) doc.description = "";
$(repl('<div class="row">\
<div class="col-md-9 col-sm-9">\
<div class="row">\
<div class="col-md-3">%(image_html)s</div>\
<div class="col-md-9">\
<h4><a href="%(page_name)s">%(item_name)s</a></h4>\
<p>%(description)s</p>\
</div>\
</div>\
</div>\
<div class="col-md-3 col-sm-3 text-right">\
<div class="input-group item-update-cart">\
<input type="text" placeholder="Qty" value="%(qty)s" \
data-item-code="%(item_code)s" class="text-right form-control">\
<div class="input-group-btn">\
<button class="btn btn-primary" data-item-code="%(item_code)s">\
<i class="icon-ok"></i></button>\
</div>\
</div>\
<p style="margin-top: 10px;">at %(formatted_rate)s</p>\
<small class="text-muted" style="margin-top: 10px;">= %(formatted_amount)s</small>\
</div>\
</div><hr>', doc)).appendTo($cart_items);
},
render_tax_row: function($cart_taxes, doc, shipping_rules) {
var shipping_selector;
if(shipping_rules) {
shipping_selector = '<select class="form-control">' + $.map(shipping_rules, function(rule) {
return '<option value="' + rule[0] + '">' + rule[1] + '</option>' }).join("\n") +
'</select>';
}
var $tax_row = $(repl('<div class="row">\
<div class="col-md-9 col-sm-9">\
<div class="row">\
<div class="col-md-9 col-md-offset-3">' +
(shipping_selector || '<p>%(description)s</p>') +
'</div>\
</div>\
</div>\
<div class="col-md-3 col-sm-3 text-right">\
<p' + (shipping_selector ? ' style="margin-top: 5px;"' : "") + '>%(formatted_tax_amount)s</p>\
</div>\
</div>', doc)).appendTo($cart_taxes);
if(shipping_selector) {
$tax_row.find('select option').each(function(i, opt) {
if($(opt).html() == doc.description) {
$(opt).attr("selected", "selected");
}
});
$tax_row.find('select').on("change", function() {
erpnext.cart.apply_shipping_rule($(this).val(), this);
});
}
},
apply_shipping_rule: function(rule, btn) {
return wn.call({
btn: btn,
type: "POST",
method: "erpnext.selling.utils.cart.apply_shipping_rule",
args: { shipping_rule: rule },
callback: function(r) {
if(!r.exc) {
erpnext.cart.render(r.message);
}
}
});
},
render_address: function($address_wrapper, addresses, address_name) {
$.each(addresses, function(i, address) {
$(repl('<div class="panel panel-default"> \
<div class="panel-heading"> \
<div class="row"> \
<div class="col-md-10 address-title" \
data-address-name="%(name)s"><strong>%(name)s</strong></div> \
<div class="col-md-2"><input type="checkbox" \
data-address-name="%(name)s"></div> \
</div> \
</div> \
<div class="panel-collapse collapse" data-address-name="%(name)s"> \
<div class="panel-body">%(display)s</div> \
</div> \
</div>', address))
.css({"margin": "10px auto"})
.appendTo($address_wrapper);
});
$address_wrapper.find(".panel-heading")
.find(".address-title")
.css({"cursor": "pointer"})
.on("click", function() {
$address_wrapper.find('.panel-collapse[data-address-name="'
+$(this).attr("data-address-name")+'"]').collapse("toggle");
});
$address_wrapper.find('input[type="checkbox"]').on("click", function() {
if($(this).prop("checked")) {
var me = this;
$address_wrapper.find('input[type="checkbox"]').each(function(i, chk) {
if($(chk).attr("data-address-name")!=$(me).attr("data-address-name")) {
$(chk).prop("checked", false);
}
});
return wn.call({
type: "POST",
method: "erpnext.selling.utils.cart.update_cart_address",
args: {
address_fieldname: $address_wrapper.attr("data-fieldname"),
address_name: $(this).attr("data-address-name")
},
callback: function(r) {
if(!r.exc) {
erpnext.cart.render(r.message);
}
}
});
} else {
return false;
}
});
$address_wrapper.find('input[type="checkbox"][data-address-name="'+ address_name +'"]')
.prop("checked", true);
$address_wrapper.find(".panel-collapse").collapse({
parent: $address_wrapper,
toggle: false
});
$address_wrapper.find('.panel-collapse[data-address-name="'+ address_name +'"]')
.collapse("show");
},
place_order: function(btn) {
return wn.call({
type: "POST",
method: "erpnext.selling.utils.cart.place_order",
btn: btn,
callback: function(r) {
if(r.exc) {
var msg = "";
if(r._server_messages) {
msg = JSON.parse(r._server_messages || []).join("<br>");
}
$("#cart-error")
.empty()
.html(msg || wn._("Something went wrong!"))
.toggle(true);
} else {
window.location.href = "order?name=" + encodeURIComponent(r.message);
}
}
});
}
});

View File

@ -1,10 +0,0 @@
{% if obj.parent_groups and (obj.parent_groups|length) > 1 %}
<div class="container">
<ul class="breadcrumb">
{% for ig in obj.parent_groups[:-1] %}
<li><a href="{{ ig.page_name }}.html">{{ ig.name }}</a></li>
{% endfor %}
<li class="active">{{ obj.parent_groups[-1].name }}</li>
</ul>
</div>
{% endif %}

View File

@ -1,14 +0,0 @@
<div class="col-md-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 'stock/doctype/item/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>

View File

@ -1,15 +0,0 @@
<!-- 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 'website/templates/html/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>

View File

@ -1,52 +0,0 @@
// 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.selling.utils.product.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);
}

View File

@ -1 +0,0 @@
<div class="missing-image"><i class="icon-camera"></i></div>

View File

@ -1,13 +0,0 @@
<style>
.item-main-image {
max-width: 100%;
margin: auto;
}
.web-long-description {
font-size: 18px;
line-height: 200%;
}
.item-stock {
margin-bottom: 10px !important;
}
</style>

View File

@ -1,78 +0,0 @@
// 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;
wn.call({
type: "POST",
method: "erpnext.selling.utils.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() {
erpnext.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() {
erpnext.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);
}

View File

@ -1,28 +0,0 @@
<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>

View File

@ -1,60 +0,0 @@
{% extends base_template %}
{% block content -%}
<div class="container content">
<ul class="breadcrumb">
<li><a href="index">Home</a></li>
<li class="active"><i class="{{ icon }} icon-fixed-width"></i> {{ title }}</li>
</ul>
<p id="msgprint-alert" class="alert alert-danger"
style="display: none;">&nbsp;</p>
<div class="list-group transaction-list">
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" style="width: 100%;"></div>
</div>
</div>
<div class="text-center">
<button class="btn btn-default btn-show-more hide">More</button>
</div>
</div>
{%- endblock %}
{% block javascript -%}
<script>
$(document).ready(function() {
window.start = 0;
window.$list = $(".transaction-list");
window.$show_more = $(".btn-show-more").on("click", function() { get_transactions(this); })
get_transactions();
});
var get_transactions = function(btn) {
wn.call({
method: "{{ method }}",
args: { start: start },
btn: btn,
callback: function(r) {
$list.find(".progress").remove();
$show_more.toggleClass("hide", !(r.message && r.message.length===20));
if(!(r.message && r.message.length)) {
console.log("empty");
if(!$list.html().trim()) {
$list.html("<div class='alert alert-warning'>\
{{ empty_list_message }}</div>");
}
return;
}
start += r.message.length;
$.each(r.message, function(i, doc) {
render(doc);
});
}
})
};
</script>
<!-- // var render = function(doc) { }; -->
{% endblock %}

View File

@ -1,114 +0,0 @@
{% extends base_template %}
{% set title=doc and doc.name or "New Address" %}
{% set docname=(doc and doc.name or "") %}
{% macro render_fields(docfields) -%}
{% for df in docfields -%}
{% if df.fieldtype in ["Data", "Link"] -%}
<fieldset>
<label>{{ df.label }}</label>
<input class="form-control" type="text" placeholder="Type {{ df.label }}"
data-fieldname="{{ df.fieldname }}" data-fieldtype="{{ df.fieldtype }}"
{% if doc and doc.fields.get(df.fieldname) -%} value="{{ doc.fields[df.fieldname] }}" {%- endif %}>
</fieldset>
{% elif df.fieldtype == "Check" -%}
<fieldset class="checkbox">
<label><input type="checkbox" data-fieldname="{{ df.fieldname }}"
data-fieldtype="{{ df.fieldtype }}"
{% if doc and cint(doc.fields.get(df.fieldname)) -%} checked="checked" {%- endif %}>
{{ df.label }}</label>
</fieldset>
{% elif df.fieldtype == "Select" -%}
<fieldset>
<label>{{ df.label }}</label>
<select class="form-control" data-fieldname="{{ df.fieldname }}" data-fieldtype="{{ df.fieldtype }}">
{% for value in df.options.split("\n") -%}
{% if doc and doc.fields.get(df.fieldname) == value -%}
<option selected="selected">{{ value }}</option>
{% else -%}
<option>{{ value }}</option>
{%- endif %}
{%- endfor %}
</select>
</fieldset>
{%- endif %}
{%- endfor %}
{%- endmacro %}
{% block content %}
<div class="container content">
<ul class="breadcrumb">
<li><a href="index">Home</a></li>
<li><a href="addresses">My Addresses</a></li>
<li class="active"><i class="icon-map-marker icon-fixed-width"></i> {{ title }}</li>
</ul>
<h3><i class="icon-map-marker icon-fixed-width"></i> {{ title }}</h3>
<button type="button" class="btn btn-primary pull-right" id="address-save"><i class="icon-ok"></i>
{{ doc and "Save" or "Insert" }}</button>
<div class="clearfix"></div>
<hr>
<div id="address-error" class="alert alert-danger" style="display: none;"></div>
<form autocomplete="on">
<div class="row">
<section class="col-md-6">
{{ render_fields(meta.left_fields) }}
</section>
<section class="col-md-6">
{{ render_fields(meta.right_fields) }}
</section>
</section>
</form>
</div>
<script>
;(function() {
$(document).ready(function() {
bind_save();
});
var bind_save = function() {
$("#address-save").on("click", function() {
var fields = {
name: "{{ docname }}"
};
$("form").find("[data-fieldname]").each(function(i, input) {
var $input = $(input);
var fieldname = $(input).attr("data-fieldname");
var fieldtype = $(input).attr("data-fieldtype");
if(fieldtype == "Check") {
fields[fieldname] = $input.is(":checked") ? 1 : 0;
} else {
fields[fieldname] = $input.val();
}
});
wn.call({
btn: $(this),
type: "POST",
method: "selling.utils.cart.save_address",
args: { fields: fields, address_fieldname: get_url_arg("address_fieldname") },
callback: function(r) {
if(r.exc) {
var msg = "";
if(r._server_messages) {
msg = JSON.parse(r._server_messages || []).join("<br>");
}
$("#address-error")
.html(msg || "Something went wrong!")
.toggle(true);
} else if(get_url_arg("address_fieldname")) {
window.location.href = "cart";
} else {
window.location.href = "address?name=" + encodeURIComponent(r.message);
}
}
});
});
};
})();
</script>
{% endblock %}

View File

@ -1,30 +0,0 @@
# 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 webnotes
from webnotes.utils import cint
no_cache = True
def get_context():
def _get_fields(fieldnames):
return [webnotes._dict(zip(["label", "fieldname", "fieldtype", "options"],
[df.label, df.fieldname, df.fieldtype, df.options]))
for df in webnotes.get_doctype("Address", processed=True).get({"fieldname": ["in", fieldnames]})]
bean = None
if webnotes.form_dict.name:
bean = webnotes.bean("Address", webnotes.form_dict.name)
return {
"doc": bean.doc if bean else None,
"meta": webnotes._dict({
"left_fields": _get_fields(["address_title", "address_type", "address_line1", "address_line2",
"city", "state", "pincode", "country"]),
"right_fields": _get_fields(["email_id", "phone", "fax", "is_primary_address",
"is_shipping_address"])
}),
"cint": cint
}

View File

@ -1,51 +0,0 @@
{% extends base_template %}
{% set title="My Addresses" %}
{% block content %}
<div class="container content">
<ul class="breadcrumb">
<li><a href="index">Home</a></li>
<li class="active"><i class="icon-map-marker icon-fixed-width"></i> My Addresses</li>
</ul>
<p><a class="btn btn-default" href="address"><i class="icon-plus"> New Address</i></a></p>
<hr>
<div id="address-list">
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" style="width: 100%;"></div>
</div>
</div>
</div>
<script>
;(function() {
$(document).ready(function() {
fetch_addresses();
});
var fetch_addresses = function() {
wn.call({
method: "selling.utils.cart.get_addresses",
callback: function(r) {
$("#address-list .progress").remove();
var $list = $("#address-list");
if(!(r.message && r.message.length)) {
$list.html("<div class='alert'>No Addresses Found</div>");
return;
}
$.each(r.message, function(i, address) {
address.url_name = encodeURIComponent(address.name);
$(repl('<div> \
<p><a href="address?name=%(url_name)s">%(name)s</a></p> \
<p>%(display)s</p> \
<hr> \
</div>', address)).appendTo($list);
});
}
});
};
})();
</script>
{% endblock %}

View File

@ -1,6 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
no_cache = True

View File

@ -1,57 +0,0 @@
{% extends base_template %}
{% block javascript %}
<script>{% include "templates/includes/cart.js" %}</script>
{% endblock %}
{% set title="Shopping Cart" %}
{% block content %}
<div class="container content">
<h2><i class="icon-shopping-cart"></i> {{ title }}</h2>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" style="width: 100%;"></div>
</div>
<div id="cart-container" class="hide">
<p class="pull-right"><button class="btn btn-success btn-place-order" type="button">Place Order</button></p>
<div class="clearfix"></div>
<div id="cart-error" class="alert alert-danger" style="display: none;"></div>
<hr>
<div class="row">
<div class="col-md-9 col-sm-9">
<div class="row">
<div class="col-md-9 col-md-offset-3"><h4>Item Details</h4></div>
</div>
</div>
<div class="col-md-3 col-sm-3 text-right"><h4>Qty, Amount</h4></div>
</div><hr>
<div id="cart-items">
</div>
<div id="cart-taxes">
</div>
<div id="cart-totals">
</div>
<hr>
<div id="cart-addresses">
<div class="row">
<div class="col-md-6">
<h4>Shipping Address</h4>
<div id="cart-shipping-address" class="panel-group"
data-fieldname="shipping_address_name"></div>
<button class="btn btn-default" type="button" id="cart-add-shipping-address">
<span class="icon icon-plus"></span> New Shipping Address</button>
</div>
<div class="col-md-6">
<h4>Billing Address</h4>
<div id="cart-billing-address" class="panel-group"
data-fieldname="customer_address"></div>
<button class="btn btn-default" type="button" id="cart-add-billing-address">
<span class="icon icon-plus"></span> New Billing Address</button>
</div>
</div>
<hr>
</div>
<p class="pull-right"><button class="btn btn-success btn-place-order" type="button">Place Order</button></p>
</div>
</div>
{% endblock %}

View File

@ -1,7 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
no_cache = True
no_sitemap = True

View File

@ -1,5 +0,0 @@
{% extends "templates/sale.html" %}
{% block status -%}
{% if doc.status %}{{ doc.status }}{% endif %}
{%- endblock %}

View File

@ -1,30 +0,0 @@
# 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 webnotes
from webnotes import _
from webnotes.utils import flt, fmt_money
no_cache = True
def get_context():
from erpnext.templates.utils import get_transaction_context
context = get_transaction_context("Sales Invoice", webnotes.form_dict.name)
modify_status(context.get("doc"))
context.update({
"parent_link": "invoices",
"parent_title": "Invoices"
})
return context
def modify_status(doc):
doc.status = ""
if flt(doc.outstanding_amount):
doc.status = '<span class="label %s"><i class="icon-fixed-width %s"></i> %s</span>' % \
("label-warning", "icon-exclamation-sign",
_("To Pay") + " = " + fmt_money(doc.outstanding_amount, currency=doc.currency))
else:
doc.status = '<span class="label %s"><i class="icon-fixed-width %s"></i> %s</span>' % \
("label-success", "icon-ok", _("Paid"))

View File

@ -1 +0,0 @@
{% extends "templates/sales_transactions.html" %}

View File

@ -1,28 +0,0 @@
# 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 webnotes
no_cache = True
def get_context():
from erpnext.templates.utils import get_currency_context
context = get_currency_context()
context.update({
"title": "Invoices",
"method": "accounts.doctype.sales_invoice.templates.pages.invoices.get_invoices",
"icon": "icon-file-text",
"empty_list_message": "No Invoices Found",
"page": "invoice"
})
return context
@webnotes.whitelist()
def get_invoices(start=0):
from erpnext.templates.utils import get_transaction_list
from erpnext.accounts.doctype.sales_invoice.templates.pages.invoice import modify_status
invoices = get_transaction_list("Sales Invoice", start, ["outstanding_amount"])
for d in invoices:
modify_status(d)
return invoices

View File

@ -1,33 +0,0 @@
{% extends base_template %}
{% set title="Product Search" %}
{% block javascript %}
<script>{% include "stock/doctype/item/templates/includes/product_list.js" %}</script>
{% endblock %}
{% block content %}
<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 "stock/doctype/item/templates/includes/product_search_box.html" %}
<div class="container 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 %}

View File

@ -1,6 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
no_cache = True

View File

@ -1,55 +0,0 @@
{% extends base_template %}
{% set title="My Profile" %}
{% block content %}
<div class="container content">
<ul class="breadcrumb">
<li><a href="index">Home</a></li>
<li class="active"><i class="icon-user icon-fixed-width"></i> My Profile</li>
</ul>
<div class="alert alert-warning" id="message" style="display: none;"></div>
<form>
<fieldset>
<label>Full Name</label>
<input class="form-control" type="text" id="fullname" placeholder="Your Name">
</fieldset>
<fieldset>
<label>Company Name</label>
<input class="form-control" type="text" id="company_name" placeholder="Company Name" value="{{ company_name }}">
</fieldset>
<fieldset>
<label>Mobile No</label>
<input class="form-control" type="text" id="mobile_no" placeholder="Mobile No" value="{{ mobile_no }}">
</fieldset>
<fieldset>
<label>Phone</label>
<input class="form-control" type="text" id="phone" placeholder="Phone" value="{{ phone }}">
</fieldset>
<button id="update_profile" type="submit" class="btn btn-default">Update</button>
</form>
</div>
<script>
$(document).ready(function() {
$("#fullname").val(getCookie("full_name") || "");
$("#update_profile").click(function() {
wn.call({
method: "erpnext.templates.pages.profile.update_profile",
type: "POST",
args: {
fullname: $("#fullname").val(),
company_name: $("#company_name").val(),
mobile_no: $("#mobile_no").val(),
phone: $("#phone").val()
},
btn: this,
msg: $("#message"),
callback: function(r) {
if(!r.exc) $("#user-full-name").html($("#fullname").val());
}
});
return false;
})
})
</script>
{% endblock %}

View File

@ -1,40 +0,0 @@
# 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 webnotes
from webnotes import _
from webnotes.utils import cstr
no_cache = True
no_sitemap = True
def get_context():
from erpnext.selling.utils.cart import get_lead_or_customer
party = get_lead_or_customer()
if party.doctype == "Lead":
mobile_no = party.mobile_no
phone = party.phone
else:
mobile_no, phone = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user,
"customer": party.name}, ["mobile_no", "phone"])
return {
"company_name": cstr(party.customer_name if party.doctype == "Customer" else party.company_name),
"mobile_no": cstr(mobile_no),
"phone": cstr(phone)
}
@webnotes.whitelist()
def update_profile(fullname, password=None, company_name=None, mobile_no=None, phone=None):
from erpnext.selling.utils.cart import update_party
update_party(fullname, company_name, mobile_no, phone)
if not fullname:
return _("Name is required")
webnotes.conn.set_value("Profile", webnotes.session.user, "first_name", fullname)
webnotes._response.set_cookie("full_name", fullname)
return _("Updated")

View File

@ -1 +0,0 @@
{% extends "templates/sale.html" %}

View File

@ -1,16 +0,0 @@
# 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 webnotes
no_cache = True
def get_context():
from erpnext.templates.utils import get_transaction_context
context = get_transaction_context("Delivery Note", webnotes.form_dict.name)
context.update({
"parent_link": "shipments",
"parent_title": "Shipments"
})
return context

View File

@ -1 +0,0 @@
{% extends "templates/sales_transactions.html" %}

View File

@ -1,24 +0,0 @@
# 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 webnotes
no_cache = True
def get_context():
from erpnext.templates.utils import get_currency_context
context = get_currency_context()
context.update({
"title": "Shipments",
"method": "erpnext.templates.pages.shipments.get_shipments",
"icon": "icon-truck",
"empty_list_message": "No Shipments Found",
"page": "shipment"
})
return context
@webnotes.whitelist()
def get_shipments(start=0):
from erpnext.templates.utils import get_transaction_list
return get_transaction_list("Delivery Note", start)

View File

@ -1,121 +0,0 @@
{% extends base_template %}
{% set title=doc.name %}
{% set status_label = {
"Open": "label-success",
"To Reply": "label-danger",
"Closed": "label-default"
} %}
{% block content %}
<div class="container content">
<ul class="breadcrumb">
<li><a href="index">Home</a></li>
<li><a href="tickets">My Tickets</a></li>
<li class="active"><i class="icon-ticket icon-fixed-width"></i> {{ doc.name }}</li>
</ul>
<h3><i class="icon-ticket icon-fixed-width"></i> {{ doc.name }}</h3>
{% if doc.name == "Not Allowed" -%}
<script>ask_to_login();</script>
{% else %}
<hr>
{%- if doc.status -%}
{% if doc.status == "Waiting for Customer" -%}
{% set status = "To Reply" %}
{% else %}
{% set status = doc.status %}
{%- endif -%}
<div class="row">
<div class="col-md-2" style="margin-bottom: 7px;">
<span class="label {{ status_label.get(status) or 'label-default' }}">{{ status }}</span>
</div>
<div class="col-md-8">
<div class="row col-md-12">{{ doc.subject }}</div>
</div>
<div class="col-md-2">
<span class="text-muted pull-right">{{ utils.formatdate(doc.creation) }}</span>
</div>
</div>
<div class="row">
<h4 class="col-xs-6">Messages</h4>
<div class="col-xs-6">
<button class="btn btn-sm btn-primary pull-right" id="ticket-reply">
<i class="icon-envelope icon-fixed-width"></i> Reply</button>
<button class="btn btn-sm btn-success pull-right hide" id="ticket-reply-send">
<i class="icon-arrow-right icon-fixed-width"></i> Send</button>
</div>
</div>
<p id="ticket-alert" class="alert alert-danger"
style="display: none;">&nbsp;</p>
{%- if doclist.get({"doctype":"Communication"}) -%}
<div>
<table class="table table-bordered table-striped" id="ticket-thread">
<tbody>
{%- for comm in
(doclist.get({"doctype":"Communication"})|sort(reverse=True, attribute="creation")) %}
<tr>
<td>
<h5 style="text-transform: none">
{{ comm.sender }} on {{ utils.formatdate(comm.creation) }}</h5>
<hr>
<p>{{ webnotes.utils.is_html(comm.content) and comm.content or
comm.content.replace("\n", "<br>")}}</p>
</td>
</tr>
{% endfor -%}
</tbody>
</table>
</div>
{%- else -%}
<div class="alert">No messages</div>
{%- endif -%}
{%- endif -%}
{% endif -%}
</div>
{% endblock %}
{% block javascript %}
<script>
$(document).ready(function() {
$("#ticket-reply").on("click", function() {
if(!$("#ticket-reply-editor").length) {
$('<tr id="ticket-reply-editor"><td>\
<h5 style="text-transform: none">Reply</h5>\
<hr>\
<textarea rows=10 class="form-control" style="resize: vertical;"></textarea>\
</td></tr>').prependTo($("#ticket-thread").find("tbody"));
$("#ticket-reply").addClass("hide");
$("#ticket-reply-send").removeClass("hide");
}
});
$("#ticket-reply-send").on("click", function() {
var reply = $("#ticket-reply-editor").find("textarea").val().trim();
if(!reply) {
msgprint("Please write something in reply!");
} else {
wn.call({
type: "POST",
method: "support.doctype.support_ticket.templates.pages.ticket.add_reply",
btn: this,
args: { ticket: "{{ doc.name }}", message: reply },
callback: function(r) {
if(r.exc) {
msgprint(r._server_messages
? JSON.parse(r._server_messages).join("<br>")
: "Something went wrong!");
} else {
window.location.reload();
}
}
})
}
});
});
var msgprint = function(txt) {
if(txt) $("#ticket-alert").html(txt).toggle(true);
}
</script>
{% endblock %}

View File

@ -1,37 +0,0 @@
# 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 webnotes
from webnotes import _
from webnotes.utils import today
no_cache = True
def get_context():
bean = webnotes.bean("Support Ticket", webnotes.form_dict.name)
if bean.doc.raised_by != webnotes.session.user:
return {
"doc": {"name": "Not Allowed"}
}
else:
return {
"doc": bean.doc,
"doclist": bean.doclist,
"webnotes": webnotes,
"utils": webnotes.utils
}
@webnotes.whitelist()
def add_reply(ticket, message):
if not message:
raise webnotes.throw(_("Please write something"))
bean = webnotes.bean("Support Ticket", ticket)
if bean.doc.raised_by != webnotes.session.user:
raise webnotes.throw(_("You are not allowed to reply to this ticket."), webnotes.PermissionError)
from webnotes.core.doctype.communication.communication import make
make(content=message, sender=bean.doc.raised_by, subject = bean.doc.subject,
doctype="Support Ticket", name=bean.doc.name,
date=today())

View File

@ -1,87 +0,0 @@
{% extends "templates/includes/transactions.html" %}
{% block javascript -%}
{{ super() }}
<script>
var status_label = {
"Open": "label-success",
"Waiting for Customer": "label-danger",
"Closed": "label-default"
}
var render = function(doc) {
doc.status = doc.status.trim();
doc.label_class = status_label[doc.status] || "label-default";
if(doc.status==="Waiting for Customer") doc.status = "To Reply";
$(repl('<a href="{{ page }}?name=%(name)s" class="list-group-item">\
<div class="row">\
<div class="col-md-2" style="margin-bottom: 7px;"><span class="label %(label_class)s">\
%(status)s</span></div>\
<div class="col-md-8">\
<div class="row col-md-12">%(name)s</div>\
<div class="row col-md-12 text-muted">%(subject)s</div>\
</div>\
<div class="col-md-2 pull-right">\
<span class="text-muted">%(creation)s</span>\
</div>\
</div>\
</a>', doc)).appendTo($list);
};
$(document).ready(function() {
if(!window.$new_ticket) {
window.$new_ticket = $('<div>\
<button class="btn btn-primary" style="margin-bottom: 15px;" id="new-ticket">\
<i class="icon-tag icon-fixed-width"></i> New Ticket\
</button>\
<button class="btn btn-success hide" style="margin-bottom: 15px;" id="new-ticket-send">\
<i class="icon-arrow-right icon-fixed-width"></i> Send\
</button>\
</div>').insertBefore(".transaction-list");
}
window.$new_ticket.find("#new-ticket").on("click", function() {
$(this).addClass("hide");
$(window.$new_ticket).find("#new-ticket-send").removeClass("hide");
$('<div class="well" id="ticket-editor">\
<div class="form-group"><input class="form-control" type="data"\
placeholder="Subject" data-fieldname="subject"></div>\
<div class="form-group"><textarea rows=10 class="form-control" \
style="resize: vertical;" placeholder="Message" \
data-fieldname="message"></textarea></div>\
</div>')
.insertAfter(window.$new_ticket);
});
window.$new_ticket.find("#new-ticket-send").on("click", function() {
var subject = $("#ticket-editor").find('[data-fieldname="subject"]').val().trim();
var message = $("#ticket-editor").find('[data-fieldname="message"]').val().trim();
if(!(subject && message)) {
msgprint("Please write something in subject and message!");
} else {
wn.call({
type: "POST",
method: "support.doctype.support_ticket.templates.pages.tickets.make_new_ticket",
btn: this,
args: { subject: subject, message: message },
callback: function(r) {
if(r.exc) {
msgprint(r._server_messages
? JSON.parse(r._server_messages).join("<br>")
: "Something went wrong!");
} else {
window.location.href = "ticket?name=" + encodeURIComponent(r.message);
}
}
})
}
});
});
var msgprint = function(txt) {
if(txt) $("#msgprint-alert").html(txt).toggle(true);
}
</script>
{%- endblock %}

View File

@ -1,38 +0,0 @@
# 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 webnotes
from webnotes.utils import cint, formatdate
no_cache = True
def get_context():
return {
"title": "My Tickets",
"method": "support.doctype.support_ticket.templates.pages.tickets.get_tickets",
"icon": "icon-ticket",
"empty_list_message": "No Tickets Raised",
"page": "ticket"
}
@webnotes.whitelist()
def get_tickets(start=0):
tickets = webnotes.conn.sql("""select name, subject, status, creation
from `tabSupport Ticket` where raised_by=%s
order by modified desc
limit %s, 20""", (webnotes.session.user, cint(start)), as_dict=True)
for t in tickets:
t.creation = formatdate(t.creation)
return tickets
@webnotes.whitelist()
def make_new_ticket(subject, message):
if not (subject and message):
raise webnotes.throw(_("Please write something in subject and message!"))
from erpnext.support.doctype.support_ticket.get_support_mails import add_support_communication
ticket = add_support_communication(subject, message, webnotes.session.user)
return ticket.doc.name

View File

@ -1,89 +0,0 @@
{% extends base_template %}
{% set title=doc.name %}
{% block content %}
<div class="container content">
<ul class="breadcrumb">
<li><a href="index">Home</a></li>
<li><a href="{{ parent_link }}">{{ parent_title }}</a></li>
<li class="active"><i class="icon-file icon-fixed-width"></i> {{ doc.name }}</li>
</ul>
<h3><i class="icon-file icon-fixed-width"></i> {{ doc.name }}</h3>
{% if doc.name == "Not Allowed" -%}
<script>ask_to_login();</script>
{% else %}
<hr>
<div>
<div class="row">
<div class="col-xs-6">
{% block status -%}{%- endblock %}
</div>
<div class="col-xs-6">
<span class="pull-right">{{ utils.formatdate(doc.posting_date or doc.transaction_date) }}</span>
</div>
</div>
<br>
<div class="row">
<div class="col-md-12">
<table class="table table-bordered">
<tbody>
<tr>
<th>Sr</th>
<th>Item Name</th>
<th>Description</th>
<th>Qty</th>
<th>UoM</th>
<th>Basic Rate</th>
<th>Amount</th>
</tr>
{%- for row in doclist.get({"doctype": doc.doctype + " Item"}) %}
<tr>
<td style="width: 3%;">{{ row.idx }}</td>
<td style="width: 20%;">{{ row.item_name }}</td>
<td style="width: 37%;">{{ row.description }}</td>
<td style="width: 5%; text-align: right;">{{ row.qty }}</td>
<td style="width: 5%;">{{ row.stock_uom }}</td>
<td style="width: 15%; text-align: right;">{{ utils.fmt_money(row.export_rate, currency=doc.currency) }}</td>
<td style="width: 15%; text-align: right;">{{ utils.fmt_money(row.export_amount, currency=doc.currency) }}</td>
</tr>
{% endfor -%}
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-md-6"></div>
<div class="col-md-6">
<table cellspacing=0 width=100%>
<tbody>
<tr>
<td>Net Total</td>
<td width=40% style="text-align: right;">{{
utils.fmt_money(doc.net_total/doc.conversion_rate, currency=doc.currency)
}}</td>
</tr>
{%- for charge in doclist.get({"doctype":"Sales Taxes and Charges"}) -%}
{%- if not charge.included_in_print_rate -%}
<tr>
<td>{{ charge.description }}</td>
<td style="text-align: right;">{{ utils.fmt_money(charge.tax_amount / doc.conversion_rate, currency=doc.currency) }}</td>
</tr>
{%- endif -%}
{%- endfor -%}
<tr>
<td>Grand Total</td>
<td style="text-align: right;">{{ utils.fmt_money(doc.grand_total_export, currency=doc.currency) }}</td>
</tr>
<tr style='font-weight: bold'>
<td>Rounded Total</td>
<td style="text-align: right;">{{ utils.fmt_money(doc.rounded_total_export, currency=doc.currency) }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{%- endif %}
</div>
{% endblock %}

View File

@ -1,32 +0,0 @@
{% extends "templates/includes/transactions.html" %}
{% block javascript -%}
<script>
$(document).ready(function() {
global_number_format = "{{ global_number_format }}";
currency = "{{ currency }}";
wn.currency_symbols = {{ currency_symbols }};
});
</script>
{{ super() }}
<script>
var render = function(doc) {
doc.grand_total_export = format_currency(doc.grand_total_export, doc.currency);
if(!doc.status) doc.status = "";
$(repl('<a href="{{ page }}?name=%(name)s" class="list-group-item">\
<div class="row">\
<div class="col-md-6">\
<div class="row col-md-12">%(name)s</div>\
<div class="row col-md-12 text-muted">%(items)s</div>\
<div class="row col-md-12">%(status)s</div>\
</div>\
<div class="col-md-3 text-right">%(grand_total_export)s</div>\
<div class="col-md-3 text-right text-muted">%(creation)s</div>\
</div>\
</a>', doc)).appendTo($list);
};
</script>
{%- endblock %}

View File

@ -3,59 +3,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import cint, formatdate
import json
def get_transaction_list(doctype, start, additional_fields=None):
# find customer id
customer = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user},
"customer")
if customer:
if additional_fields:
additional_fields = ", " + ", ".join(("`%s`" % f for f in additional_fields))
else:
additional_fields = ""
transactions = webnotes.conn.sql("""select name, creation, currency, grand_total_export
%s
from `tab%s` where customer=%s and docstatus=1
order by creation desc
limit %s, 20""" % (additional_fields, doctype, "%s", "%s"),
(customer, cint(start)), as_dict=True)
for doc in transactions:
items = webnotes.conn.sql_list("""select item_name
from `tab%s Item` where parent=%s limit 6""" % (doctype, "%s"), doc.name)
doc.items = ", ".join(items[:5]) + ("..." if (len(items) > 5) else "")
doc.creation = formatdate(doc.creation)
return transactions
else:
return []
def get_currency_context():
return {
"global_number_format": webnotes.conn.get_default("number_format") or "#,###.##",
"currency": webnotes.conn.get_default("currency"),
"currency_symbols": json.dumps(dict(webnotes.conn.sql("""select name, symbol
from tabCurrency where ifnull(enabled,0)=1""")))
}
def get_transaction_context(doctype, name):
customer = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user},
"customer")
bean = webnotes.bean(doctype, name)
if bean.doc.customer != customer:
return {
"doc": {"name": "Not Allowed"}
}
else:
return {
"doc": bean.doc,
"doclist": bean.doclist,
"webnotes": webnotes,
"utils": webnotes.utils
}
@webnotes.whitelist(allow_guest=True) @webnotes.whitelist(allow_guest=True)
def send_message(subject="Website Query", message="", sender="", status="Open"): def send_message(subject="Website Query", message="", sender="", status="Open"):