diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 182ab42371..e42f0d8968 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.74' +__version__ = '10.1.76' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 1bb7c97b0d..bfdf451f44 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -830,6 +830,10 @@ class PurchaseInvoice(BuyingController): return tax_withholding_details = get_party_tax_withholding_details(self) + + if not tax_withholding_details: + return + accounts = [] for d in self.taxes: if d.account_head == tax_withholding_details.get("account_head"): @@ -839,6 +843,12 @@ class PurchaseInvoice(BuyingController): if not accounts or tax_withholding_details.get("account_head") not in accounts: self.append("taxes", tax_withholding_details) + to_remove = [d for d in self.taxes + if not d.tax_amount and d.account_head == tax_withholding_details.get("account_head")] + + for d in to_remove: + self.remove(d) + # calculate totals again after applying TDS self.calculate_taxes_and_totals() diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index f3ec775d54..6072fb895c 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -324,7 +324,8 @@ class SalesInvoice(SellingController): return { "print_format": print_format, "allow_edit_rate": pos.get("allow_user_to_edit_rate"), - "allow_edit_discount": pos.get("allow_user_to_edit_discount") + "allow_edit_discount": pos.get("allow_user_to_edit_discount"), + "campaign": pos.get("campaign") } def update_time_sheet(self, sales_invoice): diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 68cc500004..f9364e2d84 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals @@ -762,6 +762,20 @@ class TestSalesInvoice(unittest.TestCase): set_perpetual_inventory(0) frappe.db.sql("delete from `tabPOS Profile`") + + def test_pos_si_without_payment(self): + set_perpetual_inventory() + make_pos_profile() + + pos = copy.deepcopy(test_records[1]) + pos["is_pos"] = 1 + pos["update_stock"] = 1 + + si = frappe.copy_doc(pos) + si.insert() + + # Check that the invoice cannot be submitted without payments + self.assertRaises(frappe.ValidationError, si.submit) def test_sales_invoice_gl_entry_with_perpetual_inventory_no_item_code(self): set_perpetual_inventory() diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index f553cc09ec..6c31e9efed 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -24,6 +24,7 @@ def get_party_tax_withholding_details(ref_doc): .format(tax_withholding_category, ref_doc.company)) tds_amount = get_tds_amount(ref_doc, tax_details, fy) tax_row = get_tax_row(tax_details, tds_amount) + return tax_row def get_tax_withholding_details(tax_withholding_category, fiscal_year, company): @@ -62,46 +63,64 @@ def get_tax_row(tax_details, tds_amount): def get_tds_amount(ref_doc, tax_details, fiscal_year_details): fiscal_year, year_start_date, year_end_date = fiscal_year_details tds_amount = 0 + tds_deducted = 0 - def _get_tds(): - tds_amount = 0 - if not tax_details.threshold or ref_doc.net_total >= tax_details.threshold: - tds_amount = ref_doc.net_total * tax_details.rate / 100 - return tds_amount + def _get_tds(amount): + if amount <= 0: + return 0 - if tax_details.cumulative_threshold: - entries = frappe.db.sql(""" + return amount * tax_details.rate / 100 + + entries = frappe.db.sql(""" select voucher_no, credit from `tabGL Entry` where party=%s and fiscal_year=%s and credit > 0 """, (ref_doc.supplier, fiscal_year), as_dict=1) - supplier_credit_amount = flt(sum([d.credit for d in entries])) + vouchers = [d.voucher_no for d in entries] + advance_vouchers = get_advance_vouchers(ref_doc.supplier, fiscal_year) - vouchers = [d.voucher_no for d in entries] - vouchers += get_advance_vouchers(ref_doc.supplier, fiscal_year) + tds_vouchers = vouchers + advance_vouchers - tds_deducted = 0 - if vouchers: - tds_deducted = flt(frappe.db.sql(""" - select sum(credit) - from `tabGL Entry` - where account=%s and fiscal_year=%s and credit > 0 - and voucher_no in ({0}) - """.format(', '.join(["'%s'" % d for d in vouchers])), - (tax_details.account_head, fiscal_year))[0][0]) + if tds_vouchers: + tds_deducted = frappe.db.sql(""" + SELECT sum(credit) FROM `tabGL Entry` + WHERE + account=%s and fiscal_year=%s and credit > 0 + and voucher_no in ({0})""". format(','.join(['%s'] * len(tds_vouchers))), + ((tax_details.account_head, fiscal_year) + tuple(tds_vouchers))) + + tds_deducted = tds_deducted[0][0] if tds_deducted and tds_deducted[0][0] else 0 + + if tds_deducted: + tds_amount = _get_tds(ref_doc.net_total) + else: + supplier_credit_amount = frappe.get_all('Purchase Invoice Item', + fields = ['sum(net_amount)'], + filters = {'parent': ('in', vouchers), 'docstatus': 1}, as_list=1) + + supplier_credit_amount = (supplier_credit_amount[0][0] + if supplier_credit_amount and supplier_credit_amount[0][0] else 0) + + jv_supplier_credit_amt = frappe.get_all('Journal Entry Account', + fields = ['sum(credit_in_account_currency)'], + filters = { + 'parent': ('in', vouchers), 'docstatus': 1, + 'party': ref_doc.supplier, + 'reference_type': ('not in', ['Purchase Invoice']) + }, as_list=1) + + supplier_credit_amount += (jv_supplier_credit_amt[0][0] + if jv_supplier_credit_amt and jv_supplier_credit_amt[0][0] else 0) + + supplier_credit_amount += ref_doc.net_total debit_note_amount = get_debit_note_amount(ref_doc.supplier, year_start_date, year_end_date) + supplier_credit_amount -= debit_note_amount - total_invoiced_amount = supplier_credit_amount + tds_deducted \ - + flt(ref_doc.net_total) - debit_note_amount - if total_invoiced_amount >= tax_details.cumulative_threshold: - total_applicable_tds = total_invoiced_amount * tax_details.rate / 100 - tds_amount = min(total_applicable_tds - tds_deducted, ref_doc.net_total) - else: - tds_amount = _get_tds() - else: - tds_amount = _get_tds() + if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold) + or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)): + tds_amount = _get_tds(supplier_credit_amount) return tds_amount @@ -114,7 +133,7 @@ def get_advance_vouchers(supplier, fiscal_year=None, company=None, from_date=Non select distinct voucher_no from `tabGL Entry` where party=%s and %s and debit > 0 - """, (supplier, condition)) + """, (supplier, condition)) or [] def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None): condition = "" @@ -126,4 +145,4 @@ def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None from `tabPurchase Invoice` where supplier=%s %s and is_return=1 and docstatus=1 and posting_date between %s and %s - """, (supplier, condition, year_start_date, year_end_date))) + """, (supplier, condition, year_start_date, year_end_date))) \ No newline at end of file diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index 20e1746e36..2530196708 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import frappe import unittest from frappe.utils import today +from erpnext.accounts.utils import get_fiscal_year test_dependencies = ["Supplier Group"] @@ -14,65 +15,105 @@ class TestTaxWithholdingCategory(unittest.TestCase): def setUpClass(self): # create relevant supplier, etc create_records() + create_tax_with_holding_category() - def test_single_threshold_tds(self): - frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "TDS - 194D - Individual") - pi = create_purchase_invoice() + def test_cumulative_threshold_tds(self): + frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "Cumulative Threshold TDS") + invoices = [] + + # create invoices for lower than single threshold tax rate + for _ in xrange(2): + pi = create_purchase_invoice(supplier = "Test TDS Supplier") + pi.submit() + invoices.append(pi) + + # create another invoice whose total when added to previously created invoice, + # surpasses cumulative threshhold + pi = create_purchase_invoice(supplier = "Test TDS Supplier") pi.submit() - self.assertEqual(pi.taxes_and_charges_deducted, 800) - self.assertEqual(pi.grand_total, 15200) + # assert equal tax deduction on total invoice amount uptil now + self.assertEqual(pi.taxes_and_charges_deducted, 3000) + self.assertEqual(pi.grand_total, 7000) + invoices.append(pi) + + # TDS is already deducted, so from onward system will deduct the TDS on every invoice + pi = create_purchase_invoice(supplier = "Test TDS Supplier", rate=5000) + pi.submit() + + # assert equal tax deduction on total invoice amount uptil now + self.assertEqual(pi.taxes_and_charges_deducted, 500) + invoices.append(pi) + + #delete invoices to avoid clashing + for d in invoices: + d.cancel() + frappe.delete_doc("Purchase Invoice", d.name) + + def test_single_threshold_tds(self): + invoices = [] + frappe.db.set_value("Supplier", "Test TDS Supplier1", "tax_withholding_category", "Single Threshold TDS") + pi = create_purchase_invoice(supplier = "Test TDS Supplier1", rate = 20000) + pi.submit() + invoices.append(pi) + + self.assertEqual(pi.taxes_and_charges_deducted, 2000) + self.assertEqual(pi.grand_total, 18000) # check gl entry for the purchase invoice gl_entries = frappe.db.get_all('GL Entry', filters={'voucher_no': pi.name}, fields=["*"]) self.assertEqual(len(gl_entries), 3) for d in gl_entries: if d.account == pi.credit_to: - self.assertEqual(d.credit, 15200) + self.assertEqual(d.credit, 18000) elif d.account == pi.items[0].get("expense_account"): - self.assertEqual(d.debit, 16000) + self.assertEqual(d.debit, 20000) elif d.account == pi.taxes[0].get("account_head"): - self.assertEqual(d.credit, 800) + self.assertEqual(d.credit, 2000) else: raise ValueError("Account head does not match.") - # delete purchase invoice to avoid it interefering in other tests - pi.cancel() - frappe.delete_doc('Purchase Invoice', pi.name) - - def test_cumulative_threshold_tds(self): - frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "TDS - 194C - Individual") - invoices = [] - - # create invoices for lower than single threshold tax rate - for _ in xrange(6): - pi = create_purchase_invoice() - pi.submit() - invoices.append(pi) - - # create another invoice whose total when added to previously created invoice, - # surpasses cumulative threshhold - pi = create_purchase_invoice() + pi = create_purchase_invoice(supplier = "Test TDS Supplier1") pi.submit() - - # assert equal tax deduction on total invoice amount uptil now - self.assertEqual(pi.taxes_and_charges_deducted, 1120) - self.assertEqual(pi.grand_total, 14880) invoices.append(pi) + # TDS amount is 1000 because in previous invoices it's already deducted + self.assertEqual(pi.taxes_and_charges_deducted, 1000) + # delete invoices to avoid clashing for d in invoices: d.cancel() frappe.delete_doc("Purchase Invoice", d.name) -def create_purchase_invoice(qty=1): + def test_single_threshold_tds_with_previous_vouchers(self): + invoices = [] + frappe.db.set_value("Supplier", "Test TDS Supplier2", "tax_withholding_category", "Single Threshold TDS") + pi = create_purchase_invoice(supplier="Test TDS Supplier2") + pi.submit() + invoices.append(pi) + + pi = create_purchase_invoice(supplier="Test TDS Supplier2") + pi.submit() + invoices.append(pi) + + self.assertEqual(pi.taxes_and_charges_deducted, 2000) + self.assertEqual(pi.grand_total, 8000) + + # delete invoices to avoid clashing + for d in invoices: + d.cancel() + frappe.delete_doc("Purchase Invoice", d.name) + +def create_purchase_invoice(**args): # return sales invoice doc object item = frappe.get_doc('Item', {'item_name': 'TDS Item'}) + + args = frappe._dict(args) pi = frappe.get_doc({ "doctype": "Purchase Invoice", "posting_date": today(), "apply_tds": 1, - "supplier": frappe.get_doc('Supplier', {"supplier_name": "Test TDS Supplier"}).name, + "supplier": args.supplier, "company": '_Test Company', "taxes_and_charges": "", "currency": "INR", @@ -81,8 +122,8 @@ def create_purchase_invoice(qty=1): "items": [{ 'doctype': 'Purchase Invoice Item', 'item_code': item.name, - 'qty': qty, - 'rate': 16000, + 'qty': args.qty or 1, + 'rate': args.rate or 10000, 'cost_center': 'Main - _TC', 'expense_account': 'Stock Received But Not Billed - _TC' }] @@ -92,20 +133,73 @@ def create_purchase_invoice(qty=1): return pi def create_records(): - # create a new supplier - frappe.get_doc({ - "supplier_group": "_Test Supplier Group", - "supplier_name": "Test TDS Supplier", - "doctype": "Supplier", - "tax_withholding_category": "TDS - 194D - Individual" - }).insert() + # create a new suppliers + for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']: + if frappe.db.exists('Supplier', name): + continue + + frappe.get_doc({ + "supplier_group": "_Test Supplier Group", + "supplier_name": name, + "doctype": "Supplier", + }).insert() # create an item - frappe.get_doc({ - "doctype": "Item", - "item_code": "TDS Item", - "item_name": "TDS Item", - "item_group": "All Item Groups", - "company": "_Test Company", - "is_stock_item": 0, - }).insert() \ No newline at end of file + if not frappe.db.exists('Item', "TDS Item"): + frappe.get_doc({ + "doctype": "Item", + "item_code": "TDS Item", + "item_name": "TDS Item", + "item_group": "All Item Groups", + "is_stock_item": 0, + }).insert() + + # create an account + if not frappe.db.exists("Account", "TDS - _TC"): + frappe.get_doc({ + 'doctype': 'Account', + 'company': '_Test Company', + 'account_name': 'TDS', + 'parent_account': 'Tax Assets - _TC', + 'report_type': 'Balance Sheet', + 'root_type': 'Asset' + }).insert() + +def create_tax_with_holding_category(): + fiscal_year = get_fiscal_year(today(), company="_Test Company")[0] + + # Cummulative thresold + if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TDS"): + frappe.get_doc({ + "doctype": "Tax Withholding Category", + "name": "Cumulative Threshold TDS", + "category_name": "10% TDS", + "rates": [{ + 'fiscal_year': fiscal_year, + 'tax_withholding_rate': 10, + 'single_threshold': 0, + 'cumulative_threshold': 30000.00 + }], + "accounts": [{ + 'company': '_Test Company', + 'account': 'TDS - _TC' + }] + }).insert() + + # Single thresold + if not frappe.db.exists("Tax Withholding Category", "Single Threshold TDS"): + frappe.get_doc({ + "doctype": "Tax Withholding Category", + "name": "Single Threshold TDS", + "category_name": "10% TDS", + "rates": [{ + 'fiscal_year': fiscal_year, + 'tax_withholding_rate': 10, + 'single_threshold': 20000.00, + 'cumulative_threshold': 0 + }], + "accounts": [{ + 'company': '_Test Company', + 'account': 'TDS - _TC' + }] + }).insert() \ No newline at end of file diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 91f3711f8d..04c8718ad9 100755 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -1135,16 +1135,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }, apply_category: function() { - var me = this; - category = this.selected_item_group || "All Item Groups"; + frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name", (r) => { + category = this.selected_item_group || r.name; - if(category == 'All Item Groups') { - return this.item_data - } else { - return this.item_data.filter(function(element, index, array){ - return element.item_group == category; - }); - } + if(category == r.name) { + return this.item_data + } else { + return this.item_data.filter(function(element, index, array){ + return element.item_group == category; + }); + } + }) + }, bind_items_event: function() { diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index d446c5b35a..207e28bef2 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe, erpnext from frappe import _, msgprint, scrub -from frappe.defaults import get_user_permissions +from frappe.core.doctype.user_permission.user_permission import get_permitted_documents from frappe.model.utils import get_fetch_values from frappe.utils import (add_days, getdate, formatdate, date_diff, add_years, get_timestamp, nowdate, flt, add_months, get_last_day) @@ -151,10 +151,7 @@ def get_default_price_list(party): def set_price_list(out, party, party_type, given_price_list): # price list - price_list = filter(None, get_user_permissions() - .get("Price List", {}) - .get("docs", [])) - price_list = list(price_list) + price_list = get_permitted_documents('Price List') if price_list: price_list = price_list[0] diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 36200c7868..e72f59a893 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -91,6 +91,7 @@ class PurchaseOrder(BuyingController): self.party_account_currency = get_party_account_currency("Supplier", self.supplier, self.company) def validate_minimum_order_qty(self): + if not self.get("items"): return items = list(set([d.item_code for d in self.get("items")])) itemwise_min_order_qty = frappe._dict(frappe.db.sql("""select name, min_order_qty diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py index 15996c3a44..9d8e1bf3c3 100644 --- a/erpnext/config/accounts.py +++ b/erpnext/config/accounts.py @@ -561,10 +561,6 @@ def get_data(): "label": _("Subscription Management"), "icon": "fa fa-microchip ", "items": [ - { - "type": "doctype", - "name": "Subscriber", - }, { "type": "doctype", "name": "Subscription Plan", diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 03e964581b..19616c5b84 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -678,7 +678,7 @@ class BuyingController(StockController): frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name) def validate_schedule_date(self): - if not self.schedule_date: + if not self.schedule_date and self.get("items"): self.schedule_date = min([d.schedule_date for d in self.get("items")]) if self.schedule_date: diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 7b3f740462..63e89ab6e3 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -12,6 +12,9 @@ from erpnext.controllers.accounts_controller import AccountsController from erpnext.stock.stock_ledger import get_valuation_rate from erpnext.stock import get_warehouse_account_map +class QualityInspectionRequiredError(frappe.ValidationError): pass +class QualityInspectionRejectedError(frappe.ValidationError): pass + class StockController(AccountsController): def validate(self): super(StockController, self).validate() @@ -317,7 +320,6 @@ class StockController(AccountsController): def validate_inspection(self): '''Checks if quality inspection is set for Items that require inspection. On submit, throw an exception''' - inspection_required_fieldname = None if self.doctype in ["Purchase Receipt", "Purchase Invoice"]: inspection_required_fieldname = "inspection_required_before_purchase" @@ -330,17 +332,25 @@ class StockController(AccountsController): return for d in self.get('items'): - raise_exception = False + qa_required = False if (inspection_required_fieldname and not d.quality_inspection and frappe.db.get_value("Item", d.item_code, inspection_required_fieldname)): - raise_exception = True + qa_required = True elif self.doctype == "Stock Entry" and not d.quality_inspection and d.t_warehouse: - raise_exception = True + qa_required = True - if raise_exception: + if qa_required: frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code)) if self.docstatus==1: - raise frappe.ValidationError + raise QualityInspectionRequiredError + elif self.docstatus == 1: + if d.quality_inspection: + qa_doc = frappe.get_doc("Quality Inspection", d.quality_inspection) + qa_failed = any([r.status=="Rejected" for r in qa_doc.readings]) + if qa_failed: + frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}") + .format(d.idx, d.item_code), QualityInspectionRejectedError) + def update_blanket_order(self): blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order])) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index a6585d6347..78db6d3e14 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" develop_version = '12.x.x-develop' -staging_version = '11.0.3-beta.31' +staging_version = '11.0.3-beta.32' error_report_email = "support@erpnext.com" diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py index cb4c1908fb..66d9badd2a 100755 --- a/erpnext/hr/doctype/employee/employee.py +++ b/erpnext/hr/doctype/employee/employee.py @@ -62,8 +62,8 @@ class Employee(NestedSet): def validate_user_details(self): data = frappe.db.get_value('User', self.user_id, ['enabled', 'user_image'], as_dict=1) - - self.image = data.get("user_image") + if data.get("user_image"): + self.image = data.get("user_image") self.validate_for_enabled_user_id(data.get("enabled", 0)) self.validate_duplicate_user_id() diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js index a77dd32c49..5bce348489 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.js +++ b/erpnext/hr/doctype/leave_application/leave_application.js @@ -14,7 +14,7 @@ frappe.ui.form.on("Leave Application", { doctype: frm.doc.doctype } }; - }); + }); frm.set_query("employee", erpnext.queries.employee); }, @@ -83,7 +83,7 @@ frappe.ui.form.on("Leave Application", { if (!frm.doc.employee && frappe.defaults.get_user_permissions()) { const perm = frappe.defaults.get_user_permissions(); if (perm && perm['Employee']) { - frm.set_value('employee', perm['Employee']["docs"][0]) + frm.set_value('employee', perm['Employee'].map(perm_doc => perm_doc.doc)[0]); } } }, diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py index 7ead14030f..202ae9bcfe 100644 --- a/erpnext/hr/doctype/salary_structure/salary_structure.py +++ b/erpnext/hr/doctype/salary_structure/salary_structure.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import flt, cint +from frappe.utils import flt, cint, cstr from frappe import _ from frappe.model.mapper import get_mapped_doc from frappe.model.document import Document @@ -22,7 +22,7 @@ class SalaryStructure(Document): overwritten_fields_if_missing = ["amount_based_on_formula", "formula", "amount"] for table in ["earnings", "deductions"]: for d in self.get(table): - component_default_value = frappe.db.get_value("Salary Component", str(d.salary_component), + component_default_value = frappe.db.get_value("Salary Component", cstr(d.salary_component), overwritten_fields + overwritten_fields_if_missing, as_dict=1) if component_default_value: for fieldname in overwritten_fields: diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index a01011a178..2615b31782 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -402,6 +402,8 @@ frappe.ui.form.on("BOM Item", "items_remove", function(frm) { var toggle_operations = function(frm) { frm.toggle_display("operations_section", cint(frm.doc.with_operations) == 1); + frm.toggle_display("transfer_material_against", cint(frm.doc.with_operations) == 1); + frm.toggle_reqd("transfer_material_against", cint(frm.doc.with_operations) == 1); }; frappe.ui.form.on("BOM", "with_operations", function(frm) { diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json index 8c5f2af96a..0cf7dc4f81 100644 --- a/erpnext/manufacturing/doctype/bom/bom.json +++ b/erpnext/manufacturing/doctype/bom/bom.json @@ -80,41 +80,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials", - "fieldname": "quantity", - "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": "Quantity", - "length": 0, - "no_copy": 0, - "oldfieldname": "quantity", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "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, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -154,8 +119,10 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "inspection_required", - "fieldtype": "Check", + "default": "1", + "description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials", + "fieldname": "quantity", + "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -163,51 +130,18 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Inspection Required", + "label": "Quantity", "length": 0, "no_copy": 0, + "oldfieldname": "quantity", + "oldfieldtype": "Currency", "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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "inspection_required", - "fieldname": "quality_inspection_template", - "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": "Quality Inspection Template", - "length": 0, - "no_copy": 0, - "options": "Quality Inspection Template", - "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, + "reqd": 1, "search_index": 0, "set_only_once": 0, "translatable": 0, @@ -346,77 +280,11 @@ { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, - "allow_on_submit": 1, + "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "rm_cost_as_per", - "fieldtype": "Select", - "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": "Rate Of Materials Based On", - "length": 0, - "no_copy": 0, - "options": "Valuation Rate\nLast Purchase Rate\nPrice List", - "permlevel": 0, - "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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.rm_cost_as_per===\"Price List\"", - "fieldname": "buying_price_list", - "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": "Price List", - "length": 0, - "no_copy": 0, - "options": "Price List", - "permlevel": 0, - "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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fieldname": "set_rate_of_sub_assembly_item_based_on_bom", + "fieldname": "inspection_required", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -425,7 +293,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Set rate of sub-assembly item based on BOM", + "label": "Inspection Required", "length": 0, "no_copy": 0, "permlevel": 0, @@ -481,7 +349,7 @@ "collapsible": 0, "columns": 0, "fieldname": "allow_same_item_multiple_times", - "fieldtype": "Data", + "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -508,12 +376,12 @@ { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "with_operations", - "fieldname": "transfer_material_against_job_card", + "default": "1", + "fieldname": "set_rate_of_sub_assembly_item_based_on_bom", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -522,7 +390,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Transfer Material Against Job Card", + "label": "Set rate of sub-assembly item based on BOM", "length": 0, "no_copy": 0, "permlevel": 0, @@ -538,6 +406,40 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "inspection_required", + "fieldname": "quality_inspection_template", + "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": "Quality Inspection Template", + "length": 0, + "no_copy": 0, + "options": "Quality Inspection Template", + "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, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -603,6 +505,72 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fieldname": "transfer_material_against", + "fieldtype": "Select", + "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": "Transfer Material Against", + "length": 0, + "no_copy": 0, + "options": "\nWork Order\nJob Card", + "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, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "conversion_rate", + "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": "Conversion Rate", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "9", + "print_hide": 0, + "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, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -670,12 +638,12 @@ { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "conversion_rate", - "fieldtype": "Float", + "fieldname": "rm_cost_as_per", + "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -683,17 +651,50 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Conversion Rate", + "label": "Rate Of Materials Based On", "length": 0, "no_copy": 0, + "options": "Valuation Rate\nLast Purchase Rate\nPrice List", "permlevel": 0, - "precision": "9", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.rm_cost_as_per===\"Price List\"", + "fieldname": "buying_price_list", + "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": "Price List", + "length": 0, + "no_copy": 0, + "options": "Price List", + "permlevel": 0, + "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, "translatable": 0, @@ -707,7 +708,7 @@ "collapsible": 0, "columns": 0, "depends_on": "", - "description": "Specify the operations, operating cost and give a unique Operation no to your operations.", + "description": "", "fieldname": "operations_section", "fieldtype": "Section Break", "hidden": 0, @@ -1976,7 +1977,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-10-24 02:07:21.618275", + "modified": "2018-12-13 17:45:44.843197", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM", diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 4de48e179a..a8053cdf4a 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -81,7 +81,7 @@ class BOM(WebsiteGenerator): def get_item_det(self, item_code): item = frappe.db.sql("""select name, item_name, docstatus, description, image, - is_sub_contracted_item, stock_uom, default_bom, last_purchase_rate, allow_transfer_for_manufacture + is_sub_contracted_item, stock_uom, default_bom, last_purchase_rate, include_item_in_manufacturing from `tabItem` where name=%s""", item_code, as_dict = 1) if not item: @@ -109,7 +109,7 @@ class BOM(WebsiteGenerator): "item_name": item.item_name, "bom_no": item.bom_no, "stock_qty": item.stock_qty, - "allow_transfer_for_manufacture": item.allow_transfer_for_manufacture + "include_item_in_manufacturing": item.include_item_in_manufacturing }) for r in ret: if not item.get(r): @@ -128,8 +128,8 @@ class BOM(WebsiteGenerator): self.validate_rm_item(item) args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or '' - args['transfer_for_manufacture'] = (cstr(args.get('allow_transfer_for_manufacture', '')) or - item and item[0].allow_transfer_for_manufacture or 0) + args['transfer_for_manufacture'] = (cstr(args.get('include_item_in_manufacturing', '')) or + item and item[0].include_item_in_manufacturing or 0) args.update(item[0]) rate = self.get_rm_rate(args) @@ -145,7 +145,7 @@ class BOM(WebsiteGenerator): 'qty' : args.get("qty") or args.get("stock_qty") or 1, 'stock_qty' : args.get("qty") or args.get("stock_qty") or 1, 'base_rate' : rate, - 'allow_transfer_for_manufacture': cint(args['transfer_for_manufacture']) or 0 + 'include_item_in_manufacturing': cint(args['transfer_for_manufacture']) or 0 } return ret_item @@ -479,7 +479,7 @@ class BOM(WebsiteGenerator): 'stock_uom' : d.stock_uom, 'stock_qty' : flt(d.stock_qty), 'rate' : d.base_rate, - 'allow_transfer_for_manufacture': d.allow_transfer_for_manufacture + 'include_item_in_manufacturing': d.include_item_in_manufacturing })) def company_currency(self): @@ -496,7 +496,7 @@ class BOM(WebsiteGenerator): # Did not use qty_consumed_per_unit in the query, as it leads to rounding loss child_fb_items = frappe.db.sql("""select bom_item.item_code, bom_item.item_name, bom_item.description, bom_item.source_warehouse, bom_item.operation, - bom_item.stock_uom, bom_item.stock_qty, bom_item.rate, bom_item.allow_transfer_for_manufacture, + bom_item.stock_uom, bom_item.stock_qty, bom_item.rate, bom_item.include_item_in_manufacturing, bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit from `tabBOM Explosion Item` bom_item, tabBOM bom where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1) @@ -511,7 +511,7 @@ class BOM(WebsiteGenerator): 'stock_uom' : d['stock_uom'], 'stock_qty' : d['qty_consumed_per_unit'] * stock_qty, 'rate' : flt(d['rate']), - 'allow_transfer_for_manufacture': d.get('allow_transfer_for_manufacture', 0) + 'include_item_in_manufacturing': d.get('include_item_in_manufacturing', 0) })) def add_exploded_items(self): @@ -587,7 +587,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite query = query.format(table="BOM Explosion Item", where_conditions="", is_stock_item=is_stock_item, - select_columns = """, bom_item.source_warehouse, bom_item.operation, bom_item.allow_transfer_for_manufacture, + select_columns = """, bom_item.source_warehouse, bom_item.operation, bom_item.include_item_in_manufacturing, (Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s ) as idx""") items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True) @@ -596,7 +596,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True) else: query = query.format(table="BOM Item", where_conditions="", is_stock_item=is_stock_item, - select_columns = ", bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.allow_transfer_for_manufacture") + select_columns = ", bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing") items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True) for item in items: diff --git a/erpnext/manufacturing/doctype/bom/test_records.json b/erpnext/manufacturing/doctype/bom/test_records.json index 1a7e594e87..25730f9b9f 100644 --- a/erpnext/manufacturing/doctype/bom/test_records.json +++ b/erpnext/manufacturing/doctype/bom/test_records.json @@ -11,7 +11,7 @@ "uom": "_Test UOM", "stock_uom": "_Test UOM", "source_warehouse": "_Test Warehouse - _TC", - "allow_transfer_for_manufacture": 1 + "include_item_in_manufacturing": 1 }, { "amount": 2000.0, @@ -23,7 +23,7 @@ "uom": "_Test UOM", "stock_uom": "_Test UOM", "source_warehouse": "_Test Warehouse - _TC", - "allow_transfer_for_manufacture": 1 + "include_item_in_manufacturing": 1 } ], "docstatus": 1, @@ -57,7 +57,7 @@ "uom": "_Test UOM", "stock_uom": "_Test UOM", "source_warehouse": "_Test Warehouse - _TC", - "allow_transfer_for_manufacture": 1 + "include_item_in_manufacturing": 1 }, { "amount": 2000.0, @@ -69,7 +69,7 @@ "uom": "_Test UOM", "stock_uom": "_Test UOM", "source_warehouse": "_Test Warehouse - _TC", - "allow_transfer_for_manufacture": 1 + "include_item_in_manufacturing": 1 } ], "docstatus": 1, @@ -102,7 +102,7 @@ "uom": "_Test UOM", "stock_uom": "_Test UOM", "source_warehouse": "_Test Warehouse - _TC", - "allow_transfer_for_manufacture": 1 + "include_item_in_manufacturing": 1 }, { "amount": 3000.0, @@ -115,7 +115,7 @@ "uom": "_Test UOM", "stock_uom": "_Test UOM", "source_warehouse": "_Test Warehouse - _TC", - "allow_transfer_for_manufacture": 1 + "include_item_in_manufacturing": 1 } ], "docstatus": 1, @@ -150,7 +150,7 @@ "uom": "_Test UOM", "stock_uom": "_Test UOM", "source_warehouse": "_Test Warehouse - _TC", - "allow_transfer_for_manufacture": 1 + "include_item_in_manufacturing": 1 } ], "docstatus": 1, diff --git a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json index ab3c5a1205..9fadbef0f5 100644 --- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json +++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -573,7 +574,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "allow_transfer_for_manufacture", + "fieldname": "include_item_in_manufacturing", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -582,7 +583,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Allow Transfer for Manufacture", + "label": "Include Item In Manufacturing", "length": 0, "no_copy": 0, "permlevel": 0, @@ -609,7 +610,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-08-27 16:32:35.152139", + "modified": "2018-11-20 19:04:59.813773", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Explosion Item", diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json index cc69471eba..8a380f755b 100644 --- a/erpnext/manufacturing/doctype/bom_item/bom_item.json +++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json @@ -79,34 +79,67 @@ "unique": 0 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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_global_search": 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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "operation", + "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": "Item operation", + "length": 0, + "no_copy": 0, + "options": "Operation", + "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, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 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_global_search": 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, + "translatable": 0, "unique": 0 }, { @@ -932,8 +965,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fetch_from": "item_code.allow_transfer_for_manufacture", - "fieldname": "allow_transfer_for_manufacture", + "fetch_from": "item_code.include_item_in_manufacturing", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -942,7 +974,6 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Allow Transfer for Manufacture", "length": 0, "no_copy": 0, "permlevel": 0, @@ -956,6 +987,29 @@ "search_index": 0, "set_only_once": 0, "translatable": 0, + "fieldname": "include_item_in_manufacturing", + "fieldtype": "Check", + "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": "Include Item In Manufacturing", + "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, + "translatable": 0, "unique": 0 }, { @@ -1023,6 +1077,38 @@ "set_only_once": 0, "translatable": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "allow_alternative_item", + "fieldtype": "Check", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Allow Alternative Item", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "translatable": 0, + "unique": 0 } ], "has_web_view": 0, @@ -1035,7 +1121,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-11-22 15:04:55.187136", + "modified": "2018-12-26 15:04:56.187136", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Item", diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 6f5290e9ca..3fe9b8af30 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -3,7 +3,7 @@ frappe.ui.form.on('Job Card', { refresh: function(frm) { - if (frm.doc.items && frm.doc.docstatus==1) { + if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) { if (frm.doc.for_quantity != frm.doc.transferred_qty) { frm.add_custom_button(__("Material Request"), () => { frm.trigger("make_material_request"); @@ -31,6 +31,7 @@ frappe.ui.form.on('Job Card', { frm.add_custom_button(__("Complete Job"), () => { frm.set_value('actual_end_date', frappe.datetime.now_datetime()); frm.save(); + frm.savesubmit(); }); } } diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json index 443cad8666..b020c89053 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.json +++ b/erpnext/manufacturing/doctype/job_card/job_card.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -46,6 +47,39 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "bom_no", + "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": "BOM No", + "length": 0, + "no_copy": 0, + "options": "BOM", + "permlevel": 0, + "precision": "", + "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, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -112,39 +146,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "wip_warehouse", - "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": "WIP Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "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, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -281,9 +282,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "default": "0", - "fieldname": "transferred_qty", - "fieldtype": "Float", + "fieldname": "wip_warehouse", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -291,17 +291,18 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Transferred Qty", + "label": "WIP Warehouse", "length": 0, "no_copy": 0, + "options": "Warehouse", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "translatable": 0, @@ -635,8 +636,9 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "bom_no", - "fieldtype": "Link", + "default": "0", + "fieldname": "transferred_qty", + "fieldtype": "Float", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -644,10 +646,42 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "BOM No", + "label": "Transferred Qty", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "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, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "fieldname": "requested_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": "Requested Qty", "length": 0, "no_copy": 0, - "options": "BOM", "permlevel": 0, "precision": "", "print_hide": 0, @@ -701,8 +735,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "column_break_20", - "fieldtype": "Column Break", + "fieldname": "remarks", + "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -710,6 +744,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, + "label": "Remarks", "length": 0, "no_copy": 0, "permlevel": 0, @@ -732,8 +767,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "remarks", - "fieldtype": "Small Text", + "fieldname": "column_break_20", + "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -741,7 +776,6 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Remarks", "length": 0, "no_copy": 0, "permlevel": 0, @@ -776,13 +810,13 @@ "in_standard_filter": 0, "label": "Status", "length": 0, - "no_copy": 0, - "options": "Open\nWork In Progress\nCancelled\nCompleted", + "no_copy": 1, + "options": "Open\nWork In Progress\nMaterial Transferred\nSubmitted\nCancelled\nCompleted", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -834,7 +868,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-08-28 16:50:43.576151", + "modified": "2018-12-13 17:23:57.986381", "modified_by": "Administrator", "module": "Manufacturing", "name": "Job Card", diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py index bc745350a7..5343a280ca 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.py +++ b/erpnext/manufacturing/doctype/job_card/job_card.py @@ -11,9 +11,9 @@ from frappe.model.document import Document class JobCard(Document): def validate(self): - self.status = 'Open' self.validate_actual_dates() self.set_time_in_mins() + self.set_status() def validate_actual_dates(self): if get_datetime(self.actual_start_date) > get_datetime(self.actual_end_date): @@ -48,7 +48,7 @@ class JobCard(Document): return doc = frappe.get_doc('Work Order', self.get('work_order')) - if not doc.transfer_material_against_job_card and doc.skip_transfer: + if doc.transfer_material_against == 'Work Order' and doc.skip_transfer: return for d in doc.required_items: @@ -104,20 +104,23 @@ class JobCard(Document): wo.set_actual_dates() wo.save() - def set_transferred_qty(self): + def set_transferred_qty(self, update_status=False): if not self.items: self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0 if self.items: - self.transferred_qty = frappe.db.get_value('Stock Entry', {'job_card': self.name, - 'work_order': self.work_order, 'docstatus': 1}, 'sum(fg_completed_qty)') or 0 + self.transferred_qty = frappe.db.get_value('Stock Entry', { + 'job_card': self.name, + 'work_order': self.work_order, + 'docstatus': 1 + }, 'sum(fg_completed_qty)') or 0 self.db_set("transferred_qty", self.transferred_qty) qty = 0 if self.work_order: doc = frappe.get_doc('Work Order', self.work_order) - if doc.transfer_material_against_job_card and not doc.skip_transfer: + if doc.transfer_material_against == 'Job Card' and not doc.skip_transfer: completed = True for d in doc.operations: if d.status != 'Completed': @@ -131,15 +134,28 @@ class JobCard(Document): doc.db_set('material_transferred_for_manufacturing', qty) - self.set_status() + self.set_status(update_status) - def set_status(self): - status = 'Cancelled' if self.docstatus == 2 else 'Work In Progress' + def set_status(self, update_status=False): + self.status = { + 0: "Open", + 1: "Submitted", + 2: "Cancelled" + }[self.docstatus or 0] - if self.for_quantity == self.transferred_qty: - status = 'Completed' + if self.actual_start_date: + self.status = 'Work In Progress' - self.db_set('status', status) + if (self.docstatus == 1 and + (self.for_quantity == self.transferred_qty or not self.items)): + self.status = 'Completed' + + if self.status != 'Completed': + if self.for_quantity == self.transferred_qty: + self.status = 'Material Transferred' + + if update_status: + self.db_set('status', self.status) @frappe.whitelist() def make_material_request(source_name, target_doc=None): diff --git a/erpnext/manufacturing/doctype/job_card/job_card_list.js b/erpnext/manufacturing/doctype/job_card/job_card_list.js index d40a9fa495..ed851ebc83 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card_list.js +++ b/erpnext/manufacturing/doctype/job_card/job_card_list.js @@ -6,6 +6,8 @@ frappe.listview_settings['Job Card'] = { return [__("Completed"), "green", "status,=,Completed"]; } else if (doc.docstatus == 2) { return [__("Cancelled"), "red", "status,=,Cancelled"]; + } else if (doc.status === "Material Transferred") { + return [__('Material Transferred'), "blue", "status,=,Material Transferred"]; } else { return [__("Open"), "red", "status,=,Open"]; } diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 431ad32558..69381c53b3 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -306,7 +306,7 @@ class TestWorkOrder(unittest.TestCase): items = {'Finished Good Transfer Item': 1, '_Test FG Item': 1, '_Test FG Item 1': 0} for item, allow_transfer in items.items(): make_item(item, { - 'allow_transfer_for_manufacture': allow_transfer + 'include_item_in_manufacturing': allow_transfer }) fg_item = 'Finished Good Transfer Item' diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js index e85b0a5411..7b2f9a4bff 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.js +++ b/erpnext/manufacturing/doctype/work_order/work_order.js @@ -112,11 +112,20 @@ frappe.ui.form.on("Work Order", { frm.trigger('show_progress'); } - if (frm.doc.docstatus === 1 && frm.doc.operations + if (frm.doc.docstatus === 1 + && frm.doc.operations && frm.doc.operations.length && frm.doc.qty != frm.doc.material_transferred_for_manufacturing) { - frm.add_custom_button(__('Make Job Card'), () => { - frm.trigger("make_job_card") - }).addClass('btn-primary'); + const not_completed = frm.doc.operations.filter(d => { + if(d.status != 'Completed') { + return true; + } + }); + + if(not_completed && not_completed.length) { + frm.add_custom_button(__('Make Job Card'), () => { + frm.trigger("make_job_card") + }).addClass('btn-primary'); + } } if(frm.doc.required_items && frm.doc.allow_alternative_item) { @@ -294,7 +303,7 @@ frappe.ui.form.on("Work Order", { frm.trigger('set_sales_order'); erpnext.in_production_item_onchange = true; $.each(["description", "stock_uom", "project", "bom_no", - "allow_alternative_item", "transfer_material_against_job_card"], function(i, field) { + "allow_alternative_item", "transfer_material_against"], function(i, field) { frm.set_value(field, r.message[field]); }); @@ -340,9 +349,8 @@ frappe.ui.form.on("Work Order", { before_submit: function(frm) { frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true); frm.fields_dict.required_items.grid.toggle_reqd("source_warehouse", true); - if (frm.doc.operations) { - frm.fields_dict.operations.grid.toggle_reqd("workstation", true); - } + frm.toggle_reqd("transfer_material_against", frm.doc.operations); + frm.fields_dict.operations.grid.toggle_reqd("workstation", frm.doc.operations); }, set_sales_order: function(frm) { @@ -425,7 +433,7 @@ erpnext.work_order = { } const show_start_btn = (frm.doc.skip_transfer - || frm.doc.transfer_material_against_job_card) ? 0 : 1; + || frm.doc.transfer_material_against == 'Job Card') ? 0 : 1; if (show_start_btn){ if ((flt(doc.material_transferred_for_manufacturing) < flt(doc.qty)) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json index df9dd83a70..a65d04f61b 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.json +++ b/erpnext/manufacturing/doctype/work_order/work_order.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, @@ -183,6 +184,38 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "allow_alternative_item", + "fieldtype": "Check", + "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": "Allow Alternative Item", + "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, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -223,7 +256,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "allow_alternative_item", + "description": "Check if material transfer entry is not required", + "fieldname": "skip_transfer", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -232,7 +266,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Allow Alternative Item", + "label": "Skip Material Transfer", "length": 0, "no_copy": 0, "permlevel": 0, @@ -486,39 +520,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Check if material transfer entry is not required", - "fieldname": "skip_transfer", - "fieldtype": "Check", - "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": "Skip Material Transfer", - "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, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -552,39 +553,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "operations", - "fieldname": "transfer_material_against_job_card", - "fieldtype": "Check", - "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": "Transfer Material Against Job Card", - "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, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1070,6 +1038,41 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Work Order", + "depends_on": "operations", + "fieldname": "transfer_material_against", + "fieldtype": "Select", + "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": "Transfer Material Against", + "length": 0, + "no_copy": 0, + "options": "\nWork Order\nJob Card", + "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, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1672,7 +1675,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-09-05 06:28:22.983369", + "modified": "2018-12-13 15:33:12.490710", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order", diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index e73328f10e..9873efa124 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -191,7 +191,7 @@ class WorkOrder(Document): for purpose, fieldname in (("Manufacture", "produced_qty"), ("Material Transfer for Manufacture", "material_transferred_for_manufacturing")): if (purpose == 'Material Transfer for Manufacture' and - self.operations and self.transfer_material_against_job_card): + self.operations and self.transfer_material_against == 'Job Card'): continue qty = flt(frappe.db.sql("""select sum(fg_completed_qty) @@ -459,7 +459,7 @@ class WorkOrder(Document): 'allow_alternative_item': item.allow_alternative_item, 'required_qty': item.qty, 'source_warehouse': item.source_warehouse or item.default_warehouse, - 'allow_transfer_for_manufacture': item.allow_transfer_for_manufacture + 'include_item_in_manufacturing': item.include_item_in_manufacturing }) self.set_available_qty() @@ -564,11 +564,11 @@ def get_item_details(item, project = None): frappe.throw(_("Default BOM for {0} not found").format(item)) bom_data = frappe.db.get_value('BOM', res['bom_no'], - ['project', 'allow_alternative_item', 'transfer_material_against_job_card'], as_dict=1) + ['project', 'allow_alternative_item', 'transfer_material_against'], as_dict=1) res['project'] = project or bom_data.project res['allow_alternative_item'] = bom_data.allow_alternative_item - res['transfer_material_against_job_card'] = bom_data.transfer_material_against_job_card + res['transfer_material_against'] = bom_data.transfer_material_against res.update(check_if_scrap_warehouse_mandatory(res["bom_no"])) return res @@ -682,7 +682,7 @@ def create_job_card(work_order, row, qty=0, auto_create=False): 'wip_warehouse': work_order.wip_warehouse }) - if work_order.transfer_material_against_job_card and not work_order.skip_transfer: + if work_order.transfer_material_against == 'Job Card' and not work_order.skip_transfer: doc.get_required_items() if auto_create: diff --git a/erpnext/manufacturing/doctype/work_order_item/work_order_item.json b/erpnext/manufacturing/doctype/work_order_item/work_order_item.json index 1db11f7691..4442162636 100644 --- a/erpnext/manufacturing/doctype/work_order_item/work_order_item.json +++ b/erpnext/manufacturing/doctype/work_order_item/work_order_item.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_events_in_timeline": 0, "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, @@ -342,7 +343,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "allow_transfer_for_manufacture", + "fieldname": "include_item_in_manufacturing", "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, @@ -351,7 +352,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Allow Transfer for Manufacture", + "label": "Include Item In Manufacturing", "length": 0, "no_copy": 0, "permlevel": 0, @@ -506,7 +507,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2018-10-04 16:16:54.237829", + "modified": "2018-11-20 19:04:38.508839", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order Item", diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 4a67eb4e47..9b8a69d2b2 100755 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -495,7 +495,7 @@ erpnext.patches.v10_0.set_b2c_limit erpnext.patches.v10_0.update_translatable_fields erpnext.patches.v10_0.rename_offer_letter_to_job_offer execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True) -erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group +erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group # 24-12-2018 erpnext.patches.v10_0.add_default_cash_flow_mappers erpnext.patches.v11_0.make_quality_inspection_template erpnext.patches.v10_0.update_status_for_multiple_source_in_po @@ -579,3 +579,4 @@ erpnext.patches.v10_0.update_user_image_in_employee erpnext.patches.v11_0.update_delivery_trip_status erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items erpnext.patches.v11_0.set_missing_gst_hsn_code +erpnext.patches.v11_0.rename_bom_wo_fields diff --git a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py index 3d15bbc731..102b6da875 100644 --- a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py +++ b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py @@ -6,37 +6,36 @@ import frappe def execute(): - frappe.reload_doc("hr", "doctype", "daily_work_summary_group") - frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user") + if not frappe.db.table_exists('Daily Work Summary Group'): + frappe.reload_doc("hr", "doctype", "daily_work_summary_group") + frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user") - # check if Daily Work Summary Settings Company table exists - try: - frappe.db.sql('DESC `tabDaily Work Summary Settings Company`') - except Exception: - return + # check if Daily Work Summary Settings Company table exists + try: + frappe.db.sql('DESC `tabDaily Work Summary Settings Company`') + except Exception: + return - # get the previously saved settings - previous_setting = get_previous_setting() - if previous_setting["companies"]: - for d in previous_setting["companies"]: - users = frappe.get_list("Employee", dict( - company=d.company, user_id=("!=", " ")), "user_id as user") - if(len(users)): - # create new group entry for each company entry - new_group = frappe.get_doc(dict(doctype="Daily Work Summary Group", - name="Daily Work Summary for " + d.company, - users=users, - send_emails_at=d.send_emails_at, - subject=previous_setting["subject"], - message=previous_setting["message"])) - new_group.flags.ignore_permissions = True - new_group.flags.ignore_validate = True - new_group.insert(ignore_if_duplicate = True) - frappe.delete_doc("Daily Work Summary Settings") - frappe.delete_doc("Daily Work Summary Settings Company") + # get the previously saved settings + previous_setting = get_previous_setting() + if previous_setting["companies"]: + for d in previous_setting["companies"]: + users = frappe.get_list("Employee", dict( + company=d.company, user_id=("!=", " ")), "user_id as user") + if(len(users)): + # create new group entry for each company entry + new_group = frappe.get_doc(dict(doctype="Daily Work Summary Group", + name="Daily Work Summary for " + d.company, + users=users, + send_emails_at=d.send_emails_at, + subject=previous_setting["subject"], + message=previous_setting["message"])) + new_group.flags.ignore_permissions = True + new_group.flags.ignore_validate = True + new_group.insert(ignore_if_duplicate = True) -def get_setting_companies(): - return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True) + frappe.delete_doc("DocType", "Daily Work Summary Settings") + frappe.delete_doc("DocType", "Daily Work Summary Settings Company") def get_previous_setting(): @@ -47,3 +46,6 @@ def get_previous_setting(): obj[field] = value obj["companies"] = get_setting_companies() return obj + +def get_setting_companies(): + return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True) \ No newline at end of file diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py new file mode 100644 index 0000000000..c8106a6bd5 --- /dev/null +++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py @@ -0,0 +1,36 @@ +# Copyright (c) 2018, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.utils.rename_field import rename_field + +def execute(): + for doctype in ['BOM Explosion Item', 'BOM Item', 'Work Order Item', 'Item']: + if frappe.db.has_column(doctype, 'allow_transfer_for_manufacture'): + if doctype != 'Item': + frappe.reload_doc('manufacturing', 'doctype', frappe.scrub(doctype)) + else: + frappe.reload_doc('stock', 'doctype', frappe.scrub(doctype)) + + rename_field(doctype, "allow_transfer_for_manufacture", "include_item_in_manufacturing") + + if frappe.db.has_column('BOM', 'allow_same_item_multiple_times'): + frappe.db.sql(""" UPDATE tabBOM + SET + allow_same_item_multiple_times = 0 + WHERE + trim(coalesce(allow_same_item_multiple_times, '')) = '' """) + + for doctype in ['BOM', 'Work Order']: + frappe.reload_doc('manufacturing', 'doctype', frappe.scrub(doctype)) + + if frappe.db.has_column(doctype, 'transfer_material_against_job_card'): + frappe.db.sql(""" UPDATE `tab%s` + SET transfer_material_against = CASE WHEN + transfer_material_against_job_card = 1 then 'Job Card' Else 'Work Order' END + WHERE docstatus < 2""" % (doctype)) + else: + frappe.db.sql(""" UPDATE `tab%s` + SET transfer_material_against = 'Work Order' + WHERE docstatus < 2""" % (doctype)) \ No newline at end of file diff --git a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py index 123eed5aff..7f7cfc1327 100644 --- a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py +++ b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py @@ -1,28 +1,60 @@ import frappe +from frappe.desk.form.linked_with import get_linked_doctypes # Skips user permission check for doctypes where department link field was recently added # https://github.com/frappe/erpnext/pull/14121 def execute(): - user_permissions = frappe.get_all("User Permission", - filters=[['allow', '=', 'Department']], - fields=['name', 'skip_for_doctype']) + doctypes_to_skip = [] + for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip', + 'Attendance', 'Training Feedback', 'Training Result Employee', + 'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee', + 'Timesheet', 'Sales Person', 'Payroll Employee Detail']: + if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue + doctypes_to_skip.append(doctype) - doctypes_to_skip = [] + frappe.reload_doctype('User Permission') - for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip', - 'Attendance', 'Training Feedback', 'Training Result Employee', - 'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee', - 'Timesheet', 'Sales Person', 'Payroll Employee Detail']: - if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue - doctypes_to_skip.append(doctype) + user_permissions = frappe.get_all("User Permission", + filters=[['allow', '=', 'Department'], ['applicable_for', 'in', [None] + doctypes_to_skip]], + fields=['name', 'applicable_for']) - for perm in user_permissions: - skip_for_doctype = perm.get('skip_for_doctype') + user_permissions_to_delete = [] + new_user_permissions_list = [] - skip_for_doctype = skip_for_doctype.split('\n') + doctypes_to_skip - skip_for_doctype = set(skip_for_doctype) # to remove duplicates - skip_for_doctype = '\n'.join(skip_for_doctype) # convert back to string + for user_permission in user_permissions: + if user_permission.applicable_for: + # simply delete user permission record since it needs to be skipped. + user_permissions_to_delete.append(user_permission.name) + else: + # if applicable_for is `None` it means that user permission is applicable for every doctype + # to avoid this we need to create other user permission records and only skip the listed doctypes in this patch + linked_doctypes = get_linked_doctypes(user_permission.allow, True).keys() + applicable_for_doctypes = list(set(linked_doctypes) - set(doctypes_to_skip)) - frappe.set_value('User Permission', perm.name, 'skip_for_doctype', skip_for_doctype) + user_permissions_to_delete.append(user_permission.name) + for doctype in applicable_for_doctypes: + if doctype: + # Maintain sequence (name, user, allow, for_value, applicable_for, apply_to_all_doctypes) + new_user_permissions_list.append(( + frappe.generate_hash("", 10), + user_permission.user, + user_permission.allow, + user_permission.for_value, + doctype, + 0 + )) + + if new_user_permissions_list: + frappe.db.sql(''' + INSERT INTO `tabUser Permission` + (`name`, `user`, `allow`, `for_value`, `applicable_for`, `apply_to_all_doctypes`) + VALUES {}'''.format(', '.join(['%s'] * len(new_user_permissions_list))), # nosec + tuple(new_user_permissions_list) + ) + + if user_permissions_to_delete: + frappe.db.sql('DELETE FROM `tabUser Permission` WHERE `name` IN ({})'.format( # nosec + ','.join(['%s'] * len(user_permissions_to_delete)) + ), tuple(user_permissions_to_delete)) \ No newline at end of file diff --git a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py index 9c94deee4b..1b58c97ea4 100644 --- a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py +++ b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py @@ -6,7 +6,7 @@ import frappe def execute(): frappe.reload_doc('stock', 'doctype', 'item') - frappe.db.sql(""" update `tabItem` set allow_transfer_for_manufacture = 1 + frappe.db.sql(""" update `tabItem` set include_item_in_manufacturing = 1 where ifnull(is_stock_item, 0) = 1""") for doctype in ['BOM Item', 'Work Order Item', 'BOM Explosion Item']: @@ -14,7 +14,7 @@ def execute(): frappe.db.sql(""" update `tab{0}` child, tabItem item set - child.allow_transfer_for_manufacture = 1 + child.include_item_in_manufacturing = 1 where child.item_code = item.name and ifnull(item.is_stock_item, 0) = 1 """.format(doctype)) \ No newline at end of file diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 942593a948..de45ec30a6 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -16,7 +16,7 @@ from six import iteritems class Project(Document): def get_feed(self): - return '{0}: {1}'.format(_(self.status), self.project_name) + return '{0}: {1}'.format(_(self.status), frappe.safe_decode(self.project_name)) def onload(self): """Load project tasks for quick view""" @@ -76,7 +76,7 @@ class Project(Document): def validate_project_name(self): if self.get("__islocal") and frappe.db.exists("Project", self.project_name): - frappe.throw(_("Project {0} already exists").format(self.project_name)) + frappe.throw(_("Project {0} already exists").format(frappe.safe_decode(self.project_name))) def validate_dates(self): if self.expected_start_date and self.expected_end_date: @@ -258,13 +258,13 @@ class Project(Document): self.total_purchase_cost = total_purchase_cost and total_purchase_cost[0][0] or 0 def update_sales_amount(self): - total_sales_amount = frappe.db.sql("""select sum(base_grand_total) + total_sales_amount = frappe.db.sql("""select sum(base_net_total) from `tabSales Order` where project = %s and docstatus=1""", self.name) self.total_sales_amount = total_sales_amount and total_sales_amount[0][0] or 0 def update_billed_amount(self): - total_billed_amount = frappe.db.sql("""select sum(base_grand_total) + total_billed_amount = frappe.db.sql("""select sum(base_net_total) from `tabSales Invoice` where project = %s and docstatus=1""", self.name) self.total_billed_amount = total_billed_amount and total_billed_amount[0][0] or 0 diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index 82d6f6e226..9beba6adf8 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -97,6 +97,9 @@ erpnext.setup.slides_settings = [ if (!this.values.company_abbr) { return false; } + if (this.values.company_abbr.length > 5) { + return false; + } return true; } }, diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 4b332e98ac..35105ef25f 100755 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -237,7 +237,7 @@ $.extend(erpnext.utils, { let unscrub_option = frappe.model.unscrub(option); let user_permission = frappe.defaults.get_user_permissions(); if(user_permission && user_permission[unscrub_option]) { - return user_permission[unscrub_option]["docs"]; + return user_permission[unscrub_option].map(perm => perm.doc); } else { return $.map(locals[`:${unscrub_option}`], function(c) { return c.name; }).sort(); } diff --git a/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].js b/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].js index 8606a3b3f7..a4c7640c81 100644 --- a/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].js +++ b/erpnext/regional/report/fichier_des_ecritures_comptables_[fec]/fichier_des_ecritures_comptables_[fec].js @@ -1,85 +1,75 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -/* eslint-disable */ frappe.query_reports["Fichier des Ecritures Comptables [FEC]"] = { - "filters": [{ - "fieldname": "company", - "label": __("Company"), - "fieldtype": "Link", - "options": "Company", - "default": frappe.defaults.get_user_default("Company"), - "reqd": 1 - }, - { - "fieldname": "fiscal_year", - "label": __("Fiscal Year"), - "fieldtype": "Link", - "options": "Fiscal Year", - "default": frappe.defaults.get_user_default("fiscal_year"), - "reqd": 1 - }], - + "filters": [ + { + "fieldname": "company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1 + }, + { + "fieldname": "fiscal_year", + "label": __("Fiscal Year"), + "fieldtype": "Link", + "options": "Fiscal Year", + "default": frappe.defaults.get_user_default("fiscal_year"), + "reqd": 1 + } + ], onload: function(query_report) { query_report.page.add_inner_button(__("Export"), function() { - var fiscal_year = query_report.get_values().fiscal_year; - var company = query_report.get_values().company; + fec_export(query_report); + }); - frappe.call({ - method: "frappe.client.get_value", - args: { - 'doctype': "Company", - 'fieldname': ['siren_number'], - 'filters': { - 'name': company - } - }, - callback: function(data) { - var company_data = data.message.siren_number; - if (company_data === null || company_data === undefined) { - frappe.msgprint(__("Please register the SIREN number in the company information file")) - } else { - frappe.call({ - method: "frappe.client.get_value", - args: { - 'doctype': "Fiscal Year", - 'fieldname': ['year_end_date'], - 'filters': { - 'name': fiscal_year - } - }, - callback: function(data) { - var fy = data.message.year_end_date; - var title = company_data + "FEC" + moment(fy).format('YYYYMMDD'); - var result = $.map(frappe.slickgrid_tools.get_view_data(query_report.columns, query_report.dataView), - function(row) { - return [row.splice(1)]; - }); - downloadify(result, null, title); - } - }); + query_report.add_make_chart_button = function() { + // + }; - } - } + query_report.export_report = function() { + fec_export(query_report); + }; + } +}; + +let fec_export = function(query_report) { + const fiscal_year = query_report.get_values().fiscal_year; + const company = query_report.get_values().company; + + frappe.db.get_value("Company", company, "siren_number", (value) => { + const company_data = value.siren_number; + if (company_data === null || company_data === undefined) { + frappe.msgprint(__("Please register the SIREN number in the company information file")); + } else { + frappe.db.get_value("Fiscal Year", fiscal_year, "year_end_date", (r) => { + const fy = r.year_end_date; + const title = company_data + "FEC" + moment(fy).format('YYYYMMDD'); + const column_row = query_report.columns.map(col => col.label); + const column_data = query_report.get_data_for_csv(false); + const result = [column_row].concat(column_data); + downloadify(result, null, title); }); - }); - } -} + } + }); +}; -var downloadify = function(data, roles, title) { +let downloadify = function(data, roles, title) { if (roles && roles.length && !has_common(roles, roles)) { frappe.msgprint(__("Export not allowed. You need {0} role to export.", [frappe.utils.comma_or(roles)])); return; } - var filename = title + ".csv"; - var csv_data = to_tab_csv(data); - var a = document.createElement('a'); + const filename = title + ".txt"; + let csv_data = to_tab_csv(data); + const a = document.createElement('a'); if ("download" in a) { // Used Blob object, because it can handle large files - var blob_object = new Blob([csv_data], { + let blob_object = new Blob([csv_data], { type: 'text/csv;charset=UTF-8' }); a.href = URL.createObjectURL(blob_object); @@ -98,8 +88,8 @@ var downloadify = function(data, roles, title) { document.body.removeChild(a); }; -var to_tab_csv = function(data) { - var res = []; +let to_tab_csv = function(data) { + let res = []; $.each(data, function(i, row) { res.push(row.join("\t")); }); diff --git a/erpnext/selling/README.md b/erpnext/selling/README.md index db05132a9d..d186133d1f 100644 --- a/erpnext/selling/README.md +++ b/erpnext/selling/README.md @@ -1,6 +1,11 @@ -Selling management module. Includes forms for capturing / managing the sales process. +Selling management module. Includes forms for capturing / managing the sales process: + +- Customer +- Campaign +- Quotation +- Sales Order + +Moved to CRM Module: - Lead - Opportunity -- Quotation -- Sales Order \ No newline at end of file diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 3b1c4805cc..7ea83971cd 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -871,10 +871,12 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -993,6 +995,7 @@ "label": "Net Rate", "length": 0, "no_copy": 0, + "options": "currency", "permlevel": 0, "precision": "", "print_hide": 1, @@ -1910,7 +1913,7 @@ "istable": 1, "max_attachments": 0, "menu_index": 0, - "modified": "2018-08-22 16:15:52.750381", + "modified": "2018-12-12 05:52:46.135944", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", @@ -1925,4 +1928,4 @@ "track_changes": 1, "track_seen": 0, "track_views": 0 -} \ No newline at end of file +} diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index dd6eed8b0c..1428ba41dd 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -620,7 +620,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): def update_item(source, target, source_parent): target.amount = flt(source.amount) - flt(source.billed_amt) target.base_amount = target.amount * flt(source_parent.conversion_rate) - target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty + target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty - source.returned_qty if source_parent.project: target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center") diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js index a6f7a287be..1ee5971271 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.js +++ b/erpnext/selling/page/point_of_sale/point_of_sale.js @@ -394,7 +394,7 @@ erpnext.pos.PointOfSale = class PointOfSale { } } - frappe.prompt(this.get_promopt_fields(), + frappe.prompt(this.get_prompt_fields(), on_submit, __('Select POS Profile') ); @@ -417,11 +417,12 @@ erpnext.pos.PointOfSale = class PointOfSale { ]); } - get_promopt_fields() { + get_prompt_fields() { return [{ fieldtype: 'Link', label: __('POS Profile'), options: 'POS Profile', + fieldname: 'pos_profile', reqd: 1, get_query: () => { return { @@ -433,7 +434,8 @@ erpnext.pos.PointOfSale = class PointOfSale { } }, { fieldtype: 'Check', - label: __('Set as default') + label: __('Set as default'), + fieldname: 'set_as_default' }]; } @@ -522,6 +524,7 @@ erpnext.pos.PointOfSale = class PointOfSale { this.frm.meta.default_print_format = r.message.print_format || ""; this.frm.allow_edit_rate = r.message.allow_edit_rate; this.frm.allow_edit_discount = r.message.allow_edit_discount; + this.frm.doc.campaign = r.message.campaign; } } @@ -1128,12 +1131,15 @@ class POSItems { this.events = events; this.currency = this.frm.doc.currency; - this.make_dom(); - this.make_fields(); + frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name", (r) => { + this.parent_item_group = r.name; + this.make_dom(); + this.make_fields(); - this.init_clusterize(); - this.bind_events(); - this.load_items_data(); + this.init_clusterize(); + this.bind_events(); + this.load_items_data(); + }) } load_items_data() { @@ -1175,6 +1181,7 @@ class POSItems { make_fields() { // Search field + const me = this; this.search_field = frappe.ui.form.make_control({ df: { fieldtype: 'Data', @@ -1202,7 +1209,7 @@ class POSItems { fieldtype: 'Link', label: 'Item Group', options: 'Item Group', - default: 'All Item Groups', + default: me.parent_item_group, onchange: () => { const item_group = this.item_group_field.get_value(); if (item_group) { @@ -1258,7 +1265,7 @@ class POSItems { this.clusterize.update(row_items); } - filter_items({ search_term='', item_group='All Item Groups' }={}) { + filter_items({ search_term='', item_group=this.parent_item_group }={}) { if (search_term) { search_term = search_term.toLowerCase(); @@ -1271,7 +1278,7 @@ class POSItems { this.set_item_in_the_cart(items); return; } - } else if (item_group == "All Item Groups") { + } else if (item_group == this.parent_item_group) { this.items = this.all_items; return this.render_items(this.all_items); } @@ -1376,7 +1383,7 @@ class POSItems { return template; } - get_items({start = 0, page_length = 40, search_value='', item_group="All Item Groups"}={}) { + get_items({start = 0, page_length = 40, search_value='', item_group=this.parent_item_group}={}) { return new Promise(res => { frappe.call({ method: "erpnext.selling.page.point_of_sale.point_of_sale.get_items", diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.js b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.js new file mode 100644 index 0000000000..37634efb6c --- /dev/null +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.js @@ -0,0 +1,6 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Pending SO Items For Purchase Request"] = { +} diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json index 128544b40c..3cf3235745 100644 --- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json @@ -1,36 +1,35 @@ { - "add_total_row": 0, - "apply_user_permissions": 1, - "creation": "2013-06-21 16:46:45", - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "idx": 3, - "is_standard": "Yes", - "modified": "2017-02-24 20:08:11.744036", - "modified_by": "Administrator", - "module": "Selling", - "name": "Pending SO Items For Purchase Request", - "owner": "Administrator", - "query": "select so_item.item_code as \"Item Code:Link/Item:120\",\n so_item.item_name as \"Item Name::120\",\n so_item.description as \"Description::120\",\n so.`name` as \"S.O. No.:Link/Sales Order:120\",\n so.`transaction_date` as \"Date:Date:120\",\n mr.name as \"Material Request:Link/Material Request:120\",\n so.customer as \"Customer:Link/Customer:120\",\n so.territory as \"Terretory:Link/Territory:120\",\n sum(so_item.qty) as \"SO Qty:Float:100 \",\n sum(mr_item.qty) as \"Requested Qty:Float:100\",\n sum(so_item.qty) - sum(mr_item.qty) as \"Pending Qty:Float:100 \", \n so.company as \"Company:Link/Company:\"\nfrom\n `tabSales Order` so, `tabSales Order Item` so_item, \n `tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere \n so_item.`parent` = so.`name` \n and mr_item.parent = mr.name\n and mr_item.sales_order = so.name\n and mr_item.item_code = so_item.item_code\n and so.docstatus = 1 and so.status != \"Closed\" \n and mr.docstatus = 1 and mr.status != \"Stopped\"\ngroup by so.name, so_item.item_code\nhaving sum(so_item.qty) > sum(mr_item.qty)\norder by so.name desc, so_item.item_code asc", - "ref_doctype": "Sales Order", - "report_name": "Pending SO Items For Purchase Request", - "report_type": "Query Report", + "add_total_row": 0, + "creation": "2018-11-12 14:08:27.241332", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2018-11-12 14:08:27.241332", + "modified_by": "Administrator", + "module": "Selling", + "name": "Pending SO Items For Purchase Request", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Sales Order", + "report_name": "Pending SO Items For Purchase Request", + "report_type": "Script Report", "roles": [ { - "role": "Sales User" - }, + "role": "Stock User" + }, { "role": "Sales Manager" - }, + }, { "role": "Maintenance User" - }, + }, { "role": "Accounts User" - }, + }, { - "role": "Stock User" + "role": "Sales User" } ] } \ No newline at end of file diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py new file mode 100644 index 0000000000..87216518c6 --- /dev/null +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py @@ -0,0 +1,148 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ +from frappe.utils import cint,cstr + +def execute(filters=None): + columns = get_columns() + data = get_data() + return columns, data + +def get_columns(): + columns = [ + { + "label": _("Item Code"), + "options": "Item", + "fieldname": "item_code", + "fieldtype": "Link", + "width": 200 + }, + { + "label": _("Item Name"), + "fieldname": "item_name", + "fieldtype": "Data", + "width": 200 + }, + { + "label": _("Description"), + "fieldname": "description", + "fieldtype": "Data", + "width": 140 + }, + { + "label": _("S.O. No."), + "options": "Sales Order", + "fieldname": "sales_order_no", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Date"), + "fieldname": "date", + "fieldtype": "Date", + "width": 140 + }, + { + "label": _("Material Request"), + "options": "Material Request", + "fieldname": "material_request", + "fieldtype": "Link", + "width": 140 + }, + { + "label": _("Customer"), + "fieldname": "customer", + "fieldtype": "Data", + "width": 140 + }, + { + "label": _("Territory"), + "fieldname": "territory", + "fieldtype": "Data", + "width": 140 + }, + { + "label": _("SO Qty"), + "fieldname": "so_qty", + "fieldtype": "Float", + "width": 140 + }, + { + "label": _("Requested Qty"), + "fieldname": "requested_qty", + "fieldtype": "Float", + "width": 140 + }, + { + "label": _("Pending Qty"), + "fieldname": "pending_qty", + "fieldtype": "Float", + "width": 140 + }, + { + "label": _("Company"), + "fieldname": "company", + "fieldtype": "Data", + "width": 140 + } + ] + return columns + +def get_data(): + sales_order_entry = frappe.db.sql(""" + SELECT + so_item.item_code, + so_item.item_name, + so_item.description, + so.name, + so.transaction_date, + so.customer, + so.territory, + sum(so_item.qty) as net_qty, + so.company + FROM `tabSales Order` so, `tabSales Order Item` so_item + WHERE + so.docstatus = 1 + and so.name = so_item.parent + and so.status not in ("Closed","Completed","Cancelled") + GROUP BY + so.name,so_item.item_code + """, as_dict = 1) + + mr_records = frappe.get_all("Material Request Item", + {"sales_order_item": ("!=",""), "docstatus": 1}, + ["parent", "qty", "sales_order", "item_code"]) + + grouped_records = {} + + for record in mr_records: + grouped_records.setdefault(record.sales_order, []).append(record) + + pending_so=[] + for so in sales_order_entry: + # fetch all the material request records for a sales order item + mr_list = grouped_records.get(so.name) or [{}] + mr_item_record = ([mr for mr in mr_list if mr.get('item_code') == so.item_code] or [{}]) + + for mr in mr_item_record: + # check for pending sales order + if cint(so.net_qty) > cint(mr.get('qty')): + so_record = { + "item_code": so.item_code, + "item_name": so.item_name, + "description": so.description, + "sales_order_no": so.name, + "date": so.transaction_date, + "material_request": cstr(mr.get('parent')), + "customer": so.customer, + "territory": so.territory, + "so_qty": so.net_qty, + "requested_qty": cint(mr.get('qty')), + "pending_qty": so.net_qty - cint(mr.get('qty')), + "company": so.company + } + pending_so.append(so_record) + return pending_so \ No newline at end of file diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py new file mode 100644 index 0000000000..f2b7701b10 --- /dev/null +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py @@ -0,0 +1,27 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +import unittest +from frappe.utils import nowdate, add_months +from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request\ + import execute +from erpnext.selling.doctype.sales_order.sales_order import make_material_request +from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + + +class TestPendingSOItemsForPurchaseRequest(unittest.TestCase): + def test_result_for_partial_material_request(self): + so = make_sales_order() + mr=make_material_request(so.name) + mr.items[0].qty = 4 + mr.schedule_date = add_months(nowdate(),1) + mr.submit() + report = execute() + l = len(report[1]) + self.assertEqual((so.items[0].qty - mr.items[0].qty), report[1][l-1]['pending_qty']) + + def test_result_for_so_item(self): + so = make_sales_order() + report = execute() + l = len(report[1]) + self.assertEqual(so.items[0].qty, report[1][l-1]['pending_qty']) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 4affad8065..de6ebb3a54 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -394,8 +394,24 @@ def get_invoiced_qty_map(delivery_note): return invoiced_qty_map +def get_returned_qty_map(sales_orders): + """returns a map: {so_detail: returned_qty}""" + returned_qty_map = {} + + for name, returned_qty in frappe.get_all('Sales Order Item', fields = ["name", "returned_qty"], + filters = {'parent': ('in', sales_orders), 'docstatus': 1}, as_list=1): + if not returned_qty_map.get(name): + returned_qty_map[name] = 0 + returned_qty_map[name] += returned_qty + + return returned_qty_map + @frappe.whitelist() def make_sales_invoice(source_name, target_doc=None): + doc = frappe.get_doc('Delivery Note', source_name) + sales_orders = [d.against_sales_order for d in doc.items] + returned_qty_map = get_returned_qty_map(sales_orders) + invoiced_qty_map = get_invoiced_qty_map(source_name) def set_missing_values(source, target): @@ -415,7 +431,9 @@ def make_sales_invoice(source_name, target_doc=None): target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address)) def update_item(source_doc, target_doc, source_parent): - target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0) + target_doc.qty = (source_doc.qty - + invoiced_qty_map.get(source_doc.name, 0) - returned_qty_map.get(source_doc.so_detail, 0)) + if source_doc.serial_no and source_parent.per_billed > 0: target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code, target_doc.qty, source_parent.name) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js index 6a50c5a9f7..6fc51ecdd9 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js @@ -1,7 +1,8 @@ frappe.listview_settings['Delivery Note'] = { - add_fields: ["grand_total", "is_return", "per_billed", "status", "currency"], - get_indicator: function (doc) { - if (cint(doc.is_return) == 1) { + add_fields: ["customer", "customer_name", "base_grand_total", "per_installed", "per_billed", + "transporter_name", "grand_total", "is_return", "status", "currency"], + get_indicator: function(doc) { + if(cint(doc.is_return)==1) { return [__("Return"), "darkgrey", "is_return,=,Yes"]; } else if (doc.status === "Closed") { return [__("Closed"), "green", "status,=,Closed"]; diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index 026d83cf7f..0c5a71c30c 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -636,6 +636,24 @@ class TestDeliveryNote(unittest.TestCase): self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) set_perpetual_inventory(0, company) + + def test_make_sales_invoice_from_dn_for_returned_qty(self): + from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note + from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice + + so = make_sales_order(qty=2) + so.submit() + + dn = make_delivery_note(so.name) + dn.submit() + + dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-1, do_not_submit=True) + dn1.items[0].against_sales_order = so.name + dn1.items[0].so_detail = so.items[0].name + dn1.submit() + + si = make_sales_invoice(dn.name) + self.assertEquals(si.items[0].qty, 1) def create_delivery_note(**args): dn = frappe.new_doc("Delivery Note") diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index b9c466dc5b..e0d8b6c01b 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -445,38 +445,38 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fieldname": "allow_transfer_for_manufacture", - "fieldtype": "Check", - "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": "Allow Transfer for Manufacture", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "1", + "fieldname": "include_item_in_manufacturing", + "fieldtype": "Check", + "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": "Include Item In Manufacturing", + "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, + "translatable": 0, "unique": 0 }, { @@ -4350,4 +4350,4 @@ "track_changes": 1, "track_seen": 0, "track_views": 0 -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 2033bb4890..4b1bf90d4f 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -395,4 +395,3 @@ def create_item(item_code, is_stock_item=None, valuation_rate=0, warehouse=None, "company": "_Test Company" }) item.save() - diff --git a/erpnext/stock/doctype/item_default/item_default.json b/erpnext/stock/doctype/item_default/item_default.json index 21e9355e39..96b5dfdc8f 100644 --- a/erpnext/stock/doctype/item_default/item_default.json +++ b/erpnext/stock/doctype/item_default/item_default.json @@ -1,463 +1,464 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2018-05-03 02:29:24.444341", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2018-05-03 02:29:24.444341", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "default_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Default Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Default Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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_global_search": 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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 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_global_search": 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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "default_price_list", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Default Price List", - "length": 0, - "no_copy": 0, - "options": "Price List", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_price_list", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Default Price List", + "length": 0, + "no_copy": 0, + "options": "Price List", + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "purchase_defaults", - "fieldtype": "Section Break", - "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": "Purchase Defaults", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "purchase_defaults", + "fieldtype": "Section Break", + "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": "Purchase Defaults", + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "buying_cost_center", - "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": "Default Buying Cost Center", - "length": 0, - "no_copy": 0, - "options": "Cost Center", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "buying_cost_center", + "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": "Default Buying Cost Center", + "length": 0, + "no_copy": 0, + "options": "Cost Center", + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "default_supplier", - "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": "Default Supplier", - "length": 0, - "no_copy": 0, - "options": "Supplier", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_supplier", + "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": "Default Supplier", + "length": 0, + "no_copy": 0, + "options": "Supplier", + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_8", - "fieldtype": "Column Break", - "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, - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_8", + "fieldtype": "Column Break", + "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, + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "expense_account", - "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": "Default Expense Account", - "length": 0, - "no_copy": 0, - "options": "Account", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "expense_account", + "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": "Default Expense Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "selling_defaults", - "fieldtype": "Section Break", - "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": "Sales Defaults", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "selling_defaults", + "fieldtype": "Section Break", + "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": "Sales Defaults", + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "selling_cost_center", - "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": "Default Selling Cost Center", - "length": 0, - "no_copy": 0, - "options": "Cost Center", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "selling_cost_center", + "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": "Default Selling Cost Center", + "length": 0, + "no_copy": 0, + "options": "Cost Center", + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_12", - "fieldtype": "Column Break", - "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, - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_12", + "fieldtype": "Column Break", + "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, + "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, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "income_account", - "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": "Default Income Account", - "length": 0, - "no_copy": 0, - "options": "Account", - "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, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "income_account", + "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": "Default Income Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "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, + "translatable": 0, "unique": 0 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-09-19 16:17:52.562232", - "modified_by": "Administrator", - "module": "Stock", - "name": "Item Default", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2018-12-07 11:48:07.638935", + "modified_by": "Administrator", + "module": "Stock", + "name": "Item Default", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0, "track_views": 0 } \ No newline at end of file diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 401dfc80ce..34a86c946d 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -456,31 +456,40 @@ def raise_work_orders(material_request): errors =[] work_orders = [] 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 frappe.db.get_value("BOM", {"item": d.item_code, "is_default": 1}): + if frappe.db.exists("BOM", {"item": d.item_code, "is_default": 1}): wo_order = frappe.new_doc("Work Order") - wo_order.production_item = d.item_code - wo_order.qty = d.qty - d.ordered_qty - wo_order.fg_warehouse = d.warehouse - wo_order.wip_warehouse = default_wip_warehouse - wo_order.description = d.description - wo_order.stock_uom = d.stock_uom - wo_order.expected_delivery_date = d.schedule_date - wo_order.sales_order = d.sales_order - wo_order.bom_no = get_item_details(d.item_code).bom_no - wo_order.material_request = mr.name - wo_order.material_request_item = d.name - wo_order.planned_start_date = mr.transaction_date - wo_order.company = mr.company + wo_order.update({ + "production_item": d.item_code, + "qty": d.qty - d.ordered_qty, + "fg_warehouse": d.warehouse, + "wip_warehouse": default_wip_warehouse, + "description": d.description, + "stock_uom": d.stock_uom, + "expected_delivery_date": d.schedule_date, + "sales_order": d.sales_order, + "bom_no": get_item_details(d.item_code).bom_no, + "material_request": mr.name, + "material_request_item": d.name, + "planned_start_date": mr.transaction_date, + "company": mr.company + }) + + wo_order.set_work_order_operations() wo_order.save() + work_orders.append(wo_order.name) else: errors.append(_("Row {0}: Bill of Materials not found for the Item {1}").format(d.idx, d.item_code)) + if work_orders: message = ["""%s""" % \ (p, p) for p in work_orders] 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)) + return work_orders diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js index e1d5b08a30..e81f323a46 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js @@ -1,7 +1,8 @@ frappe.listview_settings['Purchase Receipt'] = { - add_fields: ["is_return", "grand_total", "status", "per_billed"], - get_indicator: function (doc) { - if (cint(doc.is_return) == 1) { + add_fields: ["supplier", "supplier_name", "base_grand_total", "is_subcontracted", + "transporter_name", "is_return", "status", "per_billed", "currency"], + get_indicator: function(doc) { + if(cint(doc.is_return)==1) { return [__("Return"), "darkgrey", "is_return,=,Yes"]; } else if (doc.status === "Closed") { return [__("Closed"), "green", "status,=,Closed"]; diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py index 1c8ec23ebd..60cc9a0972 100644 --- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py @@ -3,8 +3,45 @@ import frappe import unittest +from frappe.utils import nowdate +from erpnext.stock.doctype.item.test_item import create_item +from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note +from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError # test_records = frappe.get_test_records('Quality Inspection') class TestQualityInspection(unittest.TestCase): - pass + def setUp(self): + create_item("_Test Item with QA") + frappe.db.set_value("Item", "_Test Item with QA", "inspection_required_before_delivery", 1) + + def test_qa_for_delivery(self): + dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True) + self.assertRaises(QualityInspectionRequiredError, dn.submit) + + qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected") + dn.reload() + self.assertRaises(QualityInspectionRejectedError, dn.submit) + + frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted") + dn.reload() + dn.submit() + +def create_quality_inspection(**args): + args = frappe._dict(args) + qa = frappe.new_doc("Quality Inspection") + qa.report_date = nowdate() + qa.inspection_type = args.inspection_type or "Outgoing" + qa.reference_type = args.reference_type + qa.reference_name = args.reference_name + qa.item_code = args.item_code or "_Test Item with QA" + qa.sample_size = 1 + qa.inspected_by = frappe.session.user + qa.append("readings", { + "specification": "Size", + "status": args.status + }) + qa.save() + qa.submit() + + return qa diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 40881e82bf..5f0b80ef62 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -609,7 +609,7 @@ class StockEntry(StockController): if self.job_card: job_doc = frappe.get_doc('Job Card', self.job_card) - job_doc.set_transferred_qty() + job_doc.set_transferred_qty(update_status=True) if self.work_order: pro_doc = frappe.get_doc("Work Order", self.work_order) @@ -1003,7 +1003,7 @@ class StockEntry(StockController): for d in pro_order.get("required_items"): if (flt(d.required_qty) > flt(d.transferred_qty) and - (d.allow_transfer_for_manufacture or self.purpose != "Material Transfer for Manufacture")): + (d.include_item_in_manufacturing or self.purpose != "Material Transfer for Manufacture")): item_row = d.as_dict() if d.source_warehouse and not frappe.db.get_value("Warehouse", d.source_warehouse, "is_group"): item_row["from_warehouse"] = d.source_warehouse diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js index 4d34d962d3..ed9d77092a 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js @@ -42,7 +42,7 @@ frappe.ui.form.on("Stock Reconciliation", { }, get_items: function(frm) { - frappe.prompt({label:"Warehouse", fieldtype:"Link", options:"Warehouse", reqd: 1, + frappe.prompt({label:"Warehouse", fieldname: "warehouse", fieldtype:"Link", options:"Warehouse", reqd: 1, "get_query": function() { return { "filters": { diff --git a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.js b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.js index 21884d89d1..39cfd7274f 100644 --- a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.js +++ b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.js @@ -10,7 +10,7 @@ frappe.query_reports["Warehouse wise Item Balance Age and Value"] = { "fieldtype": "Date", "width": "80", "reqd": 1, - "default": frappe.sys_defaults.year_start_date, + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1), }, { "fieldname":"to_date", diff --git a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py index 676cf54d8e..ebcb106b02 100644 --- a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py +++ b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py @@ -8,7 +8,8 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import flt, cint, getdate -from erpnext.stock.report.stock_balance.stock_balance import get_item_details, get_item_reorder_details, get_item_warehouse_map +from erpnext.stock.report.stock_balance.stock_balance import (get_item_details, + get_item_reorder_details, get_item_warehouse_map, get_items, get_stock_ledger_entries) from erpnext.stock.report.stock_ageing.stock_ageing import get_fifo_queue, get_average_age from six import iteritems @@ -18,8 +19,12 @@ def execute(filters=None): validate_filters(filters) columns = get_columns(filters) - item_map = get_item_details(filters) - iwb_map = get_item_warehouse_map(filters) + + items = get_items(filters) + sle = get_stock_ledger_entries(filters, items) + + item_map = get_item_details(items, sle, filters) + iwb_map = get_item_warehouse_map(filters, sle) warehouse_list = get_warehouse_list(filters) item_ageing = get_fifo_queue(filters) data = [] @@ -27,6 +32,8 @@ def execute(filters=None): item_value = {} for (company, item, warehouse) in sorted(iwb_map): + if not item_map.get(item): continue + row = [] qty_dict = iwb_map[(company, item, warehouse)] item_balance.setdefault((item, item_map[item]["item_group"]), []) @@ -42,6 +49,8 @@ def execute(filters=None): # sum bal_qty by item for (item, item_group), wh_balance in iteritems(item_balance): + if not item_ageing.get(item): continue + total_stock_value = sum(item_value[(item, item_group)]) row = [item, item_group, total_stock_value] @@ -85,11 +94,10 @@ def validate_filters(filters): filters["company"] = frappe.defaults.get_user_default("Company") def get_warehouse_list(filters): - from frappe.defaults import get_user_permissions + from frappe.core.doctype.user_permission.user_permission import get_permitted_documents + condition = '' - user_permitted_warehouse = filter(None, get_user_permissions() - .get("Warehouse", {}) - .get("docs", [])) + user_permitted_warehouse = get_permitted_documents('Warehouse') value = () if user_permitted_warehouse: condition = "and name in %s" diff --git a/erpnext/templates/includes/itemised_tax_breakup.html b/erpnext/templates/includes/itemised_tax_breakup.html index 982397e133..c27e4cede0 100644 --- a/erpnext/templates/includes/itemised_tax_breakup.html +++ b/erpnext/templates/includes/itemised_tax_breakup.html @@ -16,7 +16,7 @@ {{ item }} - {{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, currency) }} + {{ frappe.utils.fmt_money(itemised_taxable_amount.get(item, 0), None, currency) }} {% for tax_account in tax_accounts %} {% set tax_details = taxes.get(tax_account) %}