diff --git a/erpnext/__init__.py b/erpnext/__init__.py index a7ae6e1f7c..2de394c155 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals import frappe -__version__ = '7.2.21' +__version__ = '7.2.22' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index a8d166eef1..8aedf78fef 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -7,7 +7,7 @@ import frappe import datetime from frappe import _, msgprint, scrub from frappe.defaults import get_user_permissions -from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, add_years +from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff, add_years, get_timestamp from frappe.geo.doctype.address.address import get_address_display, get_default_address from frappe.email.doctype.contact.contact import get_contact_details, get_default_contact from erpnext.exceptions import PartyFrozen, InvalidCurrency, PartyDisabled, InvalidAccountCurrency @@ -353,8 +353,17 @@ def validate_party_frozen_disabled(party_type, party_name): def get_timeline_data(doctype, name): '''returns timeline data for the past one year''' from frappe.desk.form.load import get_communication_data + + out = {} data = get_communication_data(doctype, name, - fields = 'unix_timestamp(date(creation)), count(name)', - after = add_years(None, -1).strftime('%Y-%m-%d'), limit = 366, + fields = 'date(creation), count(name)', + after = add_years(None, -1).strftime('%Y-%m-%d'), group_by='group by date(creation)', as_dict=False) - return dict(data) \ No newline at end of file + + timeline_items = dict(data) + + for date, count in timeline_items.iteritems(): + timestamp = get_timestamp(date) + out.update({ timestamp: count }) + + return out \ No newline at end of file diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index c4ba9e7b1d..1d1b4e2198 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -178,6 +178,9 @@ class BuyingController(StockController): for item in self.get("items"): item.rm_supp_cost = 0.0 + if self.is_subcontracted == "No" and self.get("supplied_items"): + self.set('supplied_items', []) + def update_raw_materials_supplied(self, item, raw_material_table): bom_items = self.get_items_from_bom(item.item_code, item.bom) raw_materials_cost = 0 diff --git a/erpnext/patches.txt b/erpnext/patches.txt index e041a2b517..d4ba1193e9 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -370,4 +370,5 @@ erpnext.patches.v7_2.set_null_value_to_fields erpnext.patches.v7_2.update_guardian_name_in_student_master erpnext.patches.v7_2.update_abbr_in_salary_slips erpnext.patches.v7_2.rename_evaluation_criteria -erpnext.patches.v7_2.update_party_type \ No newline at end of file +erpnext.patches.v7_2.update_party_type +erpnext.patches.v7_2.empty_supplied_items_for_non_subcontracted diff --git a/erpnext/patches/v7_2/empty_supplied_items_for_non_subcontracted.py b/erpnext/patches/v7_2/empty_supplied_items_for_non_subcontracted.py new file mode 100644 index 0000000000..ec6f8afc3a --- /dev/null +++ b/erpnext/patches/v7_2/empty_supplied_items_for_non_subcontracted.py @@ -0,0 +1,14 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for doctype in ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]: + child_table = 'Purchase Receipt Item Supplied' if doctype != 'Purchase Order' else 'Purchase Order Item Supplied' + for data in frappe.db.sql(""" select distinct `tab{doctype}`.name from `tab{doctype}` , `tab{child_table}` + where `tab{doctype}`.name = `tab{child_table}`.parent and `tab{doctype}`.docstatus != 2 + and `tab{doctype}`.is_subcontracted = 'No' """.format(doctype = doctype, child_table = child_table), as_dict=1): + frappe.db.sql(""" delete from `tab{child_table}` + where parent = %s and parenttype = %s""".format(child_table= child_table), (data.name, doctype)) \ No newline at end of file diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index 56bc27e119..658c4fe00d 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -100,7 +100,12 @@ function load_erpnext_slides() { fy = ["01-01", "12-31"]; next_year = current_year; } - + + var year_start_date = current_year + "-" + fy[0]; + if(year_start_date > get_today()) { + next_year = current_year + current_year -= 1; + } slide.get_field("fy_start_date").set_input(current_year + "-" + fy[0]); slide.get_field("fy_end_date").set_input(next_year + "-" + fy[1]); } diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 03c23d2acc..439c729a91 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -4,6 +4,13 @@ frappe.provide("erpnext.item"); frappe.ui.form.on("Item", { + setup: function(frm) { + frm.add_fetch('attribute', 'numeric_values', 'numeric_values'); + frm.add_fetch('attribute', 'from_range', 'from_range'); + frm.add_fetch('attribute', 'to_range', 'to_range'); + frm.add_fetch('attribute', 'increment', 'increment'); + frm.add_fetch('tax_type', 'tax_rate', 'tax_rate'); + }, onload: function(frm) { erpnext.item.setup_queries(frm); if (frm.doc.variant_of){ @@ -16,7 +23,6 @@ frappe.ui.form.on("Item", { }, refresh: function(frm) { - if(frm.doc.is_stock_item) { frm.add_custom_button(__("Balance"), function() { frappe.route_options = { @@ -54,9 +60,9 @@ frappe.ui.form.on("Item", { }, __("View")); frm.add_custom_button(__("Variant"), function() { - erpnext.item.make_variant() + erpnext.item.make_variant(frm); }, __("Make")); - cur_frm.page.set_inner_btn_group_as_primary(__("Make")); + frm.page.set_inner_btn_group_as_primary(__("Make")); } if (frm.doc.variant_of) { frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set", [frm.doc.variant_of]), true); @@ -79,6 +85,17 @@ frappe.ui.form.on("Item", { frm.toggle_enable("is_fixed_asset", (frm.doc.__islocal || (!frm.doc.is_stock_item && ((frm.doc.__onload && frm.doc.__onload.asset_exists) ? false : true)))); + + frm.add_custom_button(__('Duplicate'), function() { + var new_item = frappe.model.copy_doc(frm.doc); + if(new_item.item_name===new_item.item_code) { + new_item.item_name = null; + } + if(new_item.description===new_item.description) { + new_item.description = null; + } + frappe.set_route('Form', 'Item', new_item.name); + }); }, validate: function(frm){ @@ -218,7 +235,8 @@ $.extend(erpnext.item, { return; frappe.require('assets/js/item-dashboard.min.js', function() { - var section = frm.dashboard.add_section('
' + __("Stock Levels") + '
'); + var section = frm.dashboard.add_section('
\ + ' + __("Stock Levels") + '
'); erpnext.item.item_dashboard = new erpnext.stock.ItemDashboard({ parent: section, item_code: frm.doc.name @@ -240,12 +258,12 @@ $.extend(erpnext.item, { } }, - make_variant: function(doc) { + make_variant: function(frm) { var fields = [] - for(var i=0;i< cur_frm.doc.attributes.length;i++){ + for(var i=0;i< frm.doc.attributes.length;i++){ var fieldtype, desc; - var row = cur_frm.doc.attributes[i]; + var row = frm.doc.attributes[i]; if (row.numeric_values){ fieldtype = "Float"; desc = "Min Value: "+ row.from_range +" , Max Value: "+ row.to_range +", in Increments of: "+ row.increment @@ -274,7 +292,7 @@ $.extend(erpnext.item, { frappe.call({ method:"erpnext.controllers.item_variant.get_variant", args: { - "template": cur_frm.doc.name, + "template": frm.doc.name, "args": d.get_values() }, callback: function(r) { @@ -296,7 +314,7 @@ $.extend(erpnext.item, { frappe.call({ method:"erpnext.controllers.item_variant.create_variant", args: { - "item": cur_frm.doc.name, + "item": frm.doc.name, "args": d.get_values() }, callback: function(r) { @@ -363,10 +381,3 @@ $.extend(erpnext.item, { frm.fields_dict.attributes.grid.toggle_enable("attribute_value", !frm.doc.variant_of); } }); - - -cur_frm.add_fetch('attribute', 'numeric_values', 'numeric_values'); -cur_frm.add_fetch('attribute', 'from_range', 'from_range'); -cur_frm.add_fetch('attribute', 'to_range', 'to_range'); -cur_frm.add_fetch('attribute', 'increment', 'increment'); -cur_frm.add_fetch('tax_type', 'tax_rate', 'tax_rate'); diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 6de497f43d..c11980639d 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -90,7 +90,7 @@ "in_standard_filter": 0, "label": "Item Code", "length": 0, - "no_copy": 1, + "no_copy": 0, "oldfieldname": "item_code", "oldfieldtype": "Data", "permlevel": 0, @@ -138,7 +138,7 @@ }, { "allow_on_submit": 0, - "bold": 0, + "bold": 1, "collapsible": 0, "columns": 0, "fieldname": "item_name", @@ -161,7 +161,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 1, "set_only_once": 0, "unique": 0 @@ -2804,7 +2804,7 @@ "issingle": 0, "istable": 0, "max_attachments": 1, - "modified": "2017-02-14 22:49:44.664910", + "modified": "2017-02-17 04:00:38.825621", "modified_by": "Administrator", "module": "Stock", "name": "Item", diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index d20ba49763..0f0205bae1 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -7,7 +7,7 @@ import erpnext import json import itertools from frappe import msgprint, _ -from frappe.utils import cstr, flt, cint, getdate, now_datetime, formatdate, strip +from frappe.utils import cstr, flt, cint, getdate, now_datetime, formatdate, strip, get_timestamp from frappe.website.website_generator import WebsiteGenerator from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for, get_parent_item_groups from frappe.website.render import clear_cache @@ -63,6 +63,9 @@ class Item(WebsiteGenerator): def validate(self): super(Item, self).validate() + if not self.item_name: + self.item_name = self.item_code + if not self.description: self.description = self.item_name @@ -470,12 +473,12 @@ class Item(WebsiteGenerator): def check_if_linked_document_exists(self, key): linked_doctypes = ["Delivery Note Item", "Sales Invoice Item", "Purchase Receipt Item", "Purchase Invoice Item", "Stock Entry Detail", "Stock Reconciliation Item"] - - # For "Is Stock Item", following doctypes is important + + # For "Is Stock Item", following doctypes is important # because reserved_qty, ordered_qty and requested_qty updated from these doctypes if key == "is_stock_item": linked_doctypes += ["Sales Order Item", "Purchase Order Item", "Material Request Item"] - + for doctype in linked_doctypes: if frappe.db.get_value(doctype, filters={"item_code": self.name, "docstatus": 1}) or \ frappe.db.get_value("Production Order", @@ -667,10 +670,17 @@ class Item(WebsiteGenerator): def get_timeline_data(doctype, name): '''returns timeline data based on stock ledger entry''' - return dict(frappe.db.sql('''select unix_timestamp(posting_date), count(*) + out = {} + items = dict(frappe.db.sql('''select posting_date, count(*) from `tabStock Ledger Entry` where item_code=%s and posting_date > date_sub(curdate(), interval 1 year) group by posting_date''', name)) + + for date, count in items.iteritems(): + timestamp = get_timestamp(date) + out.update({ timestamp: count }) + + return out def validate_end_of_life(item_code, end_of_life=None, disabled=None, verbose=1): if (not end_of_life) or (disabled is None): diff --git a/erpnext/stock/doctype/item_price/item_price.json b/erpnext/stock/doctype/item_price/item_price.json index 5f0826248d..0685c80438 100644 --- a/erpnext/stock/doctype/item_price/item_price.json +++ b/erpnext/stock/doctype/item_price/item_price.json @@ -69,6 +69,33 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "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 + }, { "allow_on_submit": 0, "bold": 0, @@ -151,6 +178,34 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "currency", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Currency", + "length": 0, + "no_copy": 0, + "options": "Currency", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -211,34 +266,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "currency", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Currency", - "length": 0, - "no_copy": 0, - "options": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_on_submit": 0, "bold": 0, @@ -318,61 +345,6 @@ "search_index": 0, "set_only_once": 0, "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_12", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "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 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "bulk_import_help", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Bulk Import Help", - "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, @@ -386,7 +358,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-12-15 14:52:09.842544", + "modified": "2017-02-17 04:24:30.453863", "modified_by": "Administrator", "module": "Stock", "name": "Item Price", @@ -435,7 +407,7 @@ "write": 1 } ], - "quick_entry": 0, + "quick_entry": 1, "read_only": 0, "read_only_onload": 0, "sort_order": "ASC",