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>