Merge branch 'develop'

This commit is contained in:
Nabin Hait 2015-10-29 16:35:06 +05:30
commit baefec4498
28 changed files with 195 additions and 72 deletions

View File

@ -1,2 +1,2 @@
from __future__ import unicode_literals
__version__ = '6.6.6'
__version__ = '6.6.7'

View File

@ -699,13 +699,15 @@ def get_payment_entry_from_purchase_order(purchase_order):
def get_payment_entry(doc):
bank_account = get_default_bank_cash_account(doc.company, "Bank Entry")
cost_center = frappe.db.get_value("Company", doc.company, "cost_center")
jv = frappe.new_doc('Journal Entry')
jv.voucher_type = 'Bank Entry'
jv.company = doc.company
jv.fiscal_year = doc.fiscal_year
jv.append("accounts")
d1 = jv.append("accounts")
d1.cost_center = cost_center
d2 = jv.append("accounts")
if bank_account:
@ -715,6 +717,7 @@ def get_payment_entry(doc):
d2.account_type = bank_account["account_type"]
d2.exchange_rate = get_exchange_rate(bank_account["account"],
bank_account["account_currency"], doc.company)
d2.cost_center = cost_center
return jv

View File

@ -42,6 +42,8 @@ class PurchaseCommon(BuyingController):
items = []
for d in obj.get("items"):
if not d.qty:
if obj.doctype == "Purchase Receipt" and d.rejected_qty:
continue
frappe.throw(_("Please enter quantity for Item {0}").format(d.item_code))
# udpate with latest quantities
@ -56,11 +58,11 @@ class PurchaseCommon(BuyingController):
d.set(x, f_lst[x])
item = frappe.db.sql("""select is_stock_item, is_purchase_item,
is_sub_contracted_item, end_of_life from `tabItem` where name=%s""",
is_sub_contracted_item, end_of_life, disabled from `tabItem` where name=%s""",
d.item_code, as_dict=1)[0]
from erpnext.stock.doctype.item.item import validate_end_of_life
validate_end_of_life(d.item_code, item.end_of_life)
validate_end_of_life(d.item_code, item.end_of_life, item.disabled)
# validate stock item
if item.is_stock_item==1 and d.qty and not d.warehouse:
@ -72,6 +74,7 @@ class PurchaseCommon(BuyingController):
frappe.throw(_("{0} must be a Purchased or Sub-Contracted Item in row {1}").format(d.item_code, d.idx))
items.append(cstr(d.item_code))
if items and len(items) != len(set(items)) and \
not cint(frappe.db.get_single_value("Buying Settings", "allow_multiple_items") or 0):
frappe.msgprint(_("Warning: Same item has been entered multiple times."))

View File

@ -166,6 +166,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters):
from tabItem
where tabItem.docstatus < 2
and ifnull(tabItem.has_variants, 0)=0
and tabItem.disabled=0
and (tabItem.end_of_life > %(today)s or ifnull(tabItem.end_of_life, '0000-00-00')='0000-00-00')
and (tabItem.`{key}` LIKE %(txt)s
or tabItem.item_name LIKE %(txt)s
@ -303,10 +304,10 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
# Hence the first condition is an "OR"
if not filters: filters = {}
condition = ""
condition = ""
if filters.get("company"):
condition += "and tabAccount.company = %(company)s"
return frappe.db.sql("""select tabAccount.name from `tabAccount`
where (tabAccount.report_type = "Profit and Loss"
or tabAccount.account_type in ("Income Account", "Temporary"))
@ -314,6 +315,6 @@ def get_income_account(doctype, txt, searchfield, start, page_len, filters):
and tabAccount.`{key}` LIKE %(txt)s
{condition} {match_condition}"""
.format(condition=condition, match_condition=get_match_cond(doctype), key=searchfield), {
'txt': "%%%s%%" % frappe.db.escape(txt),
'txt': "%%%s%%" % frappe.db.escape(txt),
'company': filters.get("company", "")
})
})

View File

@ -29,7 +29,7 @@ blogs.
"""
app_icon = "icon-th"
app_color = "#e74c3c"
app_version = "6.6.6"
app_version = "6.6.7"
github_link = "https://github.com/frappe/erpnext"
error_report_email = "support@erpnext.com"

View File

@ -140,7 +140,7 @@ erpnext.production_order = {
} else msgprint(__("Please enter Production Item first"));
});
},
set_default_warehouse: function(frm) {
frappe.call({
method: "erpnext.manufacturing.doctype.production_order.production_order.get_default_warehouse",

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import flt, get_datetime, getdate, date_diff, cint
from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
from frappe import _
from frappe.model.document import Document
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
@ -159,22 +159,22 @@ class ProductionOrder(Document):
def on_cancel(self):
self.validate_cancel()
frappe.db.set(self,'status', 'Cancelled')
self.update_planned_qty()
self.delete_time_logs()
def validate_cancel(self):
if self.status == "Stopped":
frappe.throw(_("Stopped Production Order cannot be cancelled, Unstop it first to cancel"))
# Check whether any stock entry exists against this Production Order
stock_entry = frappe.db.sql("""select name from `tabStock Entry`
where production_order = %s and docstatus = 1""", self.name)
if stock_entry:
frappe.throw(_("Cannot cancel because submitted Stock Entry {0} exists").format(stock_entry[0][0]))
def update_planned_qty(self):
def update_planned_qty(self):
update_bin_qty(self.production_item, self.fg_warehouse, {
"planned_qty": get_planned_qty(self.production_item, self.fg_warehouse)
})
@ -342,8 +342,8 @@ class ProductionOrder(Document):
@frappe.whitelist()
def get_item_details(item):
res = frappe.db.sql("""select stock_uom, description
from `tabItem` where (ifnull(end_of_life, "0000-00-00")="0000-00-00" or end_of_life > now())
and name=%s""", item, as_dict=1)
from `tabItem` where disabled=0 and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)
and name=%s""", (nowdate(), item), as_dict=1)
if not res:
return {}

View File

@ -86,7 +86,7 @@ class TestProductionOrder(unittest.TestCase):
self.assertEqual(prod_order.name, time_log.production_order)
self.assertEqual((prod_order.qty - d.completed_qty), time_log.completed_qty)
self.assertEqual(time_diff_in_hours(d.planned_end_time, d.planned_start_time),time_log.hours)
manufacturing_settings = frappe.get_doc({
"doctype": "Manufacturing Settings",
"allow_production_on_holidays": 0
@ -136,6 +136,11 @@ class TestProductionOrder(unittest.TestCase):
self.assertRaises(frappe.ValidationError, prod_order.save)
frappe.db.set_value("Item", "_Test FG Item", "end_of_life", None)
frappe.db.set_value("Item", "_Test FG Item", "disabled", 1)
self.assertRaises(frappe.ValidationError, prod_order.save)
frappe.db.set_value("Item", "_Test FG Item", "disabled", 0)
prod_order = make_prod_order_test_record(item="_Test Variant Item", qty=1, do_not_save=True)
self.assertRaises(ItemHasVariantError, prod_order.save)

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 KiB

View File

@ -4,6 +4,7 @@
from __future__ import unicode_literals
import frappe
import urllib
from frappe.utils import nowdate
from frappe.utils.nestedset import NestedSet
from frappe.website.website_generator import WebsiteGenerator
from frappe.website.render import clear_cache
@ -71,14 +72,16 @@ def get_product_list_for_group(product_group=None, start=0, limit=10):
concat(parent_website_route, "/", page_name) as route
from `tabItem`
where show_in_website = 1
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %(today)s)
and (variant_of = '' or variant_of is null)
and (item_group in (%s)
or name in (select parent from `tabWebsite Item Group` where item_group in (%s)))
""" % (child_groups, child_groups)
and (item_group in ({child_groups})
or name in (select parent from `tabWebsite Item Group` where item_group in ({child_groups})))
""".format(child_groups=child_groups)
query += """order by weightage desc, modified desc limit %s, %s""" % (start, limit)
data = frappe.db.sql(query, {"product_group": product_group}, as_dict=1)
data = frappe.db.sql(query, {"product_group": product_group, "today": nowdate()}, as_dict=1)
return [get_item_for_list_in_html(r) for r in data]

View File

@ -658,7 +658,7 @@ $.extend(erpnext.wiz, {
return frappe.render_template("setup_wizard_message", {
image: "/assets/frappe/images/ui/bubble-tea-happy.svg",
title: __('Setup Complete'),
message: __('Your setup is complete. Refreshing.') + ".."
message: ""
});
},
@ -670,6 +670,7 @@ $.extend(erpnext.wiz, {
args: values,
callback: function(r) {
wiz.show_complete();
localStorage.setItem("session_last_route", "#welcome-to-erpnext");
setTimeout(function() {
window.location = "/desk";
}, 2000);

View File

@ -0,0 +1,13 @@
#page-welcome-to-erpnext ul li {
margin: 7px 0px;
}
#page-welcome-to-erpnext .video-placeholder-image {
width: 100%;
cursor: pointer;
}
#page-welcome-to-erpnext .youtube-icon {
width: 10%;
cursor: pointer;
}

View File

@ -0,0 +1,31 @@
<div class="container welcome-to-erpnext text-center" style="padding: 30px 0px;">
<div class="row">
<div class="col-md-8 col-md-push-2 col-sm-12">
<h1>{%= __("Welcome to ERPNext") %}</h1>
<p class="text-muted">
{%= __("To get the best out of ERPNext, we recommend that you take some time and watch these help videos.") %}
<br><br>
</p>
<div class="embed-responsive embed-responsive-16by9">
<div class="video-placeholder embed-responsive-item">
<img class="video-placeholder-image"
src="/assets/erpnext/images/erpnext-video-placeholder.jpg">
<img class="centered youtube-icon"
src="/assets/erpnext/images/YouTube-icon-full_color.png">
</div>
</div>
<br>
<hr>
<h3>Next Steps</h3>
<ul class="list-unstyled">
<li><a class="text-muted" href="#">{%= __("Go to the Desktop and start using ERPNext") %}</a></li>
<li><a class="text-muted" href="#Module/Learn">{%= __("View a list of all the help videos") %}</a></li>
<li><a class="text-muted" href="https://manual.erpnext.com" target="_blank">{%= __("Read the ERPNext Manual") %}</a></li>
<li><a class="text-muted" href="https://discuss.erpnext.com" target="_blank">{%= __("Community Forum") %}</a></li>
</ul>
</div>
</div>
</div>

View File

@ -0,0 +1,10 @@
frappe.pages['welcome-to-erpnext'].on_page_load = function(wrapper) {
var parent = $('<div class="welcome-to-erpnext"></div>').appendTo(wrapper);
parent.html(frappe.render_template("welcome_to_erpnext", {}));
parent.find(".video-placeholder").on("click", function() {
parent.find(".video-placeholder").addClass("hidden");
parent.find(".embed-responsive").append('<iframe class="embed-responsive-item video-playlist" src="https://www.youtube.com/embed/videoseries?list=PL3lFfCEoMxvxDHtYyQFJeUYkWzQpXwFM9&color=white&autoplay=1" allowfullscreen></iframe>')
});
}

View File

@ -0,0 +1,17 @@
{
"content": null,
"creation": "2015-10-28 16:27:02.197707",
"docstatus": 0,
"doctype": "Page",
"modified": "2015-10-28 16:27:02.197707",
"modified_by": "Administrator",
"module": "Setup",
"name": "welcome-to-erpnext",
"owner": "Administrator",
"page_name": "welcome-to-erpnext",
"roles": [],
"script": null,
"standard": "Yes",
"style": null,
"title": "Welcome to ERPNext"
}

View File

@ -178,31 +178,6 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "2099-12-31",
"depends_on": "is_stock_item",
"fieldname": "end_of_life",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "End of Life",
"no_copy": 0,
"oldfieldname": "end_of_life",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -249,6 +224,28 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"fieldname": "disabled",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Disabled",
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -436,6 +433,31 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"default": "2099-12-31",
"depends_on": "is_stock_item",
"fieldname": "end_of_life",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "End of Life",
"no_copy": 0,
"oldfieldname": "end_of_life",
"oldfieldtype": "Date",
"permlevel": 0,
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -2113,7 +2135,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
"modified": "2015-10-20 12:14:43.315827",
"modified": "2015-10-29 02:25:26.256373",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",

View File

@ -245,7 +245,7 @@ class Item(WebsiteGenerator):
# loop through previous attributes
for prev_attr in self.attributes[:i]:
combination_source.append([context.selected_attributes[prev_attr.attribute]])
combination_source.append([context.selected_attributes.get(prev_attr.attribute)])
combination_source.append(context.attribute_values[attr.attribute])
@ -524,14 +524,17 @@ class Item(WebsiteGenerator):
if variant and self.get("__islocal"):
frappe.throw(_("Item variant {0} exists with same attributes").format(variant), ItemVariantExistsError)
def validate_end_of_life(item_code, end_of_life=None, verbose=1):
if not end_of_life:
end_of_life = frappe.db.get_value("Item", item_code, "end_of_life")
def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1):
if (not end_of_life) or (disabled is None):
end_of_life, disabled = frappe.db.get_value("Item", item_code, ["end_of_life", "disabled"])
if end_of_life and end_of_life!="0000-00-00" and getdate(end_of_life) <= now_datetime().date():
msg = _("Item {0} has reached its end of life on {1}").format(item_code, formatdate(end_of_life))
_msgprint(msg, verbose)
if disabled:
_msgprint(_("Item {0} is disabled").format(item_code), verbose)
def validate_is_stock_item(item_code, is_stock_item=None, verbose=1):
if not is_stock_item:
is_stock_item = frappe.db.get_value("Item", item_code, "is_stock_item")

View File

@ -1,16 +1,18 @@
frappe.listview_settings['Item'] = {
add_fields: ["item_name", "stock_uom", "item_group", "image", "variant_of",
"has_variants", "end_of_life", "is_sales_item"],
"has_variants", "end_of_life", "disabled", "is_sales_item"],
get_indicator: function(doc) {
if(doc.end_of_life && doc.end_of_life < frappe.datetime.get_today()) {
return [__("Expired"), "grey", "end_of_life,<,Today"]
} else if(doc.has_variants) {
return [__("Template"), "blue", "has_variants,=,Yes"]
} else if(doc.variant_of) {
return [__("Variant"), "green", "variant_of,=," + doc.variant_of]
if (doc.disabled) {
return [__("Disabled"), "grey", "disabled,=,Yes"];
} else if (doc.end_of_life && doc.end_of_life < frappe.datetime.get_today()) {
return [__("Expired"), "grey", "end_of_life,<,Today"];
} else if (doc.has_variants) {
return [__("Template"), "blue", "has_variants,=,Yes"];
} else if (doc.variant_of) {
return [__("Variant"), "green", "variant_of,=," + doc.variant_of];
} else {
return [__("Active"), "blue", "end_of_life,>=,Today"]
return [__("Active"), "blue", "end_of_life,>=,Today"];
}
}
};

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe
import frappe.defaults
from frappe import _
from frappe.utils import cstr, cint, flt, comma_or, getdate
from frappe.utils import cstr, cint, flt, comma_or, getdate, nowdate
from erpnext.stock.utils import get_incoming_rate
from erpnext.stock.stock_ledger import get_previous_sle, NegativeStockError
from erpnext.stock.get_item_details import get_available_qty, get_default_cost_center, get_conversion_factor
@ -359,7 +359,7 @@ class StockEntry(StockController):
def update_stock_ledger(self):
sl_entries = []
# make sl entries for source warehouse first, then do for target warehouse
for d in self.get('items'):
if cstr(d.s_warehouse):
@ -368,7 +368,7 @@ class StockEntry(StockController):
"actual_qty": -flt(d.transfer_qty),
"incoming_rate": 0
}))
for d in self.get('items'):
if cstr(d.t_warehouse):
sl_entries.append(self.get_sl_entries(d, {
@ -438,8 +438,10 @@ class StockEntry(StockController):
def get_item_details(self, args=None, for_update=False):
item = frappe.db.sql("""select stock_uom, description, image, item_name,
expense_account, buying_cost_center, item_group from `tabItem`
where name = %s and (ifnull(end_of_life,'0000-00-00')='0000-00-00' or end_of_life > now())""",
(args.get('item_code')), as_dict = 1)
where name = %s
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)""",
(args.get('item_code'), nowdate()), as_dict = 1)
if not item:
frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get("item_code")))

View File

@ -130,7 +130,7 @@ class StockReconciliation(StockController):
item = frappe.get_doc("Item", item_code)
# end of life and stock item
validate_end_of_life(item_code, item.end_of_life, verbose=0)
validate_end_of_life(item_code, item.end_of_life, item.disabled, verbose=0)
validate_is_stock_item(item_code, item.is_stock_item, verbose=0)
# item should not be serialized

View File

@ -113,7 +113,7 @@ def validate_item_details(args, item):
throw(_("Please specify Company"))
from erpnext.stock.doctype.item.item import validate_end_of_life
validate_end_of_life(item.name, item.end_of_life)
validate_end_of_life(item.name, item.end_of_life, item.disabled)
if args.transaction_type == "selling":
# validate if sales item or service item

View File

@ -23,6 +23,7 @@ def _reorder_item():
items_to_consider = frappe.db.sql_list("""select name from `tabItem` item
where is_stock_item=1 and has_variants=0
and (is_purchase_item=1 or is_sub_contracted_item=1)
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %(today)s)
and ((re_order_level is not null and re_order_level > 0)
or exists (select name from `tabItem Reorder` ir where ir.parent=item.name)

View File

@ -79,6 +79,7 @@ def get_item_map(item_code):
items = frappe.db.sql("""select * from `tabItem` item
where is_stock_item = 1
and disabled=0
{condition}
and (end_of_life > %(today)s or end_of_life is null or end_of_life='0000-00-00')
and exists (select name from `tabBin` bin where bin.item_code=item.name)"""\

View File

@ -24,7 +24,7 @@
{{ web_long_description or description or _("No description given") }}
</div>
<p class="text-muted">
{{ _("Item Code") }}: <span itemprop="productID">{{ name }}</span></p>
{{ _("Item Code") }}: <span itemprop="productID">{{ variant and variant.name or name }}</span></p>
<br>
<div class="item-attribute-selectors">
{% if has_variants %}

View File

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr
from frappe.utils import cstr, nowdate
from erpnext.setup.doctype.item_group.item_group import get_item_for_list_in_html
no_cache = 1
@ -14,7 +14,11 @@ def get_product_list(search=None, start=0, limit=10):
# base query
query = """select name, item_name, page_name, website_image, thumbnail, item_group,
web_long_description as website_description, parent_website_route
from `tabItem` where show_in_website = 1 and (variant_of is null or variant_of = '')"""
from `tabItem`
where show_in_website = 1
and disabled=0
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %(today)s)
and (variant_of is null or variant_of = '')"""
# search term condition
if search:
@ -29,6 +33,7 @@ def get_product_list(search=None, start=0, limit=10):
data = frappe.db.sql(query, {
"search": search,
"today": nowdate()
}, as_dict=1)
for d in data:

View File

@ -1,6 +1,6 @@
from setuptools import setup, find_packages
version = "6.6.6"
version = "6.6.7"
with open("requirements.txt", "r") as f:
install_requires = f.readlines()