diff --git a/.travis.yml b/.travis.yml index 66753374c7..d57b2d8a69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,4 +64,10 @@ jobs: - bench execute erpnext.setup.utils.enable_all_roles_and_domains - bench run-ui-tests --app erpnext env: Client Side Test + - # stage + script: + - wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz + - bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis + - bench migrate + env: Patch Testing diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index bbaa043208..e767ae7df6 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -29,7 +29,7 @@ class PurchaseOrder(BuyingController): 'target_field': 'ordered_qty', 'target_parent_dt': 'Material Request', 'target_parent_field': 'per_ordered', - 'target_ref_field': 'qty', + 'target_ref_field': 'stock_qty', 'source_field': 'stock_qty', 'percent_join_field': 'material_request', 'overflow_type': 'order' diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 53e2d2879c..fa1990f9cc 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -334,6 +334,7 @@ execute:frappe.reload_doctype('Employee') #2016-10-18 execute:frappe.db.sql("update `tabEmployee` set prefered_contact_email = IFNULL(prefered_contact_email,'') ") execute:frappe.reload_doctype("Salary Slip") execute:frappe.db.sql("update `tabSalary Slip` set posting_date=creation") +execute:frappe.reload_doc("stock", "doctype", "stock_settings") erpnext.patches.v8_0.create_domain_docs #16-05-2017 erpnext.patches.v7_1.update_portal_roles erpnext.patches.v7_1.set_total_amount_currency_in_je @@ -467,3 +468,4 @@ erpnext.patches.v9_2.delete_healthcare_domain_default_items erpnext.patches.v9_1.create_issue_opportunity_type erpnext.patches.v9_2.rename_translated_domains_in_en erpnext.patches.v9_0.set_shipping_type_for_existing_shipping_rules +erpnext.patches.v9_0.update_multi_uom_fields_in_material_request \ No newline at end of file diff --git a/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py b/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py index e7833c0f5c..c150cfa3e2 100644 --- a/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py +++ b/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py @@ -7,7 +7,9 @@ import frappe def execute(): doctype = 'POS Profile' frappe.reload_doc('accounts', 'doctype', doctype) - frappe.reload_doc('accounts', 'doctype', 'POS Profile User') + frappe.reload_doc('accounts', 'doctype', 'pos_profile_user') + frappe.reload_doc('accounts', 'doctype', 'pos_item_group') + frappe.reload_doc('accounts', 'doctype', 'pos_customer_group') for doc in frappe.get_all(doctype): _doc = frappe.get_doc(doctype, doc.name) @@ -19,4 +21,7 @@ def execute(): 'user': user }) _doc.pos_profile_name = user + ' - ' + _doc.company + _doc.flags.ignore_validate = True + _doc.flags.ignore_mandatory = True _doc.save() + diff --git a/erpnext/patches/v9_0/student_admission_childtable_migrate.py b/erpnext/patches/v9_0/student_admission_childtable_migrate.py index dcbbeebcaf..76b946d637 100644 --- a/erpnext/patches/v9_0/student_admission_childtable_migrate.py +++ b/erpnext/patches/v9_0/student_admission_childtable_migrate.py @@ -5,8 +5,8 @@ from __future__ import unicode_literals import frappe def execute(): - frappe.reload_doc('schools', 'doctype', 'Student Admission Program') - frappe.reload_doctype('Student Admission') + frappe.reload_doc('schools', 'doctype', 'student_admission_program') + frappe.reload_doc('schools', 'doctype', 'student_admission') if "program" not in frappe.db.get_table_columns("Student Admission"): return diff --git a/erpnext/patches/v9_0/update_multi_uom_fields_in_material_request.py b/erpnext/patches/v9_0/update_multi_uom_fields_in_material_request.py new file mode 100644 index 0000000000..45610ed5a7 --- /dev/null +++ b/erpnext/patches/v9_0/update_multi_uom_fields_in_material_request.py @@ -0,0 +1,12 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doctype('Material Request') + frappe.reload_doctype('Material Request Item') + + frappe.db.sql(""" update `tabMaterial Request Item` + set stock_uom = uom, stock_qty = qty, conversion_factor = 1.0""") \ No newline at end of file diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index fa56a95960..52d9025669 100644 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -233,7 +233,7 @@ def add_node(): }) args = make_tree_args(**args) - if args.parent_task == 'task': + if args.parent_task == 'All Tasks': args.parent_task = None frappe.get_doc(args).insert() diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 0a4d5f8512..9b592fe629 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -654,7 +654,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item)); refresh_field("stock_qty", item.name, item.parentfield); this.toggle_conversion_factor(item); - if(!dont_fetch_price_list_rate) this.apply_price_list(item, true); + if (!dont_fetch_price_list_rate && + frappe.meta.has_field(doc.doctype, "price_list_currency")) { + this.apply_price_list(item, true); + } } }, diff --git a/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.js b/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.js index f92f738ffd..20503f919c 100644 --- a/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.js +++ b/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.js @@ -1,20 +1,39 @@ // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -cur_frm.add_fetch("student_group", "program", "program"); -cur_frm.add_fetch("student_group", "course", "course"); -cur_frm.add_fetch("student_group", "academic_year", "academic_year"); -cur_frm.add_fetch("student_group", "academic_term", "academic_term"); -frappe.ui.form.on("Course Scheduling Tool", { - - refresh: function(frm) { +frappe.ui.form.on('Course Scheduling Tool', { + setup(frm) { + frm.add_fetch('student_group', 'program', 'program'); + frm.add_fetch('student_group', 'course', 'course'); + frm.add_fetch('student_group', 'academic_year', 'academic_year'); + frm.add_fetch('student_group', 'academic_term', 'academic_term'); + }, + refresh(frm) { frm.disable_save(); - frm.page.set_primary_action(__("Schedule Course"), function() { - frappe.call({ - method: "schedule_course", - doc: frm.doc - }) + frm.page.set_primary_action(__('Schedule Course'), () => { + frm.call('schedule_course') + .then(r => { + if (!r.message) { + frappe.throw(__('There were errors creating Course Schedule')); + } + const { course_schedules } = r.message; + if (course_schedules) { + const html = ` + + + + + ${course_schedules.map( + c => ` + ` + ).join('')} + +
${__('Following course schedules were created')}
${__("Course")}${__("Date")}
${c.name}${c.schedule_date}
` + + frappe.msgprint(html); + } + }); }); } }); \ No newline at end of file diff --git a/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.json b/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.json index e0fc1e215e..9bb99d75a1 100644 --- a/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.json +++ b/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.json @@ -476,7 +476,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "rechedule", + "fieldname": "reschedule", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -485,7 +485,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Rechedule", + "label": "Reschedule", "length": 0, "no_copy": 0, "permlevel": 0, @@ -602,7 +602,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2017-06-30 08:21:47.696063", + "modified": "2017-11-21 16:47:58.091740", "modified_by": "Administrator", "module": "Schools", "name": "Course Scheduling Tool", diff --git a/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.py b/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.py index 4e079221ff..647d34b65e 100644 --- a/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.py +++ b/erpnext/schools/doctype/course_scheduling_tool/course_scheduling_tool.py @@ -10,71 +10,85 @@ from frappe.model.document import Document from frappe.utils import add_days, getdate from erpnext.schools.utils import OverlapError + class CourseSchedulingTool(Document): + def schedule_course(self): - """Creates course schedules as per specified parametes""" - - course_schedules= [] - course_schedules_errors= [] - rescheduled= [] - reschedule_errors= [] - + """Creates course schedules as per specified parameters""" + + course_schedules = [] + course_schedules_errors = [] + rescheduled = [] + reschedule_errors = [] + self.validate_mandatory() self.validate_date() - self.instructor_name= frappe.db.get_value("Instructor", self.instructor, "instructor_name") + self.instructor_name = frappe.db.get_value( + "Instructor", self.instructor, "instructor_name") + + group_based_on, course = frappe.db.get_value( + "Student Group", self.student_group, ["group_based_on", "course"]) - group_based_on, course = frappe.db.get_value("Student Group", self.student_group, ["group_based_on", "course"]) if group_based_on == "Course": - self.course = course + self.course = course + + if self.reschedule: + rescheduled, reschedule_errors = self.delete_course_schedule( + rescheduled, reschedule_errors) - if self.rechedule: - rescheduled, reschedule_errors = self.delete_course_schedule(rescheduled, reschedule_errors) - date = self.course_start_date - while(date < self.course_end_date): + while date < self.course_end_date: if self.day == calendar.day_name[getdate(date).weekday()]: course_schedule = self.make_course_schedule(date) try: + print('pass') course_schedule.save() except OverlapError: + print('fail') course_schedules_errors.append(date) else: - course_schedules.append(course_schedule.name + " on " + date) - + course_schedules.append(course_schedule) + date = add_days(date, 7) else: date = add_days(date, 1) - - frappe.local.message_log = [] - if course_schedules: - frappe.msgprint(_("Course Schedules created:") + "\n" + "\n".join(course_schedules)) - if course_schedules_errors: - frappe.msgprint(_("There were errors while scheduling course on :") + "\n" + "\n".join(course_schedules_errors)) - if rescheduled: - frappe.msgprint(_("Course Schedules deleted:") + "\n" + "\n".join(rescheduled)) - if reschedule_errors: - frappe.msgprint(_("There were errors while deleting following schedules:") + "\n" + "\n".join(reschedule_errors)) - + + return dict( + course_schedules=course_schedules, + course_schedules_errors=course_schedules_errors, + rescheduled=rescheduled, + reschedule_errors=reschedule_errors + ) + def validate_mandatory(self): """Validates all mandatory fields""" - - fields = ['course', 'room', 'instructor', 'from_time', 'to_time', 'course_start_date', 'course_end_date', 'day'] - for d in fields: + + fields = ['course', 'room', 'instructor', 'from_time', + 'to_time', 'course_start_date', 'course_end_date', 'day'] + for d in fields: if not self.get(d): - frappe.throw(_("{0} is mandatory").format(self.meta.get_label(d))) + frappe.throw(_("{0} is mandatory").format( + self.meta.get_label(d))) def validate_date(self): """Validates if Course Start Date is greater than Course End Date""" if self.course_start_date > self.course_end_date: - frappe.throw("Course Start Date cannot be greater than Course End Date.") + frappe.throw( + "Course Start Date cannot be greater than Course End Date.") def delete_course_schedule(self, rescheduled, reschedule_errors): """Delete all course schedule within the Date range and specified filters""" - schedules = frappe.get_list("Course Schedule", fields=["name", "schedule_date"], filters = - [["student_group", "=", self.student_group], - ["course", "=", self.course], - ["schedule_date", ">=", self.course_start_date], - ["schedule_date", "<=", self.course_end_date]]) + + schedules = frappe.get_list("Course Schedule", + fields=["name", "schedule_date"], + filters=[ + ["student_group", "=", self.student_group], + ["course", "=", self.course], + ["schedule_date", ">=", self.course_start_date], + ["schedule_date", "<=", self.course_end_date] + ] + ) + for d in schedules: try: if self.day == calendar.day_name[getdate(d.schedule_date).weekday()]: @@ -83,19 +97,18 @@ class CourseSchedulingTool(Document): except: reschedule_errors.append(d.name) return rescheduled, reschedule_errors - + def make_course_schedule(self, date): """Makes a new Course Schedule. :param date: Date on which Course Schedule will be created.""" - + course_schedule = frappe.new_doc("Course Schedule") course_schedule.student_group = self.student_group course_schedule.course = self.course course_schedule.instructor = self.instructor course_schedule.instructor_name = self.instructor_name course_schedule.room = self.room - course_schedule.schedule_date= date - course_schedule.from_time= self.from_time - course_schedule.to_time= self.to_time + course_schedule.schedule_date = date + course_schedule.from_time = self.from_time + course_schedule.to_time = self.to_time return course_schedule - \ No newline at end of file diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index 28e617faf7..ec70c39c2f 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -254,7 +254,9 @@ def make_tax_account_and_template(company, account_name, tax_rate, template_name accounts = [] for i, name in enumerate(account_name): - accounts.append(make_tax_account(company, account_name[i], tax_rate[i])) + tax_account = make_tax_account(company, account_name[i], tax_rate[i]) + if tax_account: + accounts.append(tax_account) if accounts: make_sales_and_purchase_tax_templates(accounts, template_name) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 59075c588b..da310aa3d7 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -158,7 +158,7 @@ class MaterialRequest(BuyingController): and material_request_item = %s and docstatus = 1""", (self.name, d.name))[0][0]) - if d.ordered_qty and d.ordered_qty > d.qty: + if d.ordered_qty and d.ordered_qty > d.stock_qty: frappe.throw(_("The total Issue / Transfer quantity {0} in Material Request {1} \ cannot be greater than requested quantity {2} for Item {3}").format(d.ordered_qty, d.parent, d.qty, d.item_code)) @@ -170,11 +170,12 @@ class MaterialRequest(BuyingController): frappe.db.set_value(d.doctype, d.name, "ordered_qty", d.ordered_qty) + target_ref_field = 'qty' if self.material_request_type == "Manufacture" else 'stock_qty' self._update_percent_field({ "target_dt": "Material Request Item", "target_parent_dt": self.doctype, "target_parent_field": "per_ordered", - "target_ref_field": "qty", + "target_ref_field": target_ref_field, "target_field": "ordered_qty", "name": self.name, }, update_modified) @@ -216,9 +217,9 @@ def set_missing_values(source, target_doc): target_doc.run_method("calculate_taxes_and_totals") def update_item(obj, target, source_parent): - target.conversion_factor = 1 - target.qty = flt(obj.qty) - flt(obj.ordered_qty) - target.stock_qty = target.qty + target.conversion_factor = obj.conversion_factor + target.qty = flt(flt(obj.stock_qty) - flt(obj.ordered_qty))/ target.conversion_factor + target.stock_qty = (target.qty * target.conversion_factor) @frappe.whitelist() def make_purchase_order(source_name, target_doc=None): @@ -242,7 +243,7 @@ def make_purchase_order(source_name, target_doc=None): ["uom", "uom"] ], "postprocess": update_item, - "condition": lambda doc: doc.ordered_qty < doc.qty + "condition": lambda doc: doc.ordered_qty < doc.stock_qty } }, target_doc, postprocess) @@ -353,11 +354,11 @@ def make_supplier_quotation(source_name, target_doc=None): @frappe.whitelist() def make_stock_entry(source_name, target_doc=None): def update_item(obj, target, source_parent): - qty = flt(obj.qty) - flt(obj.ordered_qty) \ - if flt(obj.qty) > flt(obj.ordered_qty) else 0 + qty = flt(flt(obj.stock_qty) - flt(obj.ordered_qty))/ target.conversion_factor \ + if flt(obj.stock_qty) > flt(obj.ordered_qty) else 0 target.qty = qty - target.transfer_qty = qty - target.conversion_factor = 1 + target.transfer_qty = qty * obj.conversion_factor + target.conversion_factor = obj.conversion_factor if source_parent.material_request_type == "Material Transfer": target.t_warehouse = obj.warehouse @@ -384,7 +385,7 @@ def make_stock_entry(source_name, target_doc=None): "uom": "stock_uom", }, "postprocess": update_item, - "condition": lambda doc: doc.ordered_qty < doc.qty + "condition": lambda doc: doc.ordered_qty < doc.stock_qty } }, target_doc, set_missing_values) @@ -405,7 +406,7 @@ def raise_production_orders(material_request): prod_order.fg_warehouse = d.warehouse prod_order.wip_warehouse = default_wip_warehouse prod_order.description = d.description - prod_order.stock_uom = d.uom + prod_order.stock_uom = d.stock_uom prod_order.expected_delivery_date = d.schedule_date prod_order.sales_order = d.sales_order prod_order.bom_no = get_item_details(d.item_code).bom_no diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index a24957e2b0..83971d3779 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe, unittest, erpnext -from frappe.utils import flt +from frappe.utils import flt, today from erpnext.stock.doctype.material_request.material_request import raise_production_orders class TestMaterialRequest(unittest.TestCase): @@ -558,5 +558,48 @@ class TestMaterialRequest(unittest.TestCase): item_code= %s and warehouse= %s """, (mr.items[0].item_code, mr.items[0].warehouse))[0][0] self.assertEquals(requested_qty, new_requested_qty) + def test_multi_uom_for_purchase(self): + from erpnext.stock.doctype.material_request.material_request import make_purchase_order + + mr = frappe.copy_doc(test_records[0]) + mr.material_request_type = 'Purchase' + item = mr.items[0] + mr.schedule_date = today() + + if not frappe.db.get_value('UOM Conversion Detail', + {'parent': item.item_code, 'uom': 'Kg'}): + item_doc = frappe.get_doc('Item', item.item_code) + item_doc.append('uoms', { + 'uom': 'Kg', + 'conversion_factor': 5 + }) + item_doc.save(ignore_permissions=True) + + item.uom = 'Kg' + for item in mr.items: + item.schedule_date = mr.schedule_date + + mr.insert() + self.assertRaises(frappe.ValidationError, make_purchase_order, + mr.name) + + mr = frappe.get_doc("Material Request", mr.name) + mr.submit() + item = mr.items[0] + + self.assertEquals(item.uom, "Kg") + self.assertEquals(item.conversion_factor, 5.0) + self.assertEquals(item.stock_qty, flt(item.qty * 5)) + + po = make_purchase_order(mr.name) + self.assertEquals(po.doctype, "Purchase Order") + self.assertEquals(len(po.get("items")), len(mr.get("items"))) + + po.supplier = '_Test Supplier' + po.insert() + po.submit() + mr = frappe.get_doc("Material Request", mr.name) + self.assertEquals(mr.per_ordered, 100) + test_dependencies = ["Currency Exchange", "BOM"] test_records = frappe.get_test_records('Material Request') diff --git a/erpnext/stock/doctype/material_request_item/material_request_item.json b/erpnext/stock/doctype/material_request_item/material_request_item.json index 5bf3f27a1b..3434b4d48f 100644 --- a/erpnext/stock/doctype/material_request_item/material_request_item.json +++ b/erpnext/stock/doctype/material_request_item/material_request_item.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, "autoname": "hash", @@ -13,6 +14,7 @@ "engine": "InnoDB", "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 1, "collapsible": 0, @@ -46,6 +48,7 @@ "width": "100px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -73,6 +76,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -105,6 +109,7 @@ "width": "100px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 1, @@ -134,6 +139,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -166,6 +172,7 @@ "width": "250px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -194,6 +201,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -223,6 +231,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -251,6 +260,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -283,11 +293,12 @@ "width": "80px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "uom", + "fieldname": "stock_uom", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -299,23 +310,21 @@ "label": "Stock UOM", "length": 0, "no_copy": 0, - "oldfieldname": "uom", - "oldfieldtype": "Link", "options": "UOM", "permlevel": 0, - "print_hide": 0, + "precision": "", + "print_hide": 1, "print_hide_if_no_value": 0, - "print_width": "70px", "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, "set_only_once": 0, - "unique": 0, - "width": "70px" + "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -349,6 +358,7 @@ "width": "100px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -376,6 +386,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 1, "collapsible": 0, @@ -409,6 +420,101 @@ "width": "100px" }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "UOM", + "length": 0, + "no_copy": 0, + "oldfieldname": "uom", + "oldfieldtype": "Link", + "options": "UOM", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": "70px", + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "70px" + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "conversion_factor", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "UOM Conversion Factor", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "stock_qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Stock Qty", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "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_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -437,6 +543,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -469,6 +576,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -502,6 +610,7 @@ "width": "100px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -532,6 +641,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -561,6 +671,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -591,6 +702,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -618,6 +730,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -650,6 +763,7 @@ "width": "70px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -682,6 +796,7 @@ "width": "70px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -711,6 +826,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -741,6 +857,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, @@ -771,17 +888,17 @@ "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 1, "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-02-20 13:31:50.143583", + "modified": "2017-10-25 17:18:59.974778", "modified_by": "Administrator", "module": "Stock", "name": "Material Request Item", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 539e8a5667..102d168840 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -164,11 +164,17 @@ def get_basic_details(args, item): warehouse = user_default_warehouse or item.default_warehouse or args.warehouse + material_request_type = '' + if args.get('doctype') == "Material Request": + material_request_type = frappe.db.get_value('Material Request', + args.get('name'), 'material_request_type') + #Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master if not args.uom: if args.get('doctype') in ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']: args.uom = item.sales_uom if item.sales_uom else item.stock_uom - elif args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']: + elif (args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']) or \ + (args.get('doctype') == 'Material Request' and material_request_type == 'Purchase'): args.uom = item.purchase_uom if item.purchase_uom else item.stock_uom else: args.uom = item.stock_uom diff --git a/erpnext/stock/reorder_item.py b/erpnext/stock/reorder_item.py index 3189788c93..9924156035 100644 --- a/erpnext/stock/reorder_item.py +++ b/erpnext/stock/reorder_item.py @@ -129,16 +129,26 @@ def create_material_request(material_requests): for d in items: d = frappe._dict(d) item = frappe.get_doc("Item", d.item_code) + uom = item.stock_uom + conversion_factor = 1.0 + + if request_type == 'Purchase': + uom = item.purchase_uom or item.stock_uom + if uom != item.stock_uom: + conversion_factor = frappe.db.get_value("UOM Conversion Detail", + {'parent': item.name, 'uom': uom}, 'conversion_factor') or 1.0 + mr.append("items", { "doctype": "Material Request Item", "item_code": d.item_code, "schedule_date": add_days(nowdate(),cint(item.lead_time_days)), - "uom": item.stock_uom, + "qty": d.reorder_qty / conversion_factor, + "uom": uom, + "stock_uom": item.stock_uom, "warehouse": d.warehouse, "item_name": item.item_name, "description": item.description, "item_group": item.item_group, - "qty": d.reorder_qty, "brand": item.brand, }) diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt index 3e40485d74..0bbffa5666 100644 --- a/erpnext/tests/ui/tests.txt +++ b/erpnext/tests/ui/tests.txt @@ -1,7 +1,8 @@ erpnext/tests/ui/make_fixtures.js #long erpnext/setup/doctype/company/tests/test_company.js -erpnext/accounts/doctype/account/test_account.js -erpnext/accounts/doctype/account/test_make_tax_account.js +erpnext/accounts/doctype/account/tests/test_account.js +erpnext/accounts/doctype/account/tests/test_make_tax_account.js +erpnext/accounts/doctype/account/tests/test_account_with_number.js erpnext/accounts/doctype/pricing_rule/test_pricing_rule.js erpnext/accounts/doctype/sales_taxes_and_charges_template/test_sales_taxes_and_charges_template.js erpnext/accounts/doctype/purchase_taxes_and_charges_template/test_purchase_taxes_and_charges_template.js