Website data from existing child tables, layout, images
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index af030d6..bfbbce8 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -1230,7 +1230,7 @@
"label": "Website",
"length": 0,
"no_copy": 0,
- "options": "fa fa-globe",
+ "options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -1248,7 +1248,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "eval:!doc.variant_of",
+ "depends_on": "",
"fieldname": "show_in_website",
"fieldtype": "Check",
"hidden": 0,
@@ -1299,7 +1299,7 @@
"unique": 0
},
{
- "allow_on_submit": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
@@ -1328,7 +1328,7 @@
"unique": 0
},
{
- "allow_on_submit": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
@@ -1358,7 +1358,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
- "collapsible_depends_on": "",
+ "collapsible_depends_on": "website_items",
"columns": 0,
"depends_on": "show_in_website",
"fieldname": "sb_web_spec",
@@ -1384,7 +1384,7 @@
"unique": 0
},
{
- "allow_on_submit": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
@@ -1412,7 +1412,7 @@
"unique": 0
},
{
- "allow_on_submit": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
@@ -1440,7 +1440,7 @@
"unique": 0
},
{
- "allow_on_submit": 1,
+ "allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
@@ -1469,11 +1469,11 @@
"unique": 0
},
{
- "allow_on_submit": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "show_in_website",
+ "depends_on": "eval:(doc.show_in_website && doc.with_operations)",
"fieldname": "show_operations",
"fieldtype": "Check",
"hidden": 0,
@@ -1497,7 +1497,7 @@
"unique": 0
},
{
- "allow_on_submit": 1,
+ "allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
@@ -1537,7 +1537,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-02-10 07:52:53.599831",
+ "modified": "2017-02-12 23:16:15.994194",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index bdd76aa..d9f35d8 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -54,6 +54,8 @@
self.set_bom_material_details()
self.validate_operations()
self.calculate_cost()
+ self.validate_website_image()
+ self.make_thumbnail()
def get_context(self, context):
context.parents = [{'name': 'boms', 'title': _('All BOMs') }]
@@ -452,6 +454,7 @@
'item_code' : d.item_code,
'item_name' : d.item_name,
'description' : d.description,
+ 'qty' : d.qty,
'website_image' : d.image
}))
@@ -495,6 +498,86 @@
ch.docstatus = self.docstatus
ch.db_insert()
+ def validate_website_image(self):
+ """Validate if the website image is a public file"""
+ auto_set_website_image = False
+ if not self.website_image and self.image:
+ auto_set_website_image = True
+ self.website_image = self.image
+
+ if not self.website_image:
+ return
+
+ # find if website image url exists as public
+ file_doc = frappe.get_all("File", filters={
+ "file_url": self.website_image
+ }, fields=["name", "is_private"], order_by="is_private asc", limit_page_length=1)
+
+
+ if file_doc:
+ file_doc = file_doc[0]
+
+ if not file_doc:
+ if not auto_set_website_image:
+ frappe.msgprint(_("Website Image {0} attached to Item {1} cannot be found")
+ .format(self.website_image, self.name))
+
+ self.website_image = None
+
+ elif file_doc.is_private:
+ if not auto_set_website_image:
+ frappe.msgprint(_("Website Image should be a public file or website URL"))
+
+ self.website_image = None
+
+ def make_thumbnail(self):
+ """Make a thumbnail of `website_image`"""
+ import requests.exceptions
+
+ if not self.is_new() and self.website_image != frappe.db.get_value(self.doctype, self.name, "website_image"):
+ self.thumbnail = None
+
+ if self.website_image and not self.thumbnail:
+ file_doc = None
+
+ try:
+ file_doc = frappe.get_doc("File", {
+ "file_url": self.website_image,
+ "attached_to_doctype": "Item",
+ "attached_to_name": self.name
+ })
+ except frappe.DoesNotExistError:
+ pass
+ # cleanup
+ frappe.local.message_log.pop()
+
+ except requests.exceptions.HTTPError:
+ frappe.msgprint(_("Warning: Invalid attachment {0}").format(self.website_image))
+ self.website_image = None
+
+ except requests.exceptions.SSLError:
+ frappe.msgprint(_("Warning: Invalid SSL certificate on attachment {0}").format(self.website_image))
+ self.website_image = None
+
+ # for CSV import
+ if self.website_image and not file_doc:
+ try:
+ file_doc = frappe.get_doc({
+ "doctype": "File",
+ "file_url": self.website_image,
+ "attached_to_doctype": "Item",
+ "attached_to_name": self.name
+ }).insert()
+
+ except IOError:
+ self.website_image = None
+
+ if file_doc:
+ if not file_doc.thumbnail_url:
+ file_doc.make_thumbnail()
+
+ self.thumbnail = file_doc.thumbnail_url
+
def get_list_context(context):
context.title = _("Bill of Materials")
# context.introduction = _('Boms')
diff --git a/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.json b/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.json
index 3e605db..7df728b 100644
--- a/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.json
+++ b/erpnext/manufacturing/doctype/bom_website_item/bom_website_item.json
@@ -159,7 +159,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-02-10 07:34:33.625474",
+ "modified": "2017-02-12 12:48:56.949861",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Website Item",
diff --git a/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.json b/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.json
index 1a8d4fe..8f28dd7 100644
--- a/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.json
+++ b/erpnext/manufacturing/doctype/bom_website_operation/bom_website_operation.json
@@ -120,6 +120,33 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "thumbnail",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Thumbnail",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
}
],
"hide_heading": 0,
@@ -132,7 +159,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-02-10 07:34:30.479443",
+ "modified": "2017-02-12 16:32:44.316447",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Website Operation",
diff --git a/erpnext/public/css/website.css b/erpnext/public/css/website.css
index 1617ea7..1d30e78 100644
--- a/erpnext/public/css/website.css
+++ b/erpnext/public/css/website.css
@@ -250,3 +250,27 @@
.product-image-wrapper {
padding-bottom: 40px;
}
+.duration-bar {
+ display: inline-block;
+ color: white;
+ /* border-right: 2px solid green; */
+ background: #8FD288;
+ padding: 3px;
+}
+.duration-invisible {
+ visibility: hidden;
+}
+.duration-value {
+ float: right;
+}
+.bar-outer-text {
+ color: #8FD288;
+ background: none;
+ float: none;
+ border: none;
+}
+.thumbsize {
+ width: 200px;
+ height: 200px;
+ padding: 0;
+}
\ No newline at end of file
diff --git a/erpnext/public/less/website.less b/erpnext/public/less/website.less
index a645f28..b816354 100644
--- a/erpnext/public/less/website.less
+++ b/erpnext/public/less/website.less
@@ -320,4 +320,33 @@
.product-image-wrapper {
padding-bottom: 40px;
+}
+
+.duration-bar {
+ display: inline-block;
+ color: white;
+ /* border-right: 2px solid green; */
+ background: #8FD288;
+ padding: 3px;
+}
+
+.duration-invisible {
+ visibility: hidden;
+}
+
+.duration-value {
+ float: right;
+}
+
+.bar-outer-text {
+ color: #8FD288;
+ background: none;
+ float: none;
+ border: none;
+}
+
+.thumbsize {
+ width: 200px;
+ height: 200px;
+ padding: 0;
}
\ No newline at end of file
diff --git a/erpnext/templates/generators/bom.html b/erpnext/templates/generators/bom.html
index 46dea6e..f514f2d 100644
--- a/erpnext/templates/generators/bom.html
+++ b/erpnext/templates/generators/bom.html
@@ -8,48 +8,50 @@
{% block page_content %}
{% from "erpnext/templates/includes/macros.html" import product_image %}
-<div class="item-content" style="margin-top:20px;">
- <div class="product-page-content" itemscope itemtype="http://schema.org/Product">
+{% from "erpnext/templates/includes/macros.html" import media_image %}
+<div class="bom-content" style="margin-top:20px;">
+ <div class="bom-page-content" itemscope itemtype="http://schema.org/Product">
<div class="row">
- <div class="col-sm-6">
- {% if slideshow %}
- {% include "templates/includes/slideshow.html" %}
- {% else %}
- {{ product_image(website_image, "product-full-image") }}
- {% endif %}
- </div>
- <div class="col-sm-6" style="padding-left:20px;">
- <h2 itemprop="name" style="margin-top: 0px;">{{ name }}</h2>
+ <div class="col-sm-12">
+ <h2 itemprop="name" style="margin-top: 0px;">{{ name }}</h2>
<p class="text-muted">
- {{ _("Item Name") }}: <span itemprop="itemName">{{ item_name }}</span></p>
- <br>
- <!--{{ _("Item Code") }}: <span itemprop="productID">{{ item_code }}</span></p>-->
- <div class="h6 text-uppercase">{{ _("Description") }}</div>
- <div itemprop="description" class="item-desc">
- {{ web_long_description or description or _("No description given") }}</div>
- <br>
- <div class="h6 text-uppercase">{{ _("Quantity") }}</div>
- <div itemprop="quantity" class="item-desc">{{ quantity }}</div>
+ {{ _("Item") }}: <span itemprop="itemName">{{ item_name }}</span></p>
<br>
</div>
</div>
-
- </div>
+ <div class="row">
+ <div class="col-sm-6">
+ {{ product_image(website_image, "product-full-image") }}
+ <br>
+ <p>{{ _("Quantity") }}: <span itemprop="productID">{{ quantity }}</span></p>
+ <br>
+ </div>
</div>
{% if show_items -%}
<div class="row items" style="margin-top: 40px">
<div class="col-md-12">
- <div class="h6 text-uppercase">{{ _("Items") }}</div>
-
+ <h3>{{ _("Items") }}</h3>
<table class="table borderless" style="width: 100%">
- {% for d in website_items -%}
<tr>
- <td class="uppercase text-muted" style="width: 30%;">{{ d.item_name }}</td>
- <td>{{ d.item_code }}</td>
- <td>{{ d.description }}</td>
+ <th></th>
+ <th></th>
+ <th>{{ _("Qty") }}</th>
+ </tr>
+ {% for d in items -%}
+ <tr>
+ <td>{{ media_image(d.image, "product-full-image") }}</td>
+ <td><div><b>{{ d.item_name }}</b></div>
+ {% if d.item_name != d.item_code -%}
+ <div class="text-muted">{{ d.item_code }}</div>
+ {% else -%}
+
+ {%- endif %}
+ <br>
+ {{ d.description }}
+ </td>
<td>{{ d.qty }}</td>
</tr>
{%- endfor %}
@@ -61,15 +63,25 @@
{% if show_operations -%}
<div class="row operations" style="margin-top: 40px">
<div class="col-md-12">
- <div class="h6 text-uppercase">{{ _("Operations") }}</div>
-
+ <h3>{{ _("Operations") }}</h3>
<table class="table borderless" style="width: 100%">
- {% for d in website_operations -%}
<tr>
- <td class="uppercase text-muted" style="width: 30%;">{{ d.operation }}</td>
+ <th></th>
+ <th style="padding:8px 20px;"></th>
+
+ <th>{{ _("Workstation") }}</th>
+ <th style="width: 20%;">{{ _("Time(in mins)") }}</th>
+ </tr>
+ {% for d in operations -%}
+ <tr>
+ <td>{{ media_image(d.image, d.operation, "product-full-image") }}</td>
+ <td style="padding:8px 20px;"><div>{{ d.operation }}</div>
+ <div class="text-muted">{{ d.description }}</div>
+ </td>
+
<td>{{ d.workstation }}</td>
- <td>{{ d.time_in_mins }}</td>
- <td>{{ d.website_image }}</td>
+ <td class="duration" style="width: 20%;"><span class="duration-bar">
+ <span class="duration-value">{{ d.time_in_mins }}</span></span></td>
</tr>
{%- endfor %}
</table>
@@ -77,6 +89,39 @@
</div>
{%- endif %}
+ <div class="row" style="margin-top: 30px;">
+ <div class="col-sm-12">
+ <br>
+ <div class="h6 text-uppercase">{{ _("Description") }}</div>
+ <div itemprop="description" class="item-desc">
+ {{ web_long_description or _("No description given") }}</div>
+ <br>
+
+ </div>
+ </div>
+
</div>
</div>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
+<script>
+ var max_width = $(".duration").width() * 0.8;
+ var durations = [];
+ $(".duration .duration-bar").each(function() {
+ durations.push($(this).find(".duration-value").html());
+ });
+ var max_duration = Math.max(...durations);
+ var width_factor = max_width/max_duration;
+
+ $(".duration .duration-bar").each(function() {
+ var duration = $(this).find(".duration-value").html();
+ $(this).width(duration * width_factor);
+ if($(this).width() < $(this).find(".duration-value").width()) {
+ var html = $($(this).html());
+ html.addClass("duration-bar");
+ html.addClass("bar-outer-text");
+ $(this).find(".duration-value").removeClass("duration-value").addClass("duration-invisible");
+ $(this).closest("td").append(html);
+ }
+ });
+</script>
{% endblock %}
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index 675b7af..db194b2 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -19,3 +19,26 @@
{%- endif %}
</div>
{% endmacro %}
+
+{% macro media_image(website_image, name, css_class="") %}
+{% if website_image -%}
+ <meta itemprop="image" content="{{ frappe.utils.quoted(website_image) | abs_url }}"></meta>
+{%- endif %}
+<div class="product-image product-image-square thumbsize {{ css_class }}"
+ {% if not website_image -%}{{ name }}{%- endif %}
+ {% if website_image -%}
+ style="background-image: url('{{ frappe.utils.quoted(website_image) | abs_url }}');"
+ {%- endif %}>
+</div>
+{% endmacro %}
+
+{% macro bom_image(website_image, name, css_class="") %}
+ <div class="product-image {{ css_class }}">
+ {% if not website_image -%}{{ name }}{%- endif %}
+ {% if website_image -%}
+ <a href="{{ frappe.utils.quoted(website_image) }}">
+ <img itemprop="image" src="{{ frappe.utils.quoted(website_image) | abs_url }}" class="img-responsive">
+ </a>
+ {%- endif %}
+ </div>
+{% endmacro %}
diff --git a/erpnext/templates/pages/home.html b/erpnext/templates/pages/home.html
index b91cd73..750fa38 100644
--- a/erpnext/templates/pages/home.html
+++ b/erpnext/templates/pages/home.html
@@ -18,7 +18,7 @@
<a class="product-link" href="{{ item.route|abs_url }}">
<div class="col-sm-4 col-xs-4 product-image-wrapper">
<div class="product-image-img">
- {{ product_image_square(item.thumbnail or item.image) }}
+ {{ product_image_square(item.thumbnail or item.image) }}
<div class="product-text" itemprop="name">{{ item.item_name }}</div>
</div>
</div>