Website data from existing child tables, layout, images
This commit is contained in:
parent
dee36e10ae
commit
60fe77cc90
@ -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",
|
||||
|
@ -54,6 +54,8 @@ class BOM(WebsiteGenerator):
|
||||
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 @@ class BOM(WebsiteGenerator):
|
||||
'item_code' : d.item_code,
|
||||
'item_name' : d.item_name,
|
||||
'description' : d.description,
|
||||
'qty' : d.qty,
|
||||
'website_image' : d.image
|
||||
}))
|
||||
|
||||
@ -495,6 +498,86 @@ class BOM(WebsiteGenerator):
|
||||
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')
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 %}
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user