From 156ce607e2a4051ddd47b603204a10574103c55f Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 11 Sep 2015 18:49:59 +0530 Subject: [PATCH] [cleanup] [wip] portal, shopping cart cleanup --- .../controllers/website_list_for_contact.py | 51 +++++--- erpnext/hooks.py | 23 +++- erpnext/public/css/website.css | 2 + erpnext/public/less/website.less | 2 + erpnext/shopping_cart/cart.py | 17 +-- erpnext/stock/doctype/item/item.py | 1 + erpnext/templates/generators/item.html | 41 +++--- erpnext/templates/includes/address_row.html | 19 +-- erpnext/templates/includes/cart.css | 7 ++ erpnext/templates/includes/cart.js | 60 ++++----- erpnext/templates/includes/issue_row.html | 22 ++-- erpnext/templates/includes/macros.html | 28 +++-- erpnext/templates/includes/order.css | 25 ++++ erpnext/templates/includes/product_page.js | 27 ++-- .../templates/includes/transaction_row.html | 23 ++-- erpnext/templates/pages/cart.html | 117 +++++++++++------- erpnext/templates/pages/cart.py | 12 +- erpnext/templates/pages/order.html | 90 ++++++++++++++ erpnext/templates/pages/order.py | 15 +++ erpnext/utilities/doctype/address/address.py | 3 + 20 files changed, 395 insertions(+), 190 deletions(-) create mode 100644 erpnext/templates/includes/cart.css create mode 100644 erpnext/templates/includes/order.css create mode 100644 erpnext/templates/pages/order.html create mode 100644 erpnext/templates/pages/order.py diff --git a/erpnext/controllers/website_list_for_contact.py b/erpnext/controllers/website_list_for_contact.py index 9282be286f..9ec94eb3f8 100644 --- a/erpnext/controllers/website_list_for_contact.py +++ b/erpnext/controllers/website_list_for_contact.py @@ -21,37 +21,54 @@ def get_list_context(context=None): def get_transaction_list(doctype, txt=None, filters=None, limit_start=0, limit_page_length=20): from frappe.templates.pages.list import get_list user = frappe.session.user + key = None + + if not filters: filters = [] + + filters.append((doctype, "docstatus", "=", 1)) if user != "Guest" and is_website_user(): # find party for this contact customers, suppliers = get_customers_suppliers(doctype, user) + if customers: - return post_process(get_list(doctype, txt, filters=[(doctype, "customer", "in", customers)], - limit_start=limit_start, limit_page_length=limit_page_length, ignore_permissions=True)) - + key, parties = "customer", customers elif suppliers: - return post_process(get_list(doctype, txt, filters=[(doctype, "supplier", "in", suppliers)], - limit_start=limit_start, limit_page_length=limit_page_length, ignore_permissions=True)) + key, parties = "supplier", suppliers + filters.append((doctype, key, "in", parties)) + + if key: + return post_process(doctype, get_list(doctype, txt, + filters=filters, fields = "name", + limit_start=limit_start, limit_page_length=limit_page_length, + ignore_permissions=True, + order_by = "modified desc")) else: return [] - return post_process(get_list(doctype, txt, filters, limit_start, limit_page_length)) + return post_process(doctype, get_list(doctype, txt, filters, limit_start, limit_page_length, + fields="name", order_by = "modified desc")) -def post_process(result): - for r in result: - r.status_percent = 0 - r.status_display = [] +def post_process(doctype, data): + result = [] + for d in data: + doc = frappe.get_doc(doctype, d.name) - if r.get("per_billed"): - r.status_percent += flt(r.per_billed) - r.status_display.append(_("Billed") if r.per_billed==100 else _("{0}% Billed").format(r.per_billed)) + doc.status_percent = 0 + doc.status_display = [] - if r.get("per_delivered"): - r.status_percent += flt(r.per_delivered) - r.status_display.append(_("Delivered") if r.per_delivered==100 else _("{0}% Delivered").format(r.per_delivered)) + if doc.get("per_billed"): + doc.status_percent += flt(doc.per_billed) + doc.status_display.append(_("Billed") if doc.per_billed==100 else _("{0}% Billed").format(doc.per_billed)) - r.status_display = ", ".join(r.status_display) + if doc.get("per_delivered"): + doc.status_percent += flt(doc.per_delivered) + doc.status_display.append(_("Delivered") if doc.per_delivered==100 else _("{0}% Delivered").format(doc.per_delivered)) + + doc.status_display = ", ".join(doc.status_display) + doc.items_preview = ", ".join([d.item_name for d in doc.items]) + result.append(doc) return result diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 54f81b89d5..96f70a866f 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -1,4 +1,6 @@ from __future__ import unicode_literals +from frappe import _ + app_name = "erpnext" app_title = "ERPNext" app_publisher = "Frappe Technologies Pvt. Ltd." @@ -62,11 +64,26 @@ website_context = { website_route_rules = [ {"from_route": "/orders", "to_route": "Sales Order"}, - {"from_route": "/orders/", "to_route": "print", "defaults": {"doctype": "Sales Order"}}, + {"from_route": "/orders/", "to_route": "order", + "defaults": { + "doctype": "Sales Order", + "parents": [{"title": _("Orders"), "name": "orders"}] + } + }, {"from_route": "/invoices", "to_route": "Sales Invoice"}, - {"from_route": "/invoices/", "to_route": "print", "defaults": {"doctype": "Sales Invoice"}}, + {"from_route": "/invoices/", "to_route": "order", + "defaults": { + "doctype": "Sales Invoice", + "parents": [{"title": _("Invoices"), "name": "invoices"}] + } + }, {"from_route": "/shipments", "to_route": "Delivery Note"}, - {"from_route": "/shipments/", "to_route": "print", "defaults": {"doctype": "Delivery Note"}} + {"from_route": "/shipments/", "to_route": "order", + "defaults": { + "doctype": "Delivery Notes", + "parents": [{"title": _("Shipments"), "name": "shipments"}] + } + } ] has_website_permission = { diff --git a/erpnext/public/css/website.css b/erpnext/public/css/website.css index 9b4df40bd1..f3bc58d3de 100644 --- a/erpnext/public/css/website.css +++ b/erpnext/public/css/website.css @@ -29,6 +29,7 @@ background-repeat: no-repeat; background-position: center top; border-radius: 0.5em; + border: 1px solid #ebeff2; } .product-image.missing-image { width: 100%; @@ -38,6 +39,7 @@ background-repeat: no-repeat; background-position: center top; border-radius: 0.5em; + border: 1px solid #ebeff2; border: 1px dashed #d1d8dd; position: relative; } diff --git a/erpnext/public/less/website.less b/erpnext/public/less/website.less index c0667cceab..96dd0966ab 100644 --- a/erpnext/public/less/website.less +++ b/erpnext/public/less/website.less @@ -1,4 +1,5 @@ @border-color: #d1d8dd; +@light-border-color: #EBEFF2; .web-long-description { font-size: 18px; @@ -35,6 +36,7 @@ background-repeat: no-repeat; background-position: center top; border-radius: 0.5em; + border: 1px solid @light-border-color; } .product-image.missing-image { diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py index 30f4aba493..e219d8ed5f 100644 --- a/erpnext/shopping_cart/cart.py +++ b/erpnext/shopping_cart/cart.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import throw, _ import frappe.defaults -from frappe.utils import cint, flt, get_fullname, fmt_money, cstr +from frappe.utils import cint, flt, get_fullname, cstr from erpnext.utilities.doctype.address.address import get_address_display from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings import get_shopping_cart_settings from frappe.utils.nestedset import get_root_of @@ -134,20 +134,10 @@ def guess_territory(): frappe.db.get_value("Shopping Cart Settings", None, "territory") or \ get_root_of("Territory") -def decorate_quotation_doc(quotation_doc): - doc = frappe._dict(quotation_doc.as_dict()) +def decorate_quotation_doc(doc): for d in doc.get("items", []): - d.update(frappe.db.get_value("Item", d["item_code"], + d.update(frappe.db.get_value("Item", d.item_code, ["website_image", "description", "page_name"], as_dict=True)) - d["formatted_rate"] = fmt_money(d.get("rate"), currency=doc.currency) - d["formatted_amount"] = fmt_money(d.get("amount"), currency=doc.currency) - - for d in doc.get("taxes", []): - d["formatted_tax_amount"] = fmt_money(flt(d.get("tax_amount_after_discount_amount")), - currency=doc.currency) - - doc.formatted_grand_total_export = fmt_money(doc.grand_total, - currency=doc.currency) return doc @@ -314,7 +304,6 @@ def get_address_docs(doctype=None, txt=None, filters=None, limit_start=0, limit_ for address in address_docs: address.display = get_address_display(address) - address.display = (address.display).replace("\n", "
\n") return address_docs diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 6eadb83779..310f4cca22 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -19,6 +19,7 @@ class Item(WebsiteGenerator): condition_field = "show_in_website", template = "templates/generators/item.html", parent_website_route_field = "item_group", + no_cache = 1 ) def onload(self): diff --git a/erpnext/templates/generators/item.html b/erpnext/templates/generators/item.html index 535edcdb73..af4a795c9f 100644 --- a/erpnext/templates/generators/item.html +++ b/erpnext/templates/generators/item.html @@ -27,22 +27,31 @@ {{ _("Item Code") }}: {{ name }}


- +

+
+
+
+ +
+ +
diff --git a/erpnext/templates/includes/address_row.html b/erpnext/templates/includes/address_row.html index f7eaa76ae9..fd287addf4 100644 --- a/erpnext/templates/includes/address_row.html +++ b/erpnext/templates/includes/address_row.html @@ -1,19 +1,8 @@
- - diff --git a/erpnext/templates/includes/cart.css b/erpnext/templates/includes/cart.css new file mode 100644 index 0000000000..ed98846a8d --- /dev/null +++ b/erpnext/templates/includes/cart.css @@ -0,0 +1,7 @@ +.cart-content { + min-height: 400px; +} + +.cart-header, .cart-footer { + margin-bottom: 40px; +} diff --git a/erpnext/templates/includes/cart.js b/erpnext/templates/includes/cart.js index d5956f9912..349e2f5ed8 100644 --- a/erpnext/templates/includes/cart.js +++ b/erpnext/templates/includes/cart.js @@ -92,12 +92,12 @@ $.extend(shopping_cart, { $('
').appendTo($cart_taxes); shopping_cart.render_tax_row($cart_totals, { - description: "Total", - formatted_tax_amount: "" + doc.formatted_grand_total_export + "" + description: "", + formatted_tax_amount: __("Total") + ": " + doc.formatted_grand_total_export + "" }); if(!(addresses && addresses.length)) { - $cart_shipping_address.html('
'+frappe._("Hey! Go ahead and add an address")+'
'); + $cart_shipping_address.html('

'+frappe._("Please add a new address")+'

'); } else { shopping_cart.render_address($cart_shipping_address, addresses, doc.shipping_address_name); shopping_cart.render_address($cart_billing_address, addresses, doc.customer_address); @@ -113,9 +113,9 @@ $.extend(shopping_cart, { $(repl('
\
\
\ -
%(image_html)s
\ -
\ -

%(item_name)s

\ +
%(image_html)s
\ +
\ +
%(item_name)s
\

%(description)s

\
\
\ @@ -129,8 +129,8 @@ $.extend(shopping_cart, { \
\
\ -

at %(formatted_rate)s

\ - = %(formatted_amount)s\ +

' + __("Rate") + ': %(formatted_rate)s

\ + %(formatted_amount)s\
\

', doc)).appendTo($cart_items); }, @@ -189,12 +189,12 @@ $.extend(shopping_cart, {
\
%(name)s
\ -
\
\ \
\ -
%(display)s
\ +
%(display)s
\
\ ', address)) .css({"margin": "10px auto"}) @@ -274,24 +274,24 @@ $.extend(shopping_cart, { $(document).ready(function() { shopping_cart.bind_events(); - return frappe.call({ - type: "POST", - method: "erpnext.shopping_cart.cart.get_cart_quotation", - callback: function(r) { - $("#cart-container").removeClass("hide"); - $(".progress").remove(); - if(r.exc) { - if(r.exc.indexOf("WebsitePriceListMissingError")!==-1) { - shopping_cart.show_error("Configuration Error", frappe._("Price List not configured.")); - } else if(r["403"]) { - shopping_cart.show_error("Not Allowed", frappe._("You need to be logged in to view your cart.")); - } else { - shopping_cart.show_error("Error", frappe._("Something went wrong.")); - } - } else { - shopping_cart.set_cart_count(); - shopping_cart.render(r.message); - } - } - }); + // return frappe.call({ + // type: "POST", + // method: "erpnext.shopping_cart.cart.get_cart_quotation", + // callback: function(r) { + // $("#cart-container").removeClass("hide"); + // $(".loading").remove(); + // if(r.exc) { + // if(r.exc.indexOf("WebsitePriceListMissingError")!==-1) { + // shopping_cart.show_error("Configuration Error", frappe._("Price List not configured.")); + // } else if(r["403"]) { + // shopping_cart.show_error("Not Allowed", frappe._("You need to be logged in to view your cart.")); + // } else { + // shopping_cart.show_error("Error", frappe._("Something went wrong.")); + // } + // } else { + // shopping_cart.set_cart_count(); + // shopping_cart.render(r.message); + // } + // } + // }); }); diff --git a/erpnext/templates/includes/issue_row.html b/erpnext/templates/includes/issue_row.html index 16a8f7b7b7..8e87fcae7b 100644 --- a/erpnext/templates/includes/issue_row.html +++ b/erpnext/templates/includes/issue_row.html @@ -1,21 +1,15 @@
+
-
- - {{ doc.subject }} - +
+ + {{ doc.name }} + + {{ doc.subject }}
-
- - {{ doc.status }} -
- -
+
{{ frappe.format_date(doc.creation) }}
+
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html index 6748a5ebd2..487968ba81 100644 --- a/erpnext/templates/includes/macros.html +++ b/erpnext/templates/includes/macros.html @@ -6,11 +6,25 @@ {% endmacro %} {% macro product_image(website_image, css_class="") %} -
- {% if website_image -%} - - {%- else -%} - - {%- endif %} -
+
+ {% if website_image -%} + + {%- else -%} + + {%- endif %} +
+{% endmacro %} + +{% macro item_name_and_description(d) %} +
+
+
+ {{ product_image_square(d.image) }} +
+
+
+ {{ d.item_code }} +

{{ d.description }}

+
+
{% endmacro %} diff --git a/erpnext/templates/includes/order.css b/erpnext/templates/includes/order.css new file mode 100644 index 0000000000..54c8d0ffe2 --- /dev/null +++ b/erpnext/templates/includes/order.css @@ -0,0 +1,25 @@ +.order-container { + margin: 50px 0px; +} + +.order-items { + margin: 20px 0px; +} + +.order-item-table { + margin: 0px -15px; +} + +.order-item-header { + border-bottom: 1px solid #d1d8dd; +} + +.order-image-col { + padding-right: 0px; +} + +.order-image { + max-width: 55px; + max-height: 55px; + margin-top: -5px; +} diff --git a/erpnext/templates/includes/product_page.js b/erpnext/templates/includes/product_page.js index 4f4f11c9f3..98331a4f20 100644 --- a/erpnext/templates/includes/product_page.js +++ b/erpnext/templates/includes/product_page.js @@ -1,10 +1,10 @@ // Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -$(document).ready(function() { +frappe.ready(function() { var item_code = $('[itemscope] [itemprop="productID"]').text().trim(); var qty = 0; - + frappe.call({ type: "POST", method: "erpnext.shopping_cart.product.get_product_info", @@ -12,10 +12,12 @@ $(document).ready(function() { item_code: "{{ name }}" }, callback: function(r) { + console.log(r.message); + $(".item-cart").toggleClass("hide", !!!r.message.price); 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("
Not in stock
"); } @@ -23,18 +25,17 @@ $(document).ready(function() { $(".item-stock").html("
\ Available (in stock)
"); } - - $(".item-price-info").toggle(true); - + if(r.message.qty) { qty = r.message.qty; - toggle_update_cart(qty); - $("#item-update-cart input").val(qty); + toggle_update_cart(r.message.qty); + } else { + toggle_update_cart(0); } } } }) - + $("#item-add-to-cart button").on("click", function() { shopping_cart.update_cart({ item_code: item_code, @@ -45,10 +46,10 @@ $(document).ready(function() { qty = 1; } }, - btn: this, + btn: this, }); }); - + $("#item-update-cart button").on("click", function() { shopping_cart.update_cart({ item_code: item_code, @@ -63,7 +64,7 @@ $(document).ready(function() { }, }); }); - + if(localStorage && localStorage.getItem("pending_add_to_cart") && full_name) { localStorage.removeItem("pending_add_to_cart"); $("#item-add-to-cart button").trigger("click"); @@ -75,4 +76,4 @@ var toggle_update_cart = function(qty) { $("#item-update-cart") .toggle(qty ? true : false) .find("input").val(qty); -} \ No newline at end of file +} diff --git a/erpnext/templates/includes/transaction_row.html b/erpnext/templates/includes/transaction_row.html index a677fa5ad3..9b9fd52350 100644 --- a/erpnext/templates/includes/transaction_row.html +++ b/erpnext/templates/includes/transaction_row.html @@ -1,29 +1,22 @@ -{% set doc = frappe.get_doc(doc) %}
-
+
-
{{ doc.customer or doc.supplier }}
+
+
{{ doc.name }}
+
{{ doc.items_preview }}
+
- {%- if doc.status_percent > 0 -%} - {%- if doc.status_percent % 100 == 0 -%} - {{ doc.status_display }} - {%- else -%} - {{ doc.status_display }} - {%- endif -%} - {%- elif doc.status -%} - {{ doc.status }} - {%- endif -%} + + {{ doc.indicator_title or doc.status or "Submitted" }} +
{{ doc.get_formatted("grand_total") }}
-
- {{ doc.name }} -
{{ frappe.utils.pretty_date(doc.creation) }}
diff --git a/erpnext/templates/pages/cart.html b/erpnext/templates/pages/cart.html index e4e4a6a6c1..2e1572869f 100644 --- a/erpnext/templates/pages/cart.html +++ b/erpnext/templates/pages/cart.html @@ -3,53 +3,84 @@ {% block header %}

{{ _("My Cart") }}

{% endblock %} {% block script %}{% include "templates/includes/cart.js" %}{% endblock %} +{% block style %}{% include "templates/includes/cart.css" %}{% endblock %} {% block content %} + +{% from "erpnext/templates/includes/macros.html" import item_name_and_description %} +
-
{{ _("Loading") }}...
-
-

-
+

{{ _("Loading") }}...

+
+
+

+
+
-
-
-
-
-

{{ _("Item Details") }}

-
-
-

{{ _("Qty, Amount") }}

-

-
-
-
-
-
-
-
-
-
-
-

{{ _("Shipping Address") }}

-
- -
-
-

Billing Address

-
- -
-
-
-
-

-
+
+ {% if doc.items %} + {% for d in doc.items %} +
+
+
+ {{ item_name_and_description(d) }} +
+
+
+
+ +
+
+ +
+
+

+ {{ _("Rate") + ': ' + d.get_formatted("rate") }} +

+ + {{ d.get_formatted("amount") }} +
+
+
+ {% endfor %} + {% else %} +

{{ _("Cart is Empty") }}

+ {% endif %} +
+
+
+
+
+
+
+
+

{{ _("Shipping Address") }}

+
+ +
+
+

Billing Address

+
+ +
+
+
+ +
+
diff --git a/erpnext/templates/pages/cart.py b/erpnext/templates/pages/cart.py index fe50f0fe47..bb8645d816 100644 --- a/erpnext/templates/pages/cart.py +++ b/erpnext/templates/pages/cart.py @@ -2,7 +2,13 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -from __future__ import unicode_literals - no_cache = 1 -no_sitemap = 1 \ No newline at end of file +no_sitemap = 1 + +import frappe +from erpnext.shopping_cart.cart import get_cart_quotation + +def get_context(context): + context.update(get_cart_quotation()) + + print context diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html new file mode 100644 index 0000000000..c3bca5bb50 --- /dev/null +++ b/erpnext/templates/pages/order.html @@ -0,0 +1,90 @@ +{% block header %} +

{{ doc.name }}

+ +{% endblock %} + +{% block style %}{% include "templates/includes/order.css" %}{% endblock %} + +{% block content %} + +{% from "erpnext/templates/includes/macros.html" import item_name_and_description %} + +
+
+ + {{ doc.indicator_title or doc.status or "Submitted" }} + +
+
+ {{ doc.get_formatted("transaction_date") }} +
+
+ +{% if doc._header %} +{{ doc._header }} +{% endif %} + +
+ + +
+
+
+ {{ _("Item") }} +
+
+ {{ _("Quantity") }} +
+
+ {{ _("Amount") }} +
+
+ {% for d in doc.items %} +
+
+ {{ item_name_and_description(d) }} +
+
+ {{ d.qty }} + {% if d.delivered_qty != None %} +

{{ + _("Delivered: {0}").format(d.delivered_qty) }}

+ {% endif %} +
+
+ {{ d.get_formatted("amount") }} +

{{ + _("Rate: {0}").format(d.get_formatted("rate")) }}

+
+
+ {% endfor %} +
+ + +
+
+
+ {% if doc.taxes %} +
+
{{ _("Net Total") }}
+
+ {{ doc.get_formatted("net_total") }}
+
+ {% endif %} + {% for d in doc.taxes %} +
+
{{ d.description }}
+
+ {{ d.get_formatted("total") }}
+
+ {% endfor %} +
+
{{ _("Grand Total") }}
+
+ {{ doc.get_formatted("grand_total") }}
+
+
+
+
+ +{% endblock %} diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py new file mode 100644 index 0000000000..260490d129 --- /dev/null +++ b/erpnext/templates/pages/order.py @@ -0,0 +1,15 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +from frappe import _ + +def get_context(context): + context.no_cache = 1 + context.doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name) + context.parents = frappe.form_dict.parents + + if not context.doc.has_permission("read"): + frappe.throw(_("Not Permitted"), frappe.PermissionError) diff --git a/erpnext/utilities/doctype/address/address.py b/erpnext/utilities/doctype/address/address.py index b3f67175e5..8ae7c4da6f 100644 --- a/erpnext/utilities/doctype/address/address.py +++ b/erpnext/utilities/doctype/address/address.py @@ -70,6 +70,9 @@ class Address(Document): (is_address_type, fieldname, "%s", "%s"), (self.get(fieldname), self.name)) break + def get_display(self): + return get_address_display(self.as_dict()) + @frappe.whitelist() def get_address_display(address_dict): if not address_dict: