Merge pull request #21305 from deepeshgarg007/partial_loan_repayment_fixes
fix: Loan Repayment code clean up and other fixes
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 0a72d4f..c6de641 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -89,7 +89,7 @@
throw(_("Root cannot be edited."), RootNotEditable)
if not self.parent_account and not self.is_group:
- frappe.throw(_("Root Account must be a group"))
+ frappe.throw(_("The root account {0} must be a group").format(frappe.bold(self.name)))
def validate_root_company_and_sync_account_to_children(self):
# ignore validation while creating new compnay or while syncing to child companies
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index dc23b2b..89bb018 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -69,6 +69,7 @@
acc.account_name = "Accumulated Depreciation"
acc.parent_account = "Fixed Assets - _TC"
acc.company = "_Test Company"
+ acc.account_type = "Accumulated Depreciation"
acc.insert()
doc = frappe.get_doc("Account", "Securities and Deposits - _TC")
@@ -149,7 +150,7 @@
# fixed asset depreciation
["_Test Fixed Asset", "Current Assets", 0, "Fixed Asset", None],
- ["_Test Accumulated Depreciations", "Current Assets", 0, None, None],
+ ["_Test Accumulated Depreciations", "Current Assets", 0, "Accumulated Depreciation", None],
["_Test Depreciations", "Expenses", 0, None, None],
["_Test Gain/Loss on Asset Disposal", "Expenses", 0, None, None],
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index c5c5483..9292b63 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -174,7 +174,8 @@
read_only: 0,
fieldtype:'Date',
label: __('Release Date'),
- default: me.frm.doc.release_date
+ default: me.frm.doc.release_date,
+ reqd: 1
},
{
fieldname: 'hold_comment',
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index 9c97426..db3f72a 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -754,8 +754,7 @@
{
"fieldname": "manufacturer_part_no",
"fieldtype": "Data",
- "label": "Manufacturer Part Number",
- "read_only": 1
+ "label": "Manufacturer Part Number"
},
{
"depends_on": "is_fixed_asset",
@@ -777,7 +776,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-04-01 14:20:17.297284",
+ "modified": "2020-04-07 18:34:35.104178",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 82aedb6..3c40112 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -440,11 +440,12 @@
if pos.get("company_address"):
self.company_address = pos.get("company_address")
- customer_price_list, customer_group = frappe.get_value("Customer", self.customer, ['default_price_list', 'customer_group'])
-
- customer_group_price_list = frappe.get_value("Customer Group", customer_group, 'default_price_list')
-
- selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list')
+ if self.customer:
+ customer_price_list, customer_group = frappe.get_value("Customer", self.customer, ['default_price_list', 'customer_group'])
+ customer_group_price_list = frappe.get_value("Customer Group", customer_group, 'default_price_list')
+ selling_price_list = customer_price_list or customer_group_price_list or pos.get('selling_price_list')
+ else:
+ selling_price_list = pos.get('selling_price_list')
if selling_price_list:
self.set('selling_price_list', selling_price_list)
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 0e54b62..a2819af 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1926,16 +1926,6 @@
item.taxes = []
item.save()
- def test_customer_provided_parts_si(self):
- create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
- si = create_sales_invoice(item_code='CUST-0987', rate=0)
- self.assertEqual(si.get("items")[0].allow_zero_valuation_rate, 1)
- self.assertEqual(si.get("items")[0].amount, 0)
-
- # test if Sales Invoice with rate is allowed
- si2 = create_sales_invoice(item_code='CUST-0987', do_not_save=True)
- self.assertRaises(frappe.ValidationError, si2.save)
-
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
args = frappe._dict(args)
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index fc08841..9bf4df4 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -11,12 +11,34 @@
class AssetCategory(Document):
def validate(self):
self.validate_finance_books()
+ self.validate_accounts()
def validate_finance_books(self):
for d in self.finance_books:
for field in ("Total Number of Depreciations", "Frequency of Depreciation"):
if cint(d.get(frappe.scrub(field)))<1:
frappe.throw(_("Row {0}: {1} must be greater than 0").format(d.idx, field), frappe.MandatoryError)
+
+ def validate_accounts(self):
+ account_type_map = {
+ 'fixed_asset_account': { 'account_type': 'Fixed Asset' },
+ 'accumulated_depreciation_account': { 'account_type': 'Accumulated Depreciation' },
+ 'depreciation_expense_account': { 'root_type': 'Expense' },
+ 'capital_work_in_progress_account': { 'account_type': 'Capital Work in Progress' }
+ }
+ for d in self.accounts:
+ for fieldname in account_type_map.keys():
+ if d.get(fieldname):
+ selected_account = d.get(fieldname)
+ key_to_match = next(iter(account_type_map.get(fieldname))) # acount_type or root_type
+ selected_key_type = frappe.db.get_value('Account', selected_account, key_to_match)
+ expected_key_type = account_type_map[fieldname][key_to_match]
+
+ if selected_key_type != expected_key_type:
+ frappe.throw(_("Row #{}: {} of {} should be {}. Please modify the account or select a different account.")
+ .format(d.idx, frappe.unscrub(key_to_match), frappe.bold(selected_account), frappe.bold(expected_key_type)),
+ title=_("Invalid Account"))
+
@frappe.whitelist()
def get_asset_category_account(fieldname, item=None, asset=None, account=None, asset_category = None, company = None):
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index 6768dfa..e37e1dd 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -702,8 +702,7 @@
{
"fieldname": "manufacturer_part_no",
"fieldtype": "Data",
- "label": "Manufacturer Part Number",
- "read_only": 1
+ "label": "Manufacturer Part Number"
},
{
"default": "0",
@@ -723,7 +722,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2019-12-06 13:17:12.142799",
+ "modified": "2020-04-07 18:35:17.558928",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order Item",
diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
index 7d7d6f4..b50e834 100644
--- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
+++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"autoname": "hash",
"creation": "2013-05-22 12:43:10",
"doctype": "DocType",
@@ -522,8 +523,7 @@
{
"fieldname": "manufacturer_part_no",
"fieldtype": "Data",
- "label": "Manufacturer Part Number",
- "read_only": 1
+ "label": "Manufacturer Part Number"
},
{
"fieldname": "column_break_15",
@@ -532,7 +532,8 @@
],
"idx": 1,
"istable": 1,
- "modified": "2019-06-02 05:32:46.019237",
+ "links": [],
+ "modified": "2020-04-07 18:35:51.175947",
"modified_by": "Administrator",
"module": "Buying",
"name": "Supplier Quotation Item",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index d95753d..4045250 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1123,36 +1123,39 @@
}
return info
-def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_code):
+def set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
"""
Returns a Sales Order Item child item containing the default values
"""
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
child_item = frappe.new_doc('Sales Order Item', p_doc, child_docname)
- item = frappe.get_doc("Item", item_code)
+ item = frappe.get_doc("Item", trans_item.get('item_code'))
child_item.item_code = item.item_code
child_item.item_name = item.item_name
child_item.description = item.description
- child_item.reqd_by_date = p_doc.delivery_date
+ child_item.delivery_date = trans_item.get('delivery_date') or p_doc.delivery_date
child_item.uom = item.stock_uom
- child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
+ child_item.conversion_factor = get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
child_item.warehouse = get_item_warehouse(item, p_doc, overwrite_warehouse=True)
+ if not child_item.warehouse:
+ frappe.throw(_("Cannot find {} for item {}. Please set the same in Item Master or Stock Settings.")
+ .format(frappe.bold("default warehouse"), frappe.bold(item.item_code)))
return child_item
-def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, item_code):
+def set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, trans_item):
"""
Returns a Purchase Order Item child item containing the default values
"""
p_doc = frappe.get_doc(parent_doctype, parent_doctype_name)
child_item = frappe.new_doc('Purchase Order Item', p_doc, child_docname)
- item = frappe.get_doc("Item", item_code)
+ item = frappe.get_doc("Item", trans_item.get('item_code'))
child_item.item_code = item.item_code
child_item.item_name = item.item_name
child_item.description = item.description
- child_item.schedule_date = p_doc.schedule_date
+ child_item.schedule_date = trans_item.get('schedule_date') or p_doc.schedule_date
child_item.uom = item.stock_uom
- child_item.conversion_factor = get_conversion_factor(item_code, item.stock_uom).get("conversion_factor") or 1.0
+ child_item.conversion_factor = get_conversion_factor(item.item_code, item.stock_uom).get("conversion_factor") or 1.0
child_item.base_rate = 1 # Initiallize value will update in parent validation
child_item.base_amount = 1 # Initiallize value will update in parent validation
return child_item
@@ -1196,9 +1199,9 @@
if not d.get("docname"):
new_child_flag = True
if parent_doctype == "Sales Order":
- child_item = set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code"))
+ child_item = set_sales_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
if parent_doctype == "Purchase Order":
- child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d.get("item_code"))
+ child_item = set_purchase_order_defaults(parent_doctype, parent_doctype_name, child_docname, d)
else:
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
if flt(child_item.get("rate")) == flt(d.get("rate")) and flt(child_item.get("qty")) == flt(d.get("qty")):
@@ -1243,6 +1246,7 @@
child_item.flags.ignore_validate_update_after_submit = True
if new_child_flag:
+ parent.load_from_db()
child_item.idx = len(parent.items) + 1
child_item.insert()
else:
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 4037f2f..55a2c43 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -383,9 +383,6 @@
# Customer Provided parts will have zero valuation rate
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
d.allow_zero_valuation_rate = 1
- if d.parenttype in ["Delivery Note", "Sales Invoice"] and d.rate:
- frappe.throw(_("Row #{0}: {1} cannot have {2} as it is a Customer Provided Item")
- .format(d.idx, frappe.bold(d.item_code), frappe.bold("Rate")))
def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None,
warehouse_account=None, company=None):
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 5e640e7..1b071ea 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -336,3 +336,27 @@
link_communication_to_document(doc, "Opportunity", opportunity.name, ignore_communication_links)
return opportunity.name
+@frappe.whitelist()
+def get_events(start, end, filters=None):
+ """Returns events for Gantt / Calendar view rendering.
+ :param start: Start date-time.
+ :param end: End date-time.
+ :param filters: Filters (JSON).
+ """
+ from frappe.desk.calendar import get_event_conditions
+ conditions = get_event_conditions("Opportunity", filters)
+
+ data = frappe.db.sql("""
+ select
+ distinct `tabOpportunity`.name, `tabOpportunity`.customer_name, `tabOpportunity`.opportunity_amount,
+ `tabOpportunity`.title, `tabOpportunity`.contact_date
+ from
+ `tabOpportunity`
+ where
+ (`tabOpportunity`.contact_date between %(start)s and %(end)s)
+ {conditions}
+ """.format(conditions=conditions), {
+ "start": start,
+ "end": end
+ }, as_dict=True, update={"allDay": 0})
+ return data
\ No newline at end of file
diff --git a/erpnext/crm/doctype/opportunity/opportunity_calendar.js b/erpnext/crm/doctype/opportunity/opportunity_calendar.js
new file mode 100644
index 0000000..58fa2b8
--- /dev/null
+++ b/erpnext/crm/doctype/opportunity/opportunity_calendar.js
@@ -0,0 +1,19 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+frappe.views.calendar["Opportunity"] = {
+ field_map: {
+ "start": "contact_date",
+ "end": "contact_date",
+ "id": "name",
+ "title": "customer_name",
+ "allDay": "allDay"
+ },
+ options: {
+ header: {
+ left: 'prev,next today',
+ center: 'title',
+ right: 'month'
+ }
+ },
+ get_events_method: 'erpnext.crm.doctype.opportunity.opportunity.get_events'
+}
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index 8c7876d..bab0dfb 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -82,7 +82,9 @@
frm.set_value('current_time' , 0);
}
- frm.save();
+ frm.save("Save", () => {}, "", () => {
+ frm.doc.time_logs.pop(-1);
+ });
},
complete_job: function(frm, completed_time, completed_qty) {
@@ -105,6 +107,24 @@
});
},
+ validate: function(frm) {
+ if ((!frm.doc.time_logs || !frm.doc.time_logs.length) && frm.doc.started_time) {
+ frm.trigger("reset_timer");
+ }
+ },
+
+ employee: function(frm) {
+ if (frm.doc.job_started && !frm.doc.current_time) {
+ frm.trigger("reset_timer");
+ }
+ },
+
+ reset_timer: function(frm) {
+ frm.set_value('started_time' , '');
+ frm.set_value('job_started', 0);
+ frm.set_value('current_time' , 0);
+ },
+
make_dashboard: function(frm) {
if(frm.doc.__islocal)
return;
@@ -137,12 +157,12 @@
updateStopwatch(current);
}, 1000);
}
-
+
function updateStopwatch(increment) {
var hours = Math.floor(increment / 3600);
var minutes = Math.floor((increment - (hours * 3600)) / 60);
var seconds = increment - (hours * 3600) - (minutes * 60);
-
+
$(section).find(".hours").text(hours < 10 ? ("0" + hours.toString()) : hours.toString());
$(section).find(".minutes").text(minutes < 10 ? ("0" + minutes.toString()) : minutes.toString());
$(section).find(".seconds").text(seconds < 10 ? ("0" + seconds.toString()) : seconds.toString());
@@ -205,5 +225,10 @@
frappe.ui.form.on('Job Card Time Log', {
completed_qty: function(frm) {
frm.events.set_total_completed_qty(frm);
+ },
+
+ to_time: function(frm) {
+ frm.set_value('job_started', 0);
+ frm.set_value('started_time', '');
}
})
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index f8c60f2..e9627a5 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -9,7 +9,7 @@
from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document
from frappe.utils import (flt, cint, time_diff_in_hours, get_datetime, getdate,
- get_time, add_to_date, time_diff, add_days, get_datetime_str)
+ get_time, add_to_date, time_diff, add_days, get_datetime_str, get_link_to_form)
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
@@ -189,11 +189,15 @@
def validate_job_card(self):
if not self.time_logs:
- frappe.throw(_("Time logs are required for job card {0}").format(self.name))
+ frappe.throw(_("Time logs are required for {0} {1}")
+ .format(frappe.bold("Job Card"), get_link_to_form("Job Card", self.name)))
if self.for_quantity and self.total_completed_qty != self.for_quantity:
- frappe.throw(_("The total completed qty({0}) must be equal to qty to manufacture({1})"
- .format(frappe.bold(self.total_completed_qty),frappe.bold(self.for_quantity))))
+ total_completed_qty = frappe.bold(_("Total Completed Qty"))
+ qty_to_manufacture = frappe.bold(_("Qty to Manufacture"))
+
+ frappe.throw(_("The {0} ({1}) must be equal to {2} ({3})"
+ .format(total_completed_qty, frappe.bold(self.total_completed_qty), qty_to_manufacture,frappe.bold(self.for_quantity))))
def update_work_order(self):
if not self.work_order:
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index 9c8aa45..d541866 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -240,6 +240,8 @@
});
}, __("Job Card"), __("Create"));
+ dialog.fields_dict["operations"].grid.wrapper.find('.grid-add-row').hide();
+
var pending_qty = 0;
frm.doc.operations.forEach(data => {
if(data.completed_qty != frm.doc.qty) {
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 27a9de9..afbdbc6 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -379,7 +379,31 @@
}
});
}
- }
+ },
+
+ manufacturer_part_no: function(doc, cdt, cdn) {
+ const row = locals[cdt][cdn];
+
+ if (row.manufacturer_part_no) {
+ frappe.model.get_value('Item Manufacturer',
+ {
+ 'item_code': row.item_code,
+ 'manufacturer': row.manufacturer,
+ 'manufacturer_part_no': row.manufacturer_part_no
+ },
+ 'name',
+ function(data) {
+ if (!data) {
+ let msg = {
+ message: __("Manufacturer Part Number <b>{0}</b> is invalid", [row.manufacturer_part_no]),
+ title: __("Invalid Part Number")
+ }
+ frappe.throw(msg);
+ }
+ });
+
+ }
+ }
});
cur_frm.add_fetch('project', 'cost_center', 'cost_center');
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 8e8c48f..f126f6a 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -551,6 +551,10 @@
if(!d[k]) d[k] = v;
});
+ if (d.has_batch_no && d.has_serial_no) {
+ d.batch_no = undefined;
+ }
+
erpnext.show_serial_batch_selector(me.frm, d, (item) => {
me.frm.script_manager.trigger('qty', item.doctype, item.name);
if (!me.frm.doc.set_warehouse)
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 4d44eae..58969f2 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -436,6 +436,44 @@
const cannot_add_row = (typeof opts.cannot_add_row === 'undefined') ? true : opts.cannot_add_row;
const child_docname = (typeof opts.cannot_add_row === 'undefined') ? "items" : opts.child_docname;
this.data = [];
+ const fields = [{
+ fieldtype:'Data',
+ fieldname:"docname",
+ read_only: 1,
+ hidden: 1,
+ }, {
+ fieldtype:'Link',
+ fieldname:"item_code",
+ options: 'Item',
+ in_list_view: 1,
+ read_only: 0,
+ disabled: 0,
+ label: __('Item Code')
+ }, {
+ fieldtype:'Float',
+ fieldname:"qty",
+ default: 0,
+ read_only: 0,
+ in_list_view: 1,
+ label: __('Qty')
+ }, {
+ fieldtype:'Currency',
+ fieldname:"rate",
+ default: 0,
+ read_only: 0,
+ in_list_view: 1,
+ label: __('Rate')
+ }];
+
+ if (frm.doc.doctype == 'Sales Order' || frm.doc.doctype == 'Purchase Order' ) {
+ fields.splice(2, 0, {
+ fieldtype: 'Date',
+ fieldname: frm.doc.doctype == 'Sales Order' ? "delivery_date" : "schedule_date",
+ in_list_view: 1,
+ label: frm.doc.doctype == 'Sales Order' ? __("Delivery Date") : __("Reqd by date")
+ })
+ }
+
const dialog = new frappe.ui.Dialog({
title: __("Update Items"),
fields: [
@@ -450,34 +488,7 @@
get_data: () => {
return this.data;
},
- fields: [{
- fieldtype:'Data',
- fieldname:"docname",
- read_only: 1,
- hidden: 1,
- }, {
- fieldtype:'Link',
- fieldname:"item_code",
- options: 'Item',
- in_list_view: 1,
- read_only: 0,
- disabled: 0,
- label: __('Item Code')
- }, {
- fieldtype:'Float',
- fieldname:"qty",
- default: 0,
- read_only: 0,
- in_list_view: 1,
- label: __('Qty')
- }, {
- fieldtype:'Currency',
- fieldname:"rate",
- default: 0,
- read_only: 0,
- in_list_view: 1,
- label: __('Rate')
- }]
+ fields: fields
},
],
primary_action: function() {
@@ -506,6 +517,8 @@
"docname": d.name,
"name": d.name,
"item_code": d.item_code,
+ "delivery_date": d.delivery_date,
+ "schedule_date": d.schedule_date,
"qty": d.qty,
"rate": d.rate,
});
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index af10069..095b7c3 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -228,9 +228,15 @@
warehouse: function(doc, cdt, cdn) {
var me = this;
var item = frappe.get_doc(cdt, cdn);
+
+ if (item.serial_no && item.qty === item.serial_no.split(`\n`).length) {
+ return;
+ }
+
if (item.serial_no && !item.batch_no) {
item.serial_no = null;
}
+
var has_batch_no;
frappe.db.get_value('Item', {'item_code': item.item_code}, 'has_batch_no', (r) => {
has_batch_no = r && r.has_batch_no;
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 47a72b2..d7a93fb 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -434,15 +434,6 @@
update_delivery_note_status(dn.name, "Closed")
self.assertEqual(frappe.db.get_value("Delivery Note", dn.name, "Status"), "Closed")
- def test_customer_provided_parts_dn(self):
- create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
- dn = create_delivery_note(item_code='CUST-0987', rate=0)
- self.assertEqual(dn.get("items")[0].allow_zero_valuation_rate, 1)
-
- # test if Delivery Note with rate is allowed against Customer Provided Item
- dn2 = create_delivery_note(item_code='CUST-0987', do_not_save=True)
- self.assertRaises(frappe.ValidationError, dn2.save)
-
def test_dn_billing_status_case1(self):
# SO -> DN -> SI
so = make_sales_order()
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index aa6b2fe..7d2e311 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -114,6 +114,8 @@
"is_sub_contracted_item",
"column_break_74",
"customer_code",
+ "default_item_manufacturer",
+ "default_manufacturer_part_no",
"website_section",
"show_in_website",
"show_variant_in_website",
@@ -1038,6 +1040,18 @@
"fieldname": "auto_create_assets",
"fieldtype": "Check",
"label": "Auto Create Assets on Purchase"
+ },
+ {
+ "fieldname": "default_item_manufacturer",
+ "fieldtype": "Data",
+ "label": "Default Item Manufacturer",
+ "read_only": 1
+ },
+ {
+ "fieldname": "default_manufacturer_part_no",
+ "fieldtype": "Data",
+ "label": "Default Manufacturer Part No",
+ "read_only": 1
}
],
"has_web_view": 1,
@@ -1046,7 +1060,7 @@
"image_field": "image",
"links": [],
"max_attachments": 1,
- "modified": "2020-03-24 16:14:36.950677",
+ "modified": "2020-04-07 15:56:06.195722",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
diff --git a/erpnext/stock/doctype/item_manufacturer/item_manufacturer.json b/erpnext/stock/doctype/item_manufacturer/item_manufacturer.json
index 956c92e..0cef6ea 100644
--- a/erpnext/stock/doctype/item_manufacturer/item_manufacturer.json
+++ b/erpnext/stock/doctype/item_manufacturer/item_manufacturer.json
@@ -1,4 +1,5 @@
{
+ "actions": [],
"allow_import": 1,
"creation": "2019-06-02 04:41:37.332911",
"doctype": "DocType",
@@ -10,7 +11,8 @@
"manufacturer_part_no",
"column_break_3",
"item_name",
- "description"
+ "description",
+ "is_default"
],
"fields": [
{
@@ -52,9 +54,17 @@
"fieldtype": "Small Text",
"label": "Description",
"read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "is_default",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Is Default"
}
],
- "modified": "2019-06-06 19:07:31.175919",
+ "links": [],
+ "modified": "2020-04-07 20:25:55.507905",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item Manufacturer",
diff --git a/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py b/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
index 67eab82..c27d1be 100644
--- a/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
+++ b/erpnext/stock/doctype/item_manufacturer/item_manufacturer.py
@@ -11,6 +11,10 @@
class ItemManufacturer(Document):
def validate(self):
self.validate_duplicate_entry()
+ self.manage_default_item_manufacturer()
+
+ def on_trash(self):
+ self.manage_default_item_manufacturer(delete=True)
def validate_duplicate_entry(self):
if self.is_new():
@@ -24,6 +28,40 @@
frappe.throw(_("Duplicate entry against the item code {0} and manufacturer {1}")
.format(self.item_code, self.manufacturer))
+ def manage_default_item_manufacturer(self, delete=False):
+ from frappe.model.utils import set_default
+
+ item = frappe.get_doc("Item", self.item_code)
+ default_manufacturer = item.default_item_manufacturer
+ default_part_no = item.default_manufacturer_part_no
+
+ if not self.is_default:
+ # if unchecked and default in Item master, clear it.
+ if default_manufacturer == self.manufacturer and default_part_no == self.manufacturer_part_no:
+ frappe.db.set_value("Item", item.name,
+ {
+ "default_item_manufacturer": None,
+ "default_manufacturer_part_no": None
+ })
+
+ elif self.is_default:
+ set_default(self, "item_code")
+ manufacturer, manufacturer_part_no = default_manufacturer, default_part_no
+
+ if delete:
+ manufacturer, manufacturer_part_no = None, None
+
+ elif (default_manufacturer != self.manufacturer) or \
+ (default_manufacturer == self.manufacturer and default_part_no != self.manufacturer_part_no):
+ manufacturer = self.manufacturer
+ manufacturer_part_no = self.manufacturer_part_no
+
+ frappe.db.set_value("Item", item.name,
+ {
+ "default_item_manufacturer": manufacturer,
+ "default_manufacturer_part_no": manufacturer_part_no
+ })
+
@frappe.whitelist()
def get_item_manufacturer_part_no(item_code, manufacturer):
return frappe.db.get_value("Item Manufacturer",
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 5b242a5..2d98557 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -175,12 +175,11 @@
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": target_ref_field,
+ "target_ref_field": "stock_qty",
"target_field": "ordered_qty",
"name": self.name,
}, update_modified)
@@ -499,7 +498,7 @@
default_wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
for d in mr.items:
- if (d.qty - d.ordered_qty) >0:
+ if (d.stock_qty - d.ordered_qty) > 0:
if frappe.db.exists("BOM", {"item": d.item_code, "is_default": 1}):
wo_order = frappe.new_doc("Work Order")
wo_order.update({
@@ -531,7 +530,7 @@
msgprint(_("The following Work Orders were created:") + '\n' + new_line_sep(message))
if errors:
- frappe.throw(_("Productions Orders cannot be raised for:") + '\n' + new_line_sep(errors))
+ frappe.throw(_("Work Order cannot be created for following reason:") + '\n' + new_line_sep(errors))
return work_orders
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index b925aed..19924b1 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -7,7 +7,8 @@
from __future__ import unicode_literals
import frappe, unittest, erpnext
from frappe.utils import flt, today
-from erpnext.stock.doctype.material_request.material_request import raise_work_orders
+from erpnext.stock.doctype.material_request.material_request \
+ import raise_work_orders, make_stock_entry, make_purchase_order, make_supplier_quotation
from erpnext.stock.doctype.item.test_item import create_item
class TestMaterialRequest(unittest.TestCase):
@@ -15,8 +16,6 @@
erpnext.set_perpetual_inventory(0)
def test_make_purchase_order(self):
- from erpnext.stock.doctype.material_request.material_request import make_purchase_order
-
mr = frappe.copy_doc(test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_purchase_order,
@@ -30,8 +29,6 @@
self.assertEqual(len(po.get("items")), len(mr.get("items")))
def test_make_supplier_quotation(self):
- from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation
-
mr = frappe.copy_doc(test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_supplier_quotation, mr.name)
@@ -45,12 +42,9 @@
def test_make_stock_entry(self):
- from erpnext.stock.doctype.material_request.material_request import make_stock_entry
-
mr = frappe.copy_doc(test_records[0]).insert()
- self.assertRaises(frappe.ValidationError, make_stock_entry,
- mr.name)
+ self.assertRaises(frappe.ValidationError, make_stock_entry, mr.name)
mr = frappe.get_doc("Material Request", mr.name)
mr.material_request_type = "Material Transfer"
@@ -62,40 +56,40 @@
def _insert_stock_entry(self, qty1, qty2, warehouse = None ):
se = frappe.get_doc({
- "company": "_Test Company",
- "doctype": "Stock Entry",
- "posting_date": "2013-03-01",
- "posting_time": "00:00:00",
- "purpose": "Material Receipt",
- "items": [
- {
- "conversion_factor": 1.0,
- "doctype": "Stock Entry Detail",
- "item_code": "_Test Item Home Desktop 100",
- "parentfield": "items",
- "basic_rate": 100,
- "qty": qty1,
- "stock_uom": "_Test UOM 1",
- "transfer_qty": qty1,
- "uom": "_Test UOM 1",
- "t_warehouse": warehouse or "_Test Warehouse 1 - _TC",
- "cost_center": "_Test Cost Center - _TC"
- },
- {
- "conversion_factor": 1.0,
- "doctype": "Stock Entry Detail",
- "item_code": "_Test Item Home Desktop 200",
- "parentfield": "items",
- "basic_rate": 100,
- "qty": qty2,
- "stock_uom": "_Test UOM 1",
- "transfer_qty": qty2,
- "uom": "_Test UOM 1",
- "t_warehouse": warehouse or "_Test Warehouse 1 - _TC",
- "cost_center": "_Test Cost Center - _TC"
- }
- ]
- })
+ "company": "_Test Company",
+ "doctype": "Stock Entry",
+ "posting_date": "2013-03-01",
+ "posting_time": "00:00:00",
+ "purpose": "Material Receipt",
+ "items": [
+ {
+ "conversion_factor": 1.0,
+ "doctype": "Stock Entry Detail",
+ "item_code": "_Test Item Home Desktop 100",
+ "parentfield": "items",
+ "basic_rate": 100,
+ "qty": qty1,
+ "stock_uom": "_Test UOM 1",
+ "transfer_qty": qty1,
+ "uom": "_Test UOM 1",
+ "t_warehouse": warehouse or "_Test Warehouse 1 - _TC",
+ "cost_center": "_Test Cost Center - _TC"
+ },
+ {
+ "conversion_factor": 1.0,
+ "doctype": "Stock Entry Detail",
+ "item_code": "_Test Item Home Desktop 200",
+ "parentfield": "items",
+ "basic_rate": 100,
+ "qty": qty2,
+ "stock_uom": "_Test UOM 1",
+ "transfer_qty": qty2,
+ "uom": "_Test UOM 1",
+ "t_warehouse": warehouse or "_Test Warehouse 1 - _TC",
+ "cost_center": "_Test Cost Center - _TC"
+ }
+ ]
+ })
se.set_stock_entry_type()
se.insert()
@@ -198,14 +192,7 @@
mr.insert()
mr.submit()
- # check if per complete is None
- mr.load_from_db()
- self.assertEqual(mr.per_ordered, 0)
- self.assertEqual(mr.get("items")[0].ordered_qty, 0)
- self.assertEqual(mr.get("items")[1].ordered_qty, 0)
-
# map a purchase order
- from erpnext.stock.doctype.material_request.material_request import make_purchase_order
po_doc = make_purchase_order(mr.name)
po_doc.supplier = "_Test Supplier"
po_doc.transaction_date = "2013-07-07"
@@ -276,10 +263,8 @@
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
- self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
- self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
-
- from erpnext.stock.doctype.material_request.material_request import make_stock_entry
+ self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
+ self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
# map a stock entry
se_doc = make_stock_entry(mr.name)
@@ -331,8 +316,8 @@
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
- self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 27.0)
- self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 1.5)
+ self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 27.0)
+ self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 1.5)
# check if per complete is as expected for Stock Entry cancelled
se.cancel()
@@ -344,8 +329,8 @@
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
- self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
- self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
+ self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
+ self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
def test_completed_qty_for_over_transfer(self):
existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
@@ -357,14 +342,7 @@
mr.insert()
mr.submit()
- # check if per complete is None
- mr.load_from_db()
- self.assertEqual(mr.per_ordered, 0)
- self.assertEqual(mr.get("items")[0].ordered_qty, 0)
- self.assertEqual(mr.get("items")[1].ordered_qty, 0)
-
# map a stock entry
- from erpnext.stock.doctype.material_request.material_request import make_stock_entry
se_doc = make_stock_entry(mr.name)
se_doc.update({
@@ -425,8 +403,8 @@
current_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
current_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
- self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 - 54.0)
- self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 - 3.0)
+ self.assertEqual(current_requested_qty_item1, existing_requested_qty_item1 + 54.0)
+ self.assertEqual(current_requested_qty_item2, existing_requested_qty_item2 + 3.0)
def test_incorrect_mapping_of_stock_entry(self):
# submit material request of type Transfer
@@ -435,9 +413,6 @@
mr.insert()
mr.submit()
- # map a stock entry
- from erpnext.stock.doctype.material_request.material_request import make_stock_entry
-
se_doc = make_stock_entry(mr.name)
se_doc.update({
"posting_date": "2013-03-01",
@@ -468,8 +443,6 @@
mr.insert()
mr.submit()
- # map a stock entry
- from erpnext.stock.doctype.material_request.material_request import make_stock_entry
se_doc = make_stock_entry(mr.name)
self.assertEqual(se_doc.get("items")[0].s_warehouse, "_Test Warehouse - _TC")
@@ -483,8 +456,6 @@
return flt(frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "indented_qty"))
def test_make_stock_entry_for_material_issue(self):
- from erpnext.stock.doctype.material_request.material_request import make_stock_entry
-
mr = frappe.copy_doc(test_records[0]).insert()
self.assertRaises(frappe.ValidationError, make_stock_entry,
@@ -503,8 +474,6 @@
return flt(frappe.db.get_value("Bin", {"item_code": "_Test Item Home Desktop 100",
"warehouse": "_Test Warehouse - _TC"}, "indented_qty"))
- from erpnext.stock.doctype.material_request.material_request import make_stock_entry
-
existing_requested_qty = _get_requested_qty()
mr = frappe.copy_doc(test_records[0])
@@ -563,9 +532,37 @@
item_code= %s and warehouse= %s """, (mr.items[0].item_code, mr.items[0].warehouse))[0][0]
self.assertEqual(requested_qty, new_requested_qty)
- def test_multi_uom_for_purchase(self):
- from erpnext.stock.doctype.material_request.material_request import make_purchase_order
+ def test_requested_qty_multi_uom(self):
+ existing_requested_qty = self._get_requested_qty('_Test FG Item', '_Test Warehouse - _TC')
+ mr = make_material_request(item_code='_Test FG Item', material_request_type='Manufacture',
+ uom="_Test UOM 1", conversion_factor=12)
+
+ requested_qty = self._get_requested_qty('_Test FG Item', '_Test Warehouse - _TC')
+
+ self.assertEqual(requested_qty, existing_requested_qty + 120)
+
+ work_order = raise_work_orders(mr.name)
+ wo = frappe.get_doc("Work Order", work_order[0])
+ wo.qty = 50
+ wo.wip_warehouse = "_Test Warehouse 1 - _TC"
+ wo.submit()
+
+ requested_qty = self._get_requested_qty('_Test FG Item', '_Test Warehouse - _TC')
+ self.assertEqual(requested_qty, existing_requested_qty + 70)
+
+ wo.cancel()
+
+ requested_qty = self._get_requested_qty('_Test FG Item', '_Test Warehouse - _TC')
+ self.assertEqual(requested_qty, existing_requested_qty + 120)
+
+ mr.reload()
+ mr.cancel()
+ requested_qty = self._get_requested_qty('_Test FG Item', '_Test Warehouse - _TC')
+ self.assertEqual(requested_qty, existing_requested_qty)
+
+
+ def test_multi_uom_for_purchase(self):
mr = frappe.copy_doc(test_records[0])
mr.material_request_type = 'Purchase'
item = mr.items[0]
@@ -607,7 +604,6 @@
self.assertEqual(mr.per_ordered, 100)
def test_customer_provided_parts_mr(self):
- from erpnext.stock.doctype.material_request.material_request import make_stock_entry
create_item('CUST-0987', is_customer_provided_item = 1, customer = '_Test Customer', is_purchase_item = 0)
existing_requested_qty = self._get_requested_qty("_Test Customer", "_Test Warehouse - _TC")
@@ -633,6 +629,8 @@
mr.append("items", {
"item_code": args.item_code or "_Test Item",
"qty": args.qty or 10,
+ "uom": args.uom or "_Test UOM",
+ "conversion_factor": args.conversion_factor or 1,
"schedule_date": args.schedule_date or today(),
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"cost_center": args.cost_center or "_Test Cost Center - _TC"
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 9d1dafb..5604913 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,4 @@
{
- "actions": [],
"autoname": "hash",
"creation": "2013-02-22 01:28:02",
"doctype": "DocType",
@@ -374,7 +373,10 @@
{
"fieldname": "received_qty",
"fieldtype": "Float",
- "label": "Received Quantity"
+ "label": "Received Quantity",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1
},
{
"collapsible": 1,
@@ -404,14 +406,13 @@
{
"fieldname": "manufacturer_part_no",
"fieldtype": "Data",
- "label": "Manufacturer Part Number",
- "read_only": 1
+ "label": "Manufacturer Part Number"
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-02-25 03:09:10.698967",
+ "modified": "2020-04-16 09:00:00.992835",
"modified_by": "Administrator",
"module": "Stock",
"name": "Material Request Item",
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 113da9f..40d7cc2 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -356,8 +356,8 @@
'accounts': [{
'company_name': '_Test Company',
'fixed_asset_account': '_Test Fixed Asset - _TC',
- 'accumulated_depreciation_account': 'Depreciation - _TC',
- 'depreciation_expense_account': 'Depreciation - _TC'
+ 'accumulated_depreciation_account': '_Test Accumulated Depreciations - _TC',
+ 'depreciation_expense_account': '_Test Depreciation - _TC'
}]
}).insert()
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index a8b9c81..b15f23c 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -801,8 +801,7 @@
{
"fieldname": "manufacturer_part_no",
"fieldtype": "Data",
- "label": "Manufacturer Part Number",
- "read_only": 1
+ "label": "Manufacturer Part Number"
},
{
"depends_on": "is_fixed_asset",
@@ -832,7 +831,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2020-03-11 14:19:48.799370",
+ "modified": "2020-04-07 18:38:21.141558",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 3bb9415..d1048fc 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -220,8 +220,8 @@
},
get_query_filters: {
docstatus: 1,
- material_request_type: "Material Transfer",
- status: ['!=', 'Transferred']
+ material_request_type: ["in", ["Material Transfer", "Material Issue"]],
+ status: ["not in", ["Transferred", "Issued"]]
}
})
}, __("Get items from"));
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index b1bfc90..61429cc 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -341,6 +341,9 @@
else:
out["manufacturer_part_no"] = None
out["manufacturer"] = None
+ else:
+ out["manufacturer"], out["manufacturer_part_no"] = frappe.get_value("Item", item.name,
+ ["default_item_manufacturer", "default_manufacturer_part_no"] )
child_doctype = args.doctype + ' Item'
meta = frappe.get_meta(child_doctype)
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index 2bdb04e..5697315 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -113,24 +113,30 @@
return flt(reserved_qty[0][0]) if reserved_qty else 0
def get_indented_qty(item_code, warehouse):
- inward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
- from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
- where mr_item.item_code=%s and mr_item.warehouse=%s
- and mr.material_request_type in ('Purchase', 'Manufacture')
- and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
- and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
-
- outward_qty = frappe.db.sql("""select sum((mr_item.qty - mr_item.ordered_qty) * mr_item.conversion_factor)
+ # Ordered Qty is always maintained in stock UOM
+ inward_qty = frappe.db.sql("""
+ select sum(mr_item.stock_qty - mr_item.ordered_qty)
from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
where mr_item.item_code=%s and mr_item.warehouse=%s
- and mr.material_request_type in ('Material Issue', 'Material Transfer')
- and mr_item.qty > mr_item.ordered_qty and mr_item.parent=mr.name
- and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse))
+ and mr.material_request_type in ('Purchase', 'Manufacture', 'Customer Provided', 'Material Transfer')
+ and mr_item.stock_qty > mr_item.ordered_qty and mr_item.parent=mr.name
+ and mr.status!='Stopped' and mr.docstatus=1
+ """, (item_code, warehouse))
+ inward_qty = flt(inward_qty[0][0]) if inward_qty else 0
- inward_qty, outward_qty = flt(inward_qty[0][0]) if inward_qty else 0, flt(outward_qty[0][0]) if outward_qty else 0
- indented_qty = inward_qty - outward_qty
+ outward_qty = frappe.db.sql("""
+ select sum(mr_item.stock_qty - mr_item.ordered_qty)
+ from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr
+ where mr_item.item_code=%s and mr_item.warehouse=%s
+ and mr.material_request_type = 'Material Issue'
+ and mr_item.stock_qty > mr_item.ordered_qty and mr_item.parent=mr.name
+ and mr.status!='Stopped' and mr.docstatus=1
+ """, (item_code, warehouse))
+ outward_qty = flt(outward_qty[0][0]) if outward_qty else 0
- return indented_qty
+ requested_qty = inward_qty - outward_qty
+
+ return requested_qty
def get_ordered_qty(item_code, warehouse):
ordered_qty = frappe.db.sql("""