Merge pull request #9754 from creamdory/develop
Added Quotation as Standard Sidebar Menu
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 55a78d8..a8a8055 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -2,8 +2,7 @@
from __future__ import unicode_literals
import frappe
-__version__ = '8.2.4'
-
+__version__ = '8.3.5'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 777b34b..49af59b 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -1,6 +1,5 @@
{
"allow_copy": 0,
- "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:title",
@@ -13,7 +12,6 @@
"editable_grid": 0,
"fields": [
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -42,7 +40,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -72,7 +69,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -103,7 +99,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -134,7 +129,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -165,7 +159,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -196,7 +189,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -225,7 +217,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -256,7 +247,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -285,7 +275,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -314,7 +303,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -343,7 +331,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -372,7 +359,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -401,7 +387,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -432,7 +417,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -463,7 +447,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -494,7 +477,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -525,7 +507,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -556,7 +537,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -587,7 +567,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -618,7 +597,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -649,7 +627,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -678,7 +655,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -707,7 +683,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -736,7 +711,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -765,7 +739,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -794,7 +767,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -824,7 +796,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -853,7 +824,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -881,7 +851,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -911,7 +880,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -942,7 +910,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -974,7 +941,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1003,7 +969,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1035,7 +1000,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1064,7 +1028,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1095,7 +1058,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1123,7 +1085,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1153,7 +1114,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1183,7 +1143,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1214,39 +1173,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.price_or_discount==\"Price\"",
- "fieldname": "currency",
- "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": "Currency",
- "length": 0,
- "no_copy": 0,
- "options": "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1276,7 +1202,6 @@
"unique": 0
},
{
- "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1305,18 +1230,18 @@
"unique": 0
}
],
- "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-gift",
"idx": 1,
"image_view": 0,
"in_create": 0,
+ "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-06-26 19:35:50.651619",
+ "modified": "2017-02-17 16:21:28.446208",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index af31d9b..71897d4 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -23,7 +23,6 @@
self.validate_price_or_discount()
self.validate_max_discount()
- if self.price_or_discount != 'Price': self.currency = None
if not self.margin_type: self.margin_rate_or_amount = 0.0
def validate_mandatory(self):
@@ -180,15 +179,9 @@
item_details.margin_type = pricing_rule.margin_type
item_details.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
if pricing_rule.price_or_discount == "Price":
- if pricing_rule.get('currency') and \
- pricing_rule.currency == args.currency:
- price_list_rate = pricing_rule.price * (args.conversion_factor or 1.0)
- else:
- price_list_rate = (pricing_rule.price/flt(args.conversion_rate)) * args.conversion_factor or 1.0 \
- if args.conversion_rate else 0.0
-
item_details.update({
- "price_list_rate": price_list_rate,
+ "price_list_rate": (pricing_rule.price/flt(args.conversion_rate)) * args.conversion_factor or 1.0 \
+ if args.conversion_rate else 0.0,
"discount_percentage": 0.0
})
else:
@@ -247,7 +240,7 @@
conditions = item_variant_condition = ""
values = {"item_code": args.get("item_code"), "brand": args.get("brand")}
- for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner", "currency"]:
+ for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]:
if args.get(field):
conditions += " and ifnull("+field+", '') in (%("+field+")s, '')"
values[field] = args.get(field)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index dc547e3..68b5d46 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -343,12 +343,12 @@
}
}
- /*
+
var item_fields_stock = ['batch_no', 'actual_batch_qty', 'actual_qty', 'expense_account',
'warehouse', 'expense_account', 'quality_inspection']
cur_frm.fields_dict['items'].grid.set_column_disp(item_fields_stock,
(cint(doc.update_stock)==1 || cint(doc.is_return)==1 ? true : false));
- */
+
// India related fields
if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 4c05b94..260c05e 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -12,6 +12,7 @@
"doctype": "DocType",
"document_type": "",
"editable_grid": 0,
+ "engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
@@ -1927,7 +1928,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Item-wise Tax Breakup",
+ "label": "Tax Breakup",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -4687,7 +4688,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-07-04 17:11:09.477003",
+ "modified": "2017-07-07 13:05:37.469682",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index c545ee1..2dd4e7a 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -132,8 +132,7 @@
self.update_billing_status_for_zero_amount_refdoc("Sales Order")
self.check_credit_limit()
- if self.update_stock:
- self.update_serial_no()
+ self.update_serial_no()
if not cint(self.is_pos) == 1 and not self.is_return:
self.update_against_document_in_jv()
@@ -804,9 +803,10 @@
continue
for serial_no in item.serial_no.split("\n"):
- sno = frappe.get_doc('Serial No', serial_no)
- sno.sales_invoice = invoice
- sno.db_update()
+ if serial_no and frappe.db.exists('Serial No', serial_no):
+ sno = frappe.get_doc('Serial No', serial_no)
+ sno.sales_invoice = invoice
+ sno.db_update()
def validate_serial_numbers(self):
"""
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
index bc9d766..bfe00ef 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_dashboard.py
@@ -11,7 +11,8 @@
'Sales Invoice': 'return_against'
},
'internal_links': {
- 'Sales Order': ['items', 'sales_order']
+ 'Sales Order': ['items', 'sales_order'],
+ 'Delivery Note': ['items', 'delivery_note']
},
'transactions': [
{
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 071e72b..6f1c2c9 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1116,7 +1116,7 @@
})
si.insert()
- tax_breakup_html = '''\n<div class="tax-break-up" style="overflow-x: auto;">\n\t<table class="table table-bordered table-hover">\n\t\t<thead><tr><th class="text-left" style="min-width: 120px;">Item Name</th>\n<th class="text-right" style="min-width: 80px;">Taxable Amount</th>\n<th class="text-right" style="min-width: 80px;">_Test Account Service Tax - _TC</th></tr></thead>\n\t\t<tbody><tr><td>_Test Item</td><td class="text-right">5000.0</td><td class="text-right">(10.0%) \u20b9 500.00</td></tr></tbody>\n\t</table>\n</div>'''
+ tax_breakup_html = '''\n<div class="tax-break-up" style="overflow-x: auto;">\n\t<table class="table table-bordered table-hover">\n\t\t<thead><tr><th class="text-left" style="min-width: 120px;">Item Name</th><th class="text-right" style="min-width: 80px;">Taxable Amount</th><th class="text-right" style="min-width: 80px;">_Test Account Service Tax - _TC</th></tr></thead>\n\t\t<tbody><tr><td>_Test Item</td><td class="text-right">\u20b9 5,000.00</td><td class="text-right">(10.0%) \u20b9 500.00</td></tr></tbody>\n\t</table>\n</div>'''
self.assertEqual(si.other_charges_calculation, tax_breakup_html)
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
index 59af618..5810c69 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json
@@ -11,6 +11,7 @@
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
+ "engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
@@ -1423,7 +1424,7 @@
"collapsible": 1,
"collapsible_depends_on": "eval:doc.serial_no || doc.batch_no",
"columns": 0,
- "depends_on": "",
+ "depends_on": "eval: parent.update_stock",
"fieldname": "warehouse_and_reference",
"fieldtype": "Section Break",
"hidden": 0,
@@ -2165,7 +2166,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-07-03 19:34:14.820285",
+ "modified": "2017-07-06 17:54:03.347700",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice Item",
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index b798d2b..853b805 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -1,9 +1,3 @@
-{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) || frappe.defaults.get_default("letter_head"); %}
-{% if(letterhead) { %}
-<div style="margin-bottom: 7px;" class="text-center">
- {%= frappe.boot.letter_heads[letterhead].header %}
-</div>
-{% } %}
<h2 class="text-center">{%= __(report.report_name) %}</h2>
<h4 class="text-center">{%= filters.customer || filters.supplier %} </h4>
<h5 class="text-center">
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html
index 0a25225..91cc3c9 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.html
+++ b/erpnext/accounts/report/general_ledger/general_ledger.html
@@ -1,9 +1,3 @@
-{% var letterhead= filters.letter_head || (frappe.get_doc(":Company", filters.company) && frappe.get_doc(":Company", filters.company).default_letter_head) || frappe.defaults.get_default("letter_head"); %}
-{% if(letterhead) { %}
-<div style="margin-bottom: 7px;" class="text-center">
- {%= frappe.boot.letter_heads[letterhead].header %}
-</div>
-{% } %}
<h2 class="text-center">{%= __("Statement of Account") %}</h2>
<h4 class="text-center">
{% if (filters.party_name) { %}
diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
index 4f205c5..2e8b946 100644
--- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
@@ -3,8 +3,10 @@
# See license.txt
from __future__ import unicode_literals
-import frappe
import unittest
+
+import frappe
+from erpnext.templates.pages.rfq import check_supplier_has_docname_access
from frappe.utils import nowdate
class TestRequestforQuotation(unittest.TestCase):
@@ -28,6 +30,31 @@
self.assertEquals(sq1.get('items')[0].item_code, "_Test Item")
self.assertEquals(sq1.get('items')[0].qty, 5)
+ def test_make_supplier_quotation_with_special_characters(self):
+ from erpnext.buying.doctype.request_for_quotation.request_for_quotation import make_supplier_quotation
+
+ frappe.delete_doc_if_exists("Supplier", "_Test Supplier '1", force=1)
+ supplier = frappe.new_doc("Supplier")
+ supplier.supplier_name = "_Test Supplier '1"
+ supplier.supplier_type = "_Test Supplier Type"
+ supplier.insert()
+
+ rfq = make_request_for_quotation(supplier_wt_appos)
+
+ sq = make_supplier_quotation(rfq.name, supplier_wt_appos[0].get("supplier"))
+ sq.submit()
+
+ frappe.form_dict = frappe.local("form_dict")
+ frappe.form_dict.name = rfq.name
+
+ self.assertEqual(
+ check_supplier_has_docname_access(supplier_wt_appos[0].get('supplier')),
+ True
+ )
+
+ # reset form_dict
+ frappe.form_dict.name = None
+
def test_make_supplier_quotation_from_portal(self):
from erpnext.buying.doctype.request_for_quotation.request_for_quotation import create_supplier_quotation
rfq = make_request_for_quotation()
@@ -44,8 +71,11 @@
self.assertEquals(supplier_quotation_doc.get('items')[0].amount, 500)
-def make_request_for_quotation():
- supplier_data = get_supplier_data()
+def make_request_for_quotation(supplier_data=None):
+ """
+ :param supplier_data: List containing supplier data
+ """
+ supplier_data = supplier_data if supplier_data else get_supplier_data()
rfq = frappe.new_doc('Request for Quotation')
rfq.transaction_date = nowdate()
rfq.status = 'Draft'
@@ -77,3 +107,8 @@
"supplier": "_Test Supplier 1",
"supplier_name": "_Test Supplier 1"
}]
+
+supplier_wt_appos = [{
+ "supplier": "_Test Supplier '1",
+ "supplier_name": "_Test Supplier '1",
+}]
diff --git a/erpnext/change_log/v8/v8_3_0.md b/erpnext/change_log/v8/v8_3_0.md
new file mode 100644
index 0000000..bd8162d
--- /dev/null
+++ b/erpnext/change_log/v8/v8_3_0.md
@@ -0,0 +1,8 @@
+### Production Order Enahancement
+ - Show required items child table.
+ - Source warehouse for each Raw Materials, in Production Order Item and BOM Item table.
+ - Group warehouse allowed for Source and WIP warehouse.
+### GST Tax Invoice Print Format
+ - Added print format to show tax(GST) breakup.
+- Total Stock Summary report.
+- Include Search Fields in Customer Query.
\ No newline at end of file
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index b0fe395..8eb83af 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -511,14 +511,15 @@
def set_item_wise_tax_breakup(self):
item_tax = {}
tax_accounts = []
+ company_currency = erpnext.get_company_currency(self.doc.company)
- item_tax, tax_accounts = self.get_item_tax(item_tax, tax_accounts)
+ item_tax, tax_accounts = self.get_item_tax(item_tax, tax_accounts, company_currency)
headings = get_table_column_headings(tax_accounts)
distinct_items = self.get_distinct_items()
- rows = get_table_rows(distinct_items, item_tax, tax_accounts)
+ rows = get_table_rows(distinct_items, item_tax, tax_accounts, company_currency)
if not rows:
self.doc.other_charges_calculation = ""
@@ -530,13 +531,11 @@
<tbody>{rows}</tbody>
</table>
</div>'''.format(**{
- "headings": "\n".join(headings),
- "rows": "\n".join(rows)
+ "headings": "".join(headings),
+ "rows": "".join(rows)
})
- def get_item_tax(self, item_tax, tax_accounts):
- company_currency = erpnext.get_company_currency(self.doc.company)
-
+ def get_item_tax(self, item_tax, tax_accounts, company_currency):
for tax in self.doc.taxes:
tax_amount_precision = tax.precision("tax_amount")
tax_rate_precision = tax.precision("rate");
@@ -588,7 +587,7 @@
return headings
-def get_table_rows(distinct_items, item_tax, tax_accounts):
+def get_table_rows(distinct_items, item_tax, tax_accounts, company_currency):
rows = []
for item in distinct_items:
item_tax_record = item_tax.get(item.item_code or item.item_name)
@@ -605,8 +604,8 @@
rows.append("<tr><td>{item_name}</td><td class='text-right'>{taxable_amount}</td>{taxes}</tr>".format(**{
"item_name": item.item_name,
- "taxable_amount": item.net_amount,
- "taxes": "\n".join(taxes)
+ "taxable_amount": fmt_money(item.net_amount, item.precision("net_amount"), company_currency),
+ "taxes": "".join(taxes)
}))
return rows
\ No newline at end of file
diff --git a/erpnext/docs/assets/img/manufacturing/production-order.png b/erpnext/docs/assets/img/manufacturing/production-order.png
index fb552f3..fc71943 100644
--- a/erpnext/docs/assets/img/manufacturing/production-order.png
+++ b/erpnext/docs/assets/img/manufacturing/production-order.png
Binary files differ
diff --git a/erpnext/docs/assets/img/regional/india/address-template-gstin.png b/erpnext/docs/assets/img/regional/india/address-template-gstin.png
index 8740609..5862c54 100644
--- a/erpnext/docs/assets/img/regional/india/address-template-gstin.png
+++ b/erpnext/docs/assets/img/regional/india/address-template-gstin.png
Binary files differ
diff --git a/erpnext/docs/assets/img/regional/india/sample-gst-tax-invoice.png b/erpnext/docs/assets/img/regional/india/sample-gst-tax-invoice.png
index 4f4a9b1..cb65724 100644
--- a/erpnext/docs/assets/img/regional/india/sample-gst-tax-invoice.png
+++ b/erpnext/docs/assets/img/regional/india/sample-gst-tax-invoice.png
Binary files differ
diff --git a/erpnext/docs/assets/img/setup/email/email-alert-set-property.png b/erpnext/docs/assets/img/setup/email/email-alert-set-property.png
new file mode 100644
index 0000000..658b149
--- /dev/null
+++ b/erpnext/docs/assets/img/setup/email/email-alert-set-property.png
Binary files differ
diff --git a/erpnext/docs/user/manual/en/manufacturing/production-order.md b/erpnext/docs/user/manual/en/manufacturing/production-order.md
index 685a2ca..a19c510 100644
--- a/erpnext/docs/user/manual/en/manufacturing/production-order.md
+++ b/erpnext/docs/user/manual/en/manufacturing/production-order.md
@@ -17,9 +17,15 @@
* Select the Item to be produced.
* The default BOM for that item will be fetched by the system. You can also change BOM.
+ * Enter the Qty to manufacture.
* If the selected BOM has operartion mentioned in it, the system shall fetch all operations from BOM.
* Mention the Planned Start Date (an Estimated Date at which you want the Production to begin.)
- * Select Warehouses. Work-in-Progress Warehouse is where your Items will be transferred when you begin production and Target Warehouse is where you store finished Items before they are shipped.
+ * Select Warehouses:
+ * Source Warehouses: The warehouse where you store your raw materials. Each required item can have separate source warehouse. Group warehouse also can be selected as source warehouse. On submission of Production Order, the raw mateirals will be reserved in these warehouses for production usage.
+ * Work-in-Progress Warehouse: The warehouse where your Items will be transferred when you begin production. Group Warehouse can also be selected as Work-in-Progress warehouse.
+ * Target Warehouse: The warehouse where you store finished Items before they are shipped.
+ * Scrap Warehouse: Scrap Items will be stored in this warehouse.
+ * Required Items: All the required items (raw materials) will be fetched from BOM and populated in this table. Here you can also change the default source warehouse for any item. And during the production, you can track transferred raw materials from this table.
> Note : You can save a Production Order without selecting the warehouses, but warehouses are mandatory for submitting a Production Order
diff --git a/erpnext/docs/user/manual/en/regional/india/gst-setup.md b/erpnext/docs/user/manual/en/regional/india/gst-setup.md
index 0ba8284..49d75b1 100644
--- a/erpnext/docs/user/manual/en/regional/india/gst-setup.md
+++ b/erpnext/docs/user/manual/en/regional/india/gst-setup.md
@@ -16,7 +16,7 @@
**Include GSTIN number in the Address Template**
-Open Address Template record for India, and add GSTIN number there if not exists.
+Open Address Template record for India, add GSTIN number and State Code there if not exists.
<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/address-template-gstin.png">
@@ -63,7 +63,7 @@
### 6. Print GST Tax Invoice
-To print Tax Invoice as per GSTN guidelines, please select **GST Tax Invoice** print format. This print format includes company address, GSTIN numbers, HSN/SAC Code and item-wise tax breakup.
+To print Tax Invoice as per GSTN guidelines, please select **GST Tax Invoice** print format. This print format includes company address, GSTIN numbers, HSN/SAC Code and item-wise tax breakup. And while printing select correct value of Invoice Copy field, to mention whether it is for the Customer, Supplier or Transporter.
<img class="screenshot" alt="Sample GST Tax Invoice" src="{{docs_base_url}}/assets/img/regional/india/sample-gst-tax-invoice.png">
diff --git a/erpnext/docs/user/manual/en/setting-up/email/email-alerts.md b/erpnext/docs/user/manual/en/setting-up/email/email-alerts.md
index 9ec3073..8d239ea 100644
--- a/erpnext/docs/user/manual/en/setting-up/email/email-alerts.md
+++ b/erpnext/docs/user/manual/en/setting-up/email/email-alerts.md
@@ -42,6 +42,7 @@
The above example will send an Email Alert when a Task is saved with the status "Open" and the Expected End Date for the Task is the date on or before the date on which it was saved on.
+
### Setting a Message
You can use both Jinja Tags (`{% raw %}{{ doc.[field_name] }}{% endraw %}`) and HTML tags in the message textbox.
@@ -64,6 +65,17 @@
---
+### Setting a Value after the Alert is Set
+
+Sometimes to make sure that the email alert is not sent multiple times, you can
+define a custom property (via Customize Form) like "Email Alert Sent" and then
+set this property after the alert is sent by setting the **Set Property After Alert**
+field.
+
+Then you can use that as a condition in the **Condition** rules to ensure emails are not sent multiple times
+
+<img class="screenshot" alt="Setting Property in Email Alert" src="{{docs_base_url}}/assets/img/setup/email/email-alert-subject.png">
+
### Example
1. Defining the Criteria
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 87dd565..347314b 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -5,12 +5,24 @@
frappe.ui.form.on("BOM", {
setup: function(frm) {
- frm.add_fetch('buying_price_list', 'currency', 'currency');
- frm.fields_dict["items"].grid.get_field("bom_no").get_query = function(doc, cdt, cdn){
+ frm.add_fetch('buying_price_list', 'currency', 'currency')
+
+ frm.set_query("bom_no", "items", function() {
return {
- filters: {'currency': frm.doc.currency}
+ filters: {
+ 'currency': frm.doc.currency,
+ 'company': frm.doc.company
+ }
}
- }
+ });
+
+ frm.set_query("source_warehouse", "items", function() {
+ return {
+ filters: {
+ 'company': frm.doc.company,
+ }
+ }
+ });
},
onload_post_render: function(frm) {
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 41eec8d..7aef4fc 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -408,6 +408,7 @@
self.add_to_cur_exploded_items(frappe._dict({
'item_code' : d.item_code,
'item_name' : d.item_name,
+ 'source_warehouse': d.source_warehouse,
'description' : d.description,
'image' : d.image,
'stock_uom' : d.stock_uom,
@@ -427,7 +428,8 @@
def get_child_exploded_items(self, bom_no, stock_qty):
""" Add all items from Flat BOM of child BOM"""
# 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,
+ child_fb_items = frappe.db.sql("""select bom_item.item_code, bom_item.item_name,
+ bom_item.description, bom_item.source_warehouse,
bom_item.stock_uom, bom_item.stock_qty, bom_item.rate,
bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
from `tabBOM Explosion Item` bom_item, tabBOM bom
@@ -437,9 +439,10 @@
self.add_to_cur_exploded_items(frappe._dict({
'item_code' : d['item_code'],
'item_name' : d['item_name'],
+ 'source_warehouse' : d['source_warehouse'],
'description' : d['description'],
'stock_uom' : d['stock_uom'],
- 'stock_qty' : d['qty_consumed_per_unit']*stock_qty,
+ 'stock_qty' : d['qty_consumed_per_unit'] * stock_qty,
'rate' : flt(d['rate']),
}))
@@ -493,6 +496,7 @@
item.default_warehouse,
item.expense_account as expense_account,
item.buying_cost_center as cost_center
+ {select_columns}
from
`tab{table}` bom_item, `tabBOM` bom, `tabItem` item
where
@@ -501,18 +505,20 @@
and bom_item.parent = bom.name
and item.name = bom_item.item_code
and is_stock_item = 1
- {conditions}
- group by item_code, stock_uom"""
+ {where_conditions}
+ group by item_code, stock_uom"""
if fetch_exploded:
query = query.format(table="BOM Explosion Item",
- conditions="""and item.is_sub_contracted_item = 0""")
+ where_conditions="""and item.is_sub_contracted_item = 0""",
+ select_columns = ", bom_item.source_warehouse")
items = frappe.db.sql(query, { "qty": qty, "bom": bom }, as_dict=True)
elif fetch_scrap_items:
- query = query.format(table="BOM Scrap Item", conditions="")
+ query = query.format(table="BOM Scrap Item", where_conditions="", select_columns="")
items = frappe.db.sql(query, { "qty": qty, "bom": bom }, as_dict=True)
else:
- query = query.format(table="BOM Item", conditions="")
+ query = query.format(table="BOM Item", where_conditions="",
+ select_columns = ", bom_item.source_warehouse")
items = frappe.db.sql(query, { "qty": qty, "bom": bom }, 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 0f1143e..6c24871 100644
--- a/erpnext/manufacturing/doctype/bom/test_records.json
+++ b/erpnext/manufacturing/doctype/bom/test_records.json
@@ -8,7 +8,8 @@
"parentfield": "items",
"stock_qty": 1.0,
"rate": 5000.0,
- "stock_uom": "_Test UOM"
+ "stock_uom": "_Test UOM",
+ "source_warehouse": "_Test Warehouse - _TC"
},
{
"amount": 2000.0,
@@ -17,7 +18,8 @@
"parentfield": "items",
"stock_qty": 2.0,
"rate": 1000.0,
- "stock_uom": "_Test UOM"
+ "stock_uom": "_Test UOM",
+ "source_warehouse": "_Test Warehouse - _TC"
}
],
"docstatus": 1,
@@ -48,7 +50,8 @@
"parentfield": "items",
"stock_qty": 1.0,
"rate": 5000.0,
- "stock_uom": "_Test UOM"
+ "stock_uom": "_Test UOM",
+ "source_warehouse": "_Test Warehouse - _TC"
},
{
"amount": 2000.0,
@@ -57,7 +60,8 @@
"parentfield": "items",
"stock_qty": 2.0,
"rate": 1000.0,
- "stock_uom": "_Test UOM"
+ "stock_uom": "_Test UOM",
+ "source_warehouse": "_Test Warehouse - _TC"
}
],
"docstatus": 1,
@@ -86,7 +90,8 @@
"parentfield": "items",
"stock_qty": 1.0,
"rate": 5000.0,
- "stock_uom": "_Test UOM"
+ "stock_uom": "_Test UOM",
+ "source_warehouse": "_Test Warehouse - _TC"
},
{
"amount": 2000.0,
@@ -96,7 +101,8 @@
"parentfield": "items",
"stock_qty": 3.0,
"rate": 1000.0,
- "stock_uom": "_Test UOM"
+ "stock_uom": "_Test UOM",
+ "source_warehouse": "_Test Warehouse - _TC"
}
],
"docstatus": 1,
@@ -126,7 +132,8 @@
"parentfield": "items",
"stock_qty": 2.0,
"rate": 3000.0,
- "stock_uom": "_Test UOM"
+ "stock_uom": "_Test UOM",
+ "source_warehouse": "_Test Warehouse - _TC"
}
],
"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 e1a3d4d..16cba0c 100644
--- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
+++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
@@ -7,9 +7,9 @@
"beta": 0,
"creation": "2013-03-07 11:42:57",
"custom": 0,
- "default_print_format": "Standard",
"docstatus": 0,
"doctype": "DocType",
+ "document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
@@ -110,6 +110,37 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "source_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": "Source Warehouse",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Warehouse",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "section_break_3",
"fieldtype": "Section Break",
"hidden": 0,
@@ -481,7 +512,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-06-02 19:29:34.498719",
+ "modified": "2017-07-04 17:51:18.151002",
"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 966b89b..e0c4bab 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.json
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json
@@ -22,7 +22,7 @@
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
- "in_filter": 0,
+ "in_filter": 1,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
@@ -113,7 +113,7 @@
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
- "in_filter": 0,
+ "in_filter": 1,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
@@ -142,6 +142,37 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "source_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": "Source 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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "section_break_5",
"fieldtype": "Section Break",
"hidden": 0,
@@ -729,7 +760,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-05-23 15:59:37.946963",
+ "modified": "2017-07-04 17:42:37.218408",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",
diff --git a/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.json b/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.json
index e9aebfe..9f7091d 100644
--- a/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.json
+++ b/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.json
@@ -327,7 +327,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-05-23 16:04:32.442287",
+ "modified": "2017-07-04 16:04:32.442287",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Scrap Item",
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.js b/erpnext/manufacturing/doctype/production_order/production_order.js
index 6465cec..f6d9eaf 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.js
+++ b/erpnext/manufacturing/doctype/production_order/production_order.js
@@ -7,7 +7,72 @@
'Timesheet': 'Make Timesheet',
'Stock Entry': 'Make Stock Entry',
}
+
+ // Set query for warehouses
+ frm.set_query("wip_warehouse", function(doc) {
+ return {
+ filters: {
+ 'company': frm.doc.company,
+ }
+ }
+ });
+
+ frm.set_query("source_warehouse", "required_items", function() {
+ return {
+ filters: {
+ 'company': frm.doc.company,
+ }
+ }
+ });
+
+ frm.set_query("fg_warehouse", function() {
+ return {
+ filters: {
+ 'company': frm.doc.company,
+ 'is_group': 0
+ }
+ }
+ });
+
+ frm.set_query("scrap_warehouse", function() {
+ return {
+ filters: {
+ 'company': frm.doc.company,
+ 'is_group': 0
+ }
+ }
+ });
+
+ // Set query for BOM
+ frm.set_query("bom_no", function() {
+ if (frm.doc.production_item) {
+ return{
+ query: "erpnext.controllers.queries.bom",
+ filters: {item: cstr(frm.doc.production_item)}
+ }
+ } else msgprint(__("Please enter Production Item first"));
+ });
+
+ // Set query for FG Item
+ frm.set_query("production_item", function() {
+ return {
+ query: "erpnext.controllers.queries.item_query",
+ filters:{
+ 'is_stock_item': 1,
+ }
+ }
+ });
+
+ // Set query for FG Item
+ frm.set_query("project", function() {
+ return{
+ filters:[
+ ['Project', 'status', 'not in', 'Completed, Cancelled']
+ ]
+ }
+ });
},
+
onload: function(frm) {
if (!frm.doc.status)
frm.doc.status = 'Draft';
@@ -25,12 +90,9 @@
// formatter for production order operation
frm.set_indicator_formatter('operation',
- function(doc) { return (frm.doc.qty==doc.completed_qty) ? "green" : "orange" })
-
- erpnext.production_order.set_custom_buttons(frm);
- erpnext.production_order.setup_company_filter(frm);
- erpnext.production_order.setup_bom_filter(frm);
+ function(doc) { return (frm.doc.qty==doc.completed_qty) ? "green" : "orange" });
},
+
refresh: function(frm) {
erpnext.toggle_naming_series();
erpnext.production_order.set_custom_buttons(frm);
@@ -53,6 +115,7 @@
})
}
},
+
show_progress: function(frm) {
var bars = [];
var message = '';
@@ -85,10 +148,85 @@
}
}
frm.dashboard.add_progress(__('Status'), bars, message);
+ },
+
+ production_item: function(frm) {
+ if (frm.doc.production_item) {
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.production_order.production_order.get_item_details",
+ args: {
+ item: frm.doc.production_item,
+ project: frm.doc.project
+ },
+ callback: function(r) {
+ if(r.message) {
+ erpnext.in_production_item_onchange = true;
+ $.each(["description", "stock_uom", "project", "bom_no"], function(i, field) {
+ frm.set_value(field, r.message[field]);
+ });
+
+ if(r.message["set_scrap_wh_mandatory"]){
+ frm.toggle_reqd("scrap_warehouse", true);
+ }
+ erpnext.in_production_item_onchange = false;
+ }
+ }
+ });
+ }
+ },
+
+ project: function(frm) {
+ if(!erpnext.in_production_item_onchange) {
+ frm.trigger("production_item");
+ }
+ },
+
+ bom_no: function(frm) {
+ return frm.call({
+ doc: frm.doc,
+ method: "get_items_and_operations_from_bom",
+ callback: function(r) {
+ if(r.message["set_scrap_wh_mandatory"]){
+ frm.toggle_reqd("scrap_warehouse", true);
+ }
+ }
+ });
+ },
+
+ use_multi_level_bom: function(frm) {
+ if(frm.doc.bom_no) {
+ frm.trigger("bom_no");
+ }
+ },
+
+ qty: function(frm) {
+ frm.trigger('bom_no');
+ },
+
+ before_submit: function(frm) {
+ frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true);
+ frm.fields_dict.required_items.grid.toggle_reqd("source_warehouse", true);
}
});
-
+frappe.ui.form.on("Production Order Item", {
+ source_warehouse: function(frm, cdt, cdn) {
+ var row = locals[cdt][cdn];
+ if(row.source_warehouse) {
+ frappe.call({
+ "method": "erpnext.stock.utils.get_latest_stock_qty",
+ args: {
+ item_code: row.item_code,
+ warehouse: row.source_warehouse
+ },
+ callback: function (r) {
+ frappe.model.set_value(row.doctype, row.name,
+ "available_qty_at_source_warehouse", r.message);
+ }
+ })
+ }
+ }
+})
frappe.ui.form.on("Production Order Operation", {
workstation: function(frm, cdt, cdn) {
@@ -119,38 +257,46 @@
var doc = frm.doc;
if (doc.docstatus === 1) {
if (doc.status != 'Stopped' && doc.status != 'Completed') {
- frm.add_custom_button(__('Stop'), cur_frm.cscript['Stop Production Order'], __("Status"));
+ frm.add_custom_button(__('Stop'), function() {
+ erpnext.production_order.stop_production_order(frm, "Stopped");
+ }, __("Status"));
} else if (doc.status == 'Stopped') {
- frm.add_custom_button(__('Re-open'), cur_frm.cscript['Unstop Production Order'], __("Status"));
+ frm.add_custom_button(__('Re-open'), function() {
+ erpnext.production_order.stop_production_order(frm, "Resumed");
+ }, __("Status"));
}
if(!frm.doc.skip_transfer){
- if ((flt(doc.material_transferred_for_manufacturing) < flt(doc.qty)) && frm.doc.status != 'Stopped') {
+ if ((flt(doc.material_transferred_for_manufacturing) < flt(doc.qty))
+ && frm.doc.status != 'Stopped') {
frm.has_start_btn = true;
- var btn = frm.add_custom_button(__('Start'),
- cur_frm.cscript['Transfer Raw Materials']);
- btn.addClass('btn-primary');
+ var start_btn = frm.add_custom_button(__('Start'), function() {
+ erpnext.production_order.make_se(frm, 'Material Transfer for Manufacture');
+ });
+ start_btn.addClass('btn-primary');
}
}
if(!frm.doc.skip_transfer){
- if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing)) && frm.doc.status != 'Stopped') {
+ if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))
+ && frm.doc.status != 'Stopped') {
frm.has_finish_btn = true;
- var btn = frm.add_custom_button(__('Finish'),
- cur_frm.cscript['Update Finished Goods']);
+ var finish_btn = frm.add_custom_button(__('Finish'), function() {
+ erpnext.production_order.make_se(frm, 'Manufacture');
+ });
if(doc.material_transferred_for_manufacturing==doc.qty) {
- // all materials transferred for manufacturing,
- // make this primary
- btn.addClass('btn-primary');
+ // all materials transferred for manufacturing, make this primary
+ finish_btn.addClass('btn-primary');
}
}
} else {
if ((flt(doc.produced_qty) < flt(doc.qty)) && frm.doc.status != 'Stopped') {
frm.has_finish_btn = true;
- var btn = frm.add_custom_button(__('Finish'),
- cur_frm.cscript['Update Finished Goods']);
- btn.addClass('btn-primary');
+ var finish_btn = frm.add_custom_button(__('Finish'), function() {
+ erpnext.production_order.make_se(frm, 'Manufacture');
+ });
+ finish_btn.addClass('btn-primary');
}
}
}
@@ -162,8 +308,8 @@
doc.planned_operating_cost = 0.0;
for(var i=0;i<op.length;i++) {
var planned_operating_cost = flt(flt(op[i].hour_rate) * flt(op[i].time_in_mins) / 60, 2);
- frappe.model.set_value('Production Order Operation',op[i].name, "planned_operating_cost", planned_operating_cost);
-
+ frappe.model.set_value('Production Order Operation', op[i].name,
+ "planned_operating_cost", planned_operating_cost);
doc.planned_operating_cost += planned_operating_cost;
}
refresh_field('planned_operating_cost');
@@ -176,37 +322,10 @@
frm.set_value("total_operating_cost", (flt(frm.doc.additional_operating_cost) + variable_cost))
},
- setup_company_filter: function(frm) {
- var company_filter = function(doc) {
- return {
- filters: {
- 'company': frm.doc.company,
- 'is_group': 0
- }
- }
- }
-
- frm.fields_dict.source_warehouse.get_query = company_filter;
- frm.fields_dict.fg_warehouse.get_query = company_filter;
- frm.fields_dict.wip_warehouse.get_query = company_filter;
- },
-
- setup_bom_filter: function(frm) {
- frm.set_query("bom_no", function(doc) {
- if (doc.production_item) {
- return{
- query: "erpnext.controllers.queries.bom",
- filters: {item: cstr(doc.production_item)}
- }
- } else frappe.msgprint(__("Please enter Production Item first"));
- });
- },
-
set_default_warehouse: function(frm) {
if (!(frm.doc.wip_warehouse || frm.doc.fg_warehouse)) {
frappe.call({
method: "erpnext.manufacturing.doctype.production_order.production_order.get_default_warehouse",
-
callback: function(r) {
if(!r.exe) {
frm.set_value("wip_warehouse", r.message.wip_warehouse);
@@ -215,45 +334,15 @@
}
});
}
- }
-}
-
-$.extend(cur_frm.cscript, {
- before_submit: function() {
- cur_frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true);
},
-
- production_item: function(doc) {
- frappe.call({
- method: "erpnext.manufacturing.doctype.production_order.production_order.get_item_details",
- args: {
- item: doc.production_item,
- project: doc.project
- },
- callback: function(r) {
- $.each(["description", "stock_uom", "project", "bom_no"], function(i, field) {
- cur_frm.set_value(field, r.message[field]);
- });
-
- if(r.message["set_scrap_wh_mandatory"]){
- cur_frm.toggle_reqd("scrap_warehouse", true);
- }
- }
- });
- },
-
- project: function(doc) {
- cur_frm.cscript.production_item(doc)
- },
-
- make_se: function(purpose) {
- var me = this;
- if(!this.frm.doc.skip_transfer){
+
+ make_se: function(frm, purpose) {
+ if(!frm.doc.skip_transfer){
var max = (purpose === "Manufacture") ?
- flt(this.frm.doc.material_transferred_for_manufacturing) - flt(this.frm.doc.produced_qty) :
- flt(this.frm.doc.qty) - flt(this.frm.doc.material_transferred_for_manufacturing);
+ flt(frm.doc.material_transferred_for_manufacturing) - flt(frm.doc.produced_qty) :
+ flt(frm.doc.qty) - flt(frm.doc.material_transferred_for_manufacturing);
} else {
- var max = flt(this.frm.doc.qty) - flt(this.frm.doc.produced_qty);
+ var max = flt(frm.doc.qty) - flt(frm.doc.produced_qty);
}
frappe.prompt({fieldtype:"Float", label: __("Qty for {0}", [purpose]), fieldname:"qty",
@@ -266,7 +355,7 @@
frappe.call({
method:"erpnext.manufacturing.doctype.production_order.production_order.make_stock_entry",
args: {
- "production_order_id": me.frm.doc.name,
+ "production_order_id": frm.doc.name,
"purpose": purpose,
"qty": data.qty
},
@@ -277,59 +366,20 @@
});
}, __("Select Quantity"), __("Make"));
},
-
- bom_no: function() {
- return this.frm.call({
- doc: this.frm.doc,
- method: "set_production_order_operations",
+
+ stop_production_order: function(frm, status) {
+ frappe.call({
+ method: "erpnext.manufacturing.doctype.production_order.production_order.stop_unstop",
+ args: {
+ production_order: frm.doc.name,
+ status: status
+ },
callback: function(r) {
- if(r.message["set_scrap_wh_mandatory"]){
- cur_frm.toggle_reqd("scrap_warehouse", true);
+ if(r.message) {
+ frm.set_value("status", r.message);
+ frm.reload_doc();
}
}
- });
- },
-
- use_multi_level_bom: function() {
- if(this.frm.doc.bom_no) {
- this.frm.trigger("bom_no");
- }
- },
-
- qty: function() {
- frappe.ui.form.trigger("Production Order", 'bom_no')
- },
-});
-
-cur_frm.cscript['Stop Production Order'] = function() {
- $c_obj(cur_frm.doc, 'stop_unstop', 'Stopped', function(r, rt) {cur_frm.refresh();});
-}
-
-cur_frm.cscript['Unstop Production Order'] = function() {
- $c_obj(cur_frm.doc, 'stop_unstop', 'Unstopped', function(r, rt) {cur_frm.refresh();});
-}
-
-cur_frm.cscript['Transfer Raw Materials'] = function() {
- cur_frm.cscript.make_se('Material Transfer for Manufacture');
-}
-
-cur_frm.cscript['Update Finished Goods'] = function() {
- cur_frm.cscript.make_se('Manufacture');
-}
-
-cur_frm.fields_dict['production_item'].get_query = function(doc) {
- return {
- query: "erpnext.controllers.queries.item_query",
- filters:{
- 'is_stock_item': 1,
- }
+ })
}
}
-
-cur_frm.fields_dict['project'].get_query = function(doc, dt, dn) {
- return{
- filters:[
- ['Project', 'status', 'not in', 'Completed, Cancelled']
- ]
- }
-}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.json b/erpnext/manufacturing/doctype/production_order/production_order.json
index 94b6b95..ee033c4 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.json
+++ b/erpnext/manufacturing/doctype/production_order/production_order.json
@@ -95,7 +95,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nNot Started\nStopped\nUnstopped\nIn Process\nCompleted\nCancelled",
+ "options": "\nDraft\nSubmitted\nNot Started\nIn Process\nCompleted\nStopped\nCancelled",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@@ -145,38 +145,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "project",
- "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": "Project",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "project",
- "oldfieldtype": "Link",
- "options": "Project",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "",
"description": "",
"fieldname": "bom_no",
@@ -272,37 +240,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "description": "",
- "fieldname": "sales_order",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 1,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Order",
- "length": 0,
- "no_copy": 0,
- "options": "Sales Order",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "",
"fieldname": "qty",
"fieldtype": "Float",
@@ -335,37 +272,6 @@
"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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"default": "0",
"depends_on": "eval:doc.docstatus==1 && doc.skip_transfer==0",
"description": "",
@@ -433,6 +339,100 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "description": "",
+ "fieldname": "sales_order",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 1,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Sales Order",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Sales Order",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "project",
+ "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": "Project",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "project",
+ "oldfieldtype": "Link",
+ "options": "Project",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "warehouses",
"fieldtype": "Section Break",
"hidden": 0,
@@ -463,38 +463,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "description": "",
- "fieldname": "source_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": "Source Warehouse (for reserving Items)",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "wip_warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -525,34 +493,6 @@
"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,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"depends_on": "",
"description": "",
"fieldname": "fg_warehouse",
@@ -585,6 +525,34 @@
"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,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "scrap_warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -616,7 +584,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "time",
+ "fieldname": "required_items_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -625,10 +593,9 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Time",
+ "label": "Required Items",
"length": 0,
"no_copy": 0,
- "options": "fa fa-time",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -647,9 +614,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "",
- "fieldname": "expected_delivery_date",
- "fieldtype": "Date",
+ "fieldname": "required_items",
+ "fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -657,10 +623,43 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Expected Delivery Date",
+ "label": "Required Items",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Production Order Item",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "time",
+ "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": "Time",
"length": 0,
"no_copy": 0,
+ "options": "fa fa-time",
"permlevel": 0,
+ "precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@@ -708,7 +707,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "planned_end_date",
+ "fieldname": "actual_start_date",
"fieldtype": "Datetime",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -717,9 +716,9 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Planned End Date",
+ "label": "Actual Start Date",
"length": 0,
- "no_copy": 1,
+ "no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -767,7 +766,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "actual_start_date",
+ "fieldname": "planned_end_date",
"fieldtype": "Datetime",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -776,9 +775,9 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Actual Start Date",
+ "label": "Planned End Date",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -828,6 +827,36 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
+ "fieldname": "expected_delivery_date",
+ "fieldtype": "Date",
+ "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": "Expected Delivery Date",
+ "length": 0,
+ "no_copy": 0,
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
"fieldname": "operations_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1076,67 +1105,6 @@
"bold": 0,
"collapsible": 1,
"columns": 0,
- "fieldname": "required_items_section",
- "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": "Required Items",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "required_items",
- "fieldtype": "Table",
- "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": "Required Items",
- "length": 0,
- "no_copy": 1,
- "options": "Production Order Item",
- "permlevel": 0,
- "precision": "",
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 1,
- "columns": 0,
"fieldname": "more_info",
"fieldtype": "Section Break",
"hidden": 0,
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index 68da336..040a559 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -3,24 +3,21 @@
from __future__ import unicode_literals
import frappe
-
import json
-from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
from frappe import _
-from frappe.utils import time_diff_in_seconds
+from frappe.utils import flt, get_datetime, getdate, date_diff, cint, nowdate
from frappe.model.document import Document
-from frappe.model.mapper import get_mapped_doc
-from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
+from erpnext.manufacturing.doctype.bom.bom import validate_bom_no, get_bom_items_as_dict
from dateutil.relativedelta import relativedelta
from erpnext.stock.doctype.item.item import validate_end_of_life
-from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError, NotInWorkingHoursError
+from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
from erpnext.projects.doctype.timesheet.timesheet import OverlapError
from erpnext.stock.doctype.stock_entry.stock_entry import get_additional_costs
from erpnext.manufacturing.doctype.manufacturing_settings.manufacturing_settings import get_mins_between_operations
from erpnext.stock.stock_balance import get_planned_qty, update_bin_qty
-from erpnext.manufacturing.doctype.bom.bom import get_bom_items_as_dict
-from erpnext.stock.utils import get_bin
from frappe.utils.csvutils import getlink
+from erpnext.stock.utils import get_bin, validate_warehouse_company, get_latest_stock_qty
+from erpnext.utilities.transaction_base import validate_uom_is_integer
class OverProductionError(frappe.ValidationError): pass
class StockOverProductionError(frappe.ValidationError): pass
@@ -38,15 +35,19 @@
validate_bom_no(self.production_item, self.bom_no)
self.validate_sales_order()
- self.validate_warehouse()
+ self.validate_warehouse_belongs_to_company()
self.calculate_operating_cost()
self.validate_qty()
self.validate_operation_time()
self.status = self.get_status()
- from erpnext.utilities.transaction_base import validate_uom_is_integer
validate_uom_is_integer(self, "stock_uom", ["qty", "produced_qty"])
+ if not self.get("required_items"):
+ self.set_required_items()
+ else:
+ self.set_available_qty()
+
def validate_sales_order(self):
if self.sales_order:
so = frappe.db.sql("""select name, delivery_date, project from `tabSales Order`
@@ -64,11 +65,14 @@
else:
frappe.throw(_("Sales Order {0} is not valid").format(self.sales_order))
- def validate_warehouse(self):
- from erpnext.stock.utils import validate_warehouse_company
+ def validate_warehouse_belongs_to_company(self):
+ warehouses = [self.fg_warehouse, self.wip_warehouse]
+ for d in self.get("required_items"):
+ if d.source_warehouse not in warehouses:
+ warehouses.append(d.source_warehouse)
- for w in [self.source_warehouse, self.fg_warehouse, self.wip_warehouse]:
- validate_warehouse_company(w, self.company)
+ for wh in warehouses:
+ validate_warehouse_company(wh, self.company)
def calculate_operating_cost(self):
self.planned_operating_cost, self.actual_operating_cost = 0.0, 0.0
@@ -79,7 +83,8 @@
self.planned_operating_cost += flt(d.planned_operating_cost)
self.actual_operating_cost += flt(d.actual_operating_cost)
- variable_cost = self.actual_operating_cost if self.actual_operating_cost else self.planned_operating_cost
+ variable_cost = self.actual_operating_cost if self.actual_operating_cost \
+ else self.planned_operating_cost
self.total_operating_cost = flt(self.additional_operating_cost) + flt(variable_cost)
def validate_production_order_against_so(self):
@@ -101,22 +106,16 @@
# total qty in SO
so_qty = flt(so_item_qty) + flt(dnpi_qty)
- allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings", "over_production_allowance_percentage"))
+ allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings",
+ "over_production_allowance_percentage"))
+
if total_qty > so_qty + (allowance_percentage/100 * so_qty):
- frappe.throw(_("Cannot produce more Item {0} than Sales Order quantity {1}").format(self.production_item,
- so_qty), OverProductionError)
-
- def stop_unstop(self, status):
- """ Called from client side on Stop/Unstop event"""
- status = self.update_status(status)
- self.update_planned_qty()
- frappe.msgprint(_("Production Order status is {0}").format(status))
- self.notify_update()
-
+ frappe.throw(_("Cannot produce more Item {0} than Sales Order quantity {1}")
+ .format(self.production_item, so_qty), OverProductionError)
def update_status(self, status=None):
'''Update status of production order if unknown'''
- if not status:
+ if status != "Stopped":
status = self.get_status(status)
if status != self.status:
@@ -167,7 +166,6 @@
self.db_set(fieldname, qty)
def before_submit(self):
- self.set_required_items()
self.make_time_logs()
def on_submit(self):
@@ -184,10 +182,10 @@
self.validate_cancel()
frappe.db.set(self,'status', 'Cancelled')
- self.clear_required_items()
self.delete_timesheet()
self.update_completed_qty_in_material_request()
self.update_planned_qty()
+ self.update_reserved_qty_for_production()
def validate_cancel(self):
if self.status == "Stopped":
@@ -214,12 +212,11 @@
def set_production_order_operations(self):
"""Fetch operations from BOM and set in 'Production Order'"""
+ self.set('operations', [])
if not self.bom_no \
or cint(frappe.db.get_single_value("Manufacturing Settings", "disable_capacity_planning")):
return
-
- self.set('operations', [])
if self.use_multi_level_bom:
bom_list = frappe.get_doc("BOM", self.bom_no).traverse_tree()
@@ -240,8 +237,6 @@
self.set('operations', operations)
self.calculate_time()
- return check_if_scrap_warehouse_mandatory(self.bom_no)
-
def calculate_time(self):
bom_qty = frappe.db.get_value("BOM", self.bom_no, "quantity")
@@ -403,62 +398,60 @@
update bin reserved_qty_for_production
called from Stock Entry for production, after submit, cancel
'''
- if self.docstatus==1 and self.source_warehouse:
- if self.material_transferred_for_manufacturing == self.produced_qty:
- # clear required items table and save document
- self.clear_required_items()
- else:
- # calculate transferred qty based on submitted
- # stock entries
- self.update_transaferred_qty_for_required_items()
+ if self.docstatus==1:
+ # calculate transferred qty based on submitted stock entries
+ self.update_transaferred_qty_for_required_items()
- # update in bin
- self.update_reserved_qty_for_production()
-
- def clear_required_items(self):
- '''Remove the required_items table and update the bins'''
- items = [d.item_code for d in self.required_items]
- self.required_items = []
-
- self.update_child_table('required_items')
-
- # completed, update reserved qty in bin
- self.update_reserved_qty_for_production(items)
+ # update in bin
+ self.update_reserved_qty_for_production()
def update_reserved_qty_for_production(self, items=None):
'''update reserved_qty_for_production in bins'''
- if not self.source_warehouse:
- return
-
- if not items:
- items = [d.item_code for d in self.required_items]
-
- for item in items:
- stock_bin = get_bin(item, self.source_warehouse)
- stock_bin.update_reserved_qty_for_production()
+ for d in self.required_items:
+ if d.source_warehouse:
+ stock_bin = get_bin(d.item_code, d.source_warehouse)
+ stock_bin.update_reserved_qty_for_production()
+
+ def get_items_and_operations_from_bom(self):
+ self.set_required_items()
+ self.set_production_order_operations()
+
+ return check_if_scrap_warehouse_mandatory(self.bom_no)
+
+ def set_available_qty(self):
+ for d in self.get("required_items"):
+ if d.source_warehouse:
+ d.available_qty_at_source_warehouse = get_latest_stock_qty(d.item_code, d.source_warehouse)
+
+ if self.wip_warehouse:
+ d.available_qty_at_wip_warehouse = get_latest_stock_qty(d.item_code, self.wip_warehouse)
def set_required_items(self):
'''set required_items for production to keep track of reserved qty'''
- if self.source_warehouse:
+ self.required_items = []
+ if self.bom_no and self.qty:
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=self.qty,
fetch_exploded = self.use_multi_level_bom)
for item in item_dict.values():
- self.append('required_items', {'item_code': item.item_code,
- 'required_qty': item.qty})
-
- #print frappe.as_json(self.required_items)
+ self.append('required_items', {
+ 'item_code': item.item_code,
+ 'required_qty': item.qty,
+ 'source_warehouse': item.source_warehouse or item.default_warehouse
+ })
+
+ self.set_available_qty()
def update_transaferred_qty_for_required_items(self):
'''update transferred qty from submitted stock entries for that item against
the production order'''
for d in self.required_items:
- transferred_qty = frappe.db.sql('''select count(qty)
+ transferred_qty = frappe.db.sql('''select sum(qty)
from `tabStock Entry` entry, `tabStock Entry Detail` detail
where
entry.production_order = %s
- entry.purpose = "Material Transfer for Manufacture"
+ and entry.purpose = "Material Transfer for Manufacture"
and entry.docstatus = 1
and detail.parent = entry.name
and detail.item_code = %s''', (self.name, d.item_code))[0][0]
@@ -496,10 +489,12 @@
if not res["bom_no"]:
if project:
- frappe.throw(_("Default BOM for {0} not found for Project {1}").format(item, project))
- frappe.throw(_("Default BOM for {0} not found").format(item))
+ res = get_item_details(item)
+ frappe.msgprint(_("Default BOM not found for Item {0} and Project {1}").format(item, project))
+ else:
+ frappe.throw(_("Default BOM for {0} not found").format(item))
- res['project'] = frappe.db.get_value('BOM', res['bom_no'], 'project')
+ res['project'] = project or frappe.db.get_value('BOM', res['bom_no'], 'project')
res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
return res
@@ -507,16 +502,21 @@
@frappe.whitelist()
def check_if_scrap_warehouse_mandatory(bom_no):
res = {"set_scrap_wh_mandatory": False }
- bom = frappe.get_doc("BOM", bom_no)
+ if bom_no:
+ bom = frappe.get_doc("BOM", bom_no)
- if len(bom.scrap_items) > 0:
- res["set_scrap_wh_mandatory"] = True
+ if len(bom.scrap_items) > 0:
+ res["set_scrap_wh_mandatory"] = True
return res
@frappe.whitelist()
def make_stock_entry(production_order_id, purpose, qty=None):
production_order = frappe.get_doc("Production Order", production_order_id)
+ if not frappe.db.get_value("Warehouse", production_order.wip_warehouse, "is_group"):
+ wip_warehouse = production_order.wip_warehouse
+ else:
+ wip_warehouse = None
stock_entry = frappe.new_doc("Stock Entry")
stock_entry.purpose = purpose
@@ -528,12 +528,10 @@
stock_entry.fg_completed_qty = qty or (flt(production_order.qty) - flt(production_order.produced_qty))
if purpose=="Material Transfer for Manufacture":
- if production_order.source_warehouse:
- stock_entry.from_warehouse = production_order.source_warehouse
- stock_entry.to_warehouse = production_order.wip_warehouse
+ stock_entry.to_warehouse = wip_warehouse
stock_entry.project = production_order.project
else:
- stock_entry.from_warehouse = production_order.wip_warehouse
+ stock_entry.from_warehouse = wip_warehouse
stock_entry.to_warehouse = production_order.fg_warehouse
additional_costs = get_additional_costs(production_order, fg_qty=stock_entry.fg_completed_qty)
stock_entry.project = production_order.project
@@ -601,3 +599,18 @@
frappe.throw(_("Already completed"))
return ts
+
+@frappe.whitelist()
+def stop_unstop(production_order, status):
+ """ Called from client side on Stop/Unstop event"""
+
+ if not frappe.has_permission("Production Order", "write"):
+ frappe.throw(_("Not permitted"), frappe.PermissionError)
+
+ pro_order = frappe.get_doc("Production Order", production_order)
+ pro_order.update_status(status)
+ pro_order.update_planned_qty()
+ frappe.msgprint(_("Production Order has been {0}").format(status))
+ pro_order.notify_update()
+
+ return pro_order.status
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_order/test_production_order.py b/erpnext/manufacturing/doctype/production_order/test_production_order.py
index cdadba4..18aa51d 100644
--- a/erpnext/manufacturing/doctype/production_order/test_production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/test_production_order.py
@@ -8,7 +8,7 @@
from frappe.utils import flt, time_diff_in_hours, now, add_days, cint
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
from erpnext.manufacturing.doctype.production_order.production_order \
- import make_stock_entry, ItemHasVariantError
+ import make_stock_entry, ItemHasVariantError, stop_unstop
from erpnext.stock.doctype.stock_entry import test_stock_entry
from erpnext.stock.doctype.item.test_item import get_total_projected_qty
from erpnext.stock.utils import get_bin
@@ -228,10 +228,46 @@
cint(bin1_on_start_production.reserved_qty_for_production))
self.assertEqual(cint(bin1_on_end_production.projected_qty),
cint(bin1_on_end_production.projected_qty))
+
+ def test_reserved_qty_for_stopped_production(self):
+ test_stock_entry.make_stock_entry(item_code="_Test Item",
+ target= self.warehouse, qty=100, basic_rate=100)
+ test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100",
+ target= self.warehouse, qty=100, basic_rate=100)
- # required_items removed
- self.pro_order.reload()
- self.assertEqual(len(self.pro_order.required_items), 0)
+ # 0 0 0
+
+ self.test_reserved_qty_for_production_submit()
+
+ #2 0 -2
+
+ s = frappe.get_doc(make_stock_entry(self.pro_order.name,
+ "Material Transfer for Manufacture", 1))
+
+ s.submit()
+
+ #1 -1 0
+
+ bin1_on_start_production = get_bin(self.item, self.warehouse)
+
+ # reserved_qty_for_producion updated
+ self.assertEqual(cint(self.bin1_at_start.reserved_qty_for_production) + 1,
+ cint(bin1_on_start_production.reserved_qty_for_production))
+
+ # projected qty will now be 2 less (becuase of item movement)
+ self.assertEqual(cint(self.bin1_at_start.projected_qty),
+ cint(bin1_on_start_production.projected_qty) + 2)
+
+ # STOP
+ stop_unstop(self.pro_order.name, "Stopped")
+
+ bin1_on_stop_production = get_bin(self.item, self.warehouse)
+
+ # no change in reserved / projected
+ self.assertEqual(cint(bin1_on_stop_production.reserved_qty_for_production),
+ cint(self.bin1_at_start.reserved_qty_for_production))
+ self.assertEqual(cint(bin1_on_stop_production.projected_qty) + 1,
+ cint(self.bin1_at_start.projected_qty))
def test_scrap_material_qty(self):
prod_order = make_prod_order_test_record(planned_start_date=now(), qty=2)
@@ -286,10 +322,11 @@
pro_order.company = args.company or "_Test Company"
pro_order.stock_uom = args.stock_uom or "_Test UOM"
pro_order.use_multi_level_bom=0
- pro_order.set_production_order_operations()
-
+ pro_order.get_items_and_operations_from_bom()
+
if args.source_warehouse:
- pro_order.source_warehouse = args.source_warehouse
+ for item in pro_order.get("required_items"):
+ item.source_warehouse = args.source_warehouse
if args.planned_start_date:
pro_order.planned_start_date = args.planned_start_date
diff --git a/erpnext/manufacturing/doctype/production_order_item/production_order_item.json b/erpnext/manufacturing/doctype/production_order_item/production_order_item.json
index a0fe7ab..06a7876 100644
--- a/erpnext/manufacturing/doctype/production_order_item/production_order_item.json
+++ b/erpnext/manufacturing/doctype/production_order_item/production_order_item.json
@@ -13,6 +13,7 @@
"engine": "InnoDB",
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -43,6 +44,157 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "source_warehouse",
+ "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": "Source 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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "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 Name",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "description",
+ "fieldtype": "Text",
+ "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": "Description",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "qty_section",
+ "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": "Qty",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -72,6 +224,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -99,6 +252,95 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_9",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "available_qty_at_source_warehouse",
+ "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": "Available Qty at Source Warehouse",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "available_qty_at_wip_warehouse",
+ "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": "Available Qty at WIP Warehouse",
+ "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,
+ "unique": 0
}
],
"has_web_view": 0,
@@ -111,7 +353,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-03-28 14:18:36.342161",
+ "modified": "2017-05-15 17:37:20.212361",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Order Item",
diff --git a/erpnext/manufacturing/doctype/production_order_operation/production_order_operation.json b/erpnext/manufacturing/doctype/production_order_operation/production_order_operation.json
index 618235f..89306c4 100644
--- a/erpnext/manufacturing/doctype/production_order_operation/production_order_operation.json
+++ b/erpnext/manufacturing/doctype/production_order_operation/production_order_operation.json
@@ -13,6 +13,7 @@
"engine": "InnoDB",
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -42,6 +43,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -74,6 +76,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -85,7 +88,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
- "in_list_view": 1,
+ "in_list_view": 0,
"in_standard_filter": 0,
"label": "BOM",
"length": 0,
@@ -104,6 +107,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -135,6 +139,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -163,6 +168,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -193,6 +199,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -224,6 +231,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -256,6 +264,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -285,6 +294,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -314,6 +324,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -343,6 +354,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -371,6 +383,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -403,6 +416,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -434,6 +448,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -464,6 +479,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -493,6 +509,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -522,6 +539,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -552,6 +570,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -580,6 +599,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -610,6 +630,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -651,7 +672,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-03-27 15:56:29.010336",
+ "modified": "2017-05-29 18:02:04.252419",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Order Operation",
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index e7cf5f2..80d64e8 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -411,4 +411,7 @@
erpnext.patches.v8_1.setup_gst_india #2017-06-27
execute:frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
erpnext.patches.v8_1.removed_roles_from_gst_report_non_indian_account
-erpnext.patches.v8_1.gst_fixes
+erpnext.patches.v8_1.gst_fixes #2017-07-06
+erpnext.patches.v8_0.update_production_orders
+erpnext.patches.v8_1.remove_sales_invoice_from_returned_serial_no
+erpnext.patches.v8_1.allow_invoice_copy_to_edit_after_submit
\ No newline at end of file
diff --git a/erpnext/patches/v7_0/create_warehouse_nestedset.py b/erpnext/patches/v7_0/create_warehouse_nestedset.py
index 06766b9..dbf1241 100644
--- a/erpnext/patches/v7_0/create_warehouse_nestedset.py
+++ b/erpnext/patches/v7_0/create_warehouse_nestedset.py
@@ -73,7 +73,7 @@
if not company:
return
- if cint(erpnext.is_perpetual_inventory_enabled(company)):
+ if cint(erpnext.is_perpetual_inventory_enabled(company.name)):
parent_account = frappe.db.sql("""select name from tabAccount
where account_type='Stock' and company=%s and is_group=1
and (warehouse is null or warehouse = '')""", company.name)
diff --git a/erpnext/patches/v8_0/update_production_orders.py b/erpnext/patches/v8_0/update_production_orders.py
new file mode 100644
index 0000000..06b8ce7
--- /dev/null
+++ b/erpnext/patches/v8_0/update_production_orders.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ # reload schema
+ for doctype in ("Production Order", "Production Order Item", "Production Order Operation",
+ "BOM Item", "BOM Explosion Item", "BOM"):
+ frappe.reload_doctype(doctype)
+
+ # fetch all draft and submitted production orders
+ fields = ["name"]
+ if "source_warehouse" in frappe.db.get_table_columns("Production Order"):
+ fields.append("source_warehouse")
+
+ pro_orders = frappe.get_all("Production Order", filters={"docstatus": ["!=", 2]}, fields=fields)
+
+ count = 0
+ for p in pro_orders:
+ pro_order = frappe.get_doc("Production Order", p.name)
+ count += 1
+
+ # set required items table
+ pro_order.set_required_items()
+
+ for item in pro_order.get("required_items"):
+ # set source warehouse based on parent
+ if not item.source_warehouse and "source_warehouse" in fields:
+ item.source_warehouse = pro_order.get("source_warehouse")
+ item.db_update()
+
+ if pro_order.docstatus == 1:
+ # update transferred qty based on Stock Entry, it also updates db
+ pro_order.update_transaferred_qty_for_required_items()
+
+ # Set status where it was 'Unstopped', as it is deprecated
+ if pro_order.status == "Unstopped":
+ status = pro_order.get_status()
+ pro_order.db_set("status", status)
+ elif pro_order.status == "Stopped":
+ pro_order.update_reserved_qty_for_production()
+
+ if count % 200 == 0:
+ frappe.db.commit()
\ No newline at end of file
diff --git a/erpnext/patches/v8_1/allow_invoice_copy_to_edit_after_submit.py b/erpnext/patches/v8_1/allow_invoice_copy_to_edit_after_submit.py
new file mode 100644
index 0000000..1fb297f
--- /dev/null
+++ b/erpnext/patches/v8_1/allow_invoice_copy_to_edit_after_submit.py
@@ -0,0 +1,12 @@
+import frappe
+
+def execute():
+ inv_copy_options = "ORIGINAL FOR RECIPIENT\nDUPLICATE FOR TRANSPORTER\nDUPLICATE FOR SUPPLIER\nTRIPLICATE FOR SUPPLIER"
+
+ frappe.db.sql("""update `tabCustom Field` set allow_on_submit=1, options=%s
+ where fieldname='invoice_copy' and dt = 'Sales Invoice'
+ """, inv_copy_options)
+
+ frappe.db.sql("""update `tabCustom Field` set read_only=1
+ where fieldname='gst_state_number' and dt = 'Address'
+ """)
diff --git a/erpnext/patches/v8_1/gst_fixes.py b/erpnext/patches/v8_1/gst_fixes.py
index 5454f0f..b47879c 100644
--- a/erpnext/patches/v8_1/gst_fixes.py
+++ b/erpnext/patches/v8_1/gst_fixes.py
@@ -1,7 +1,19 @@
import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_field
+from erpnext.regional.india.setup import update_address_template
def execute():
- frappe.db.sql("""update `tabCustom Field` set label = 'HSN/SAC Code'
+ company = frappe.get_all('Company', filters = {'country': 'India'})
+ if not company:
+ return
+
+ update_existing_custom_fields()
+ add_custom_fields()
+ update_address_template()
+ frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
+
+def update_existing_custom_fields():
+ frappe.db.sql("""update `tabCustom Field` set label = 'HSN/SAC'
where fieldname='gst_hsn_code' and label='GST HSN Code'
""")
@@ -21,7 +33,26 @@
where fieldname='gst_hsn_code' and dt in ('Sales Invoice Item', 'Purchase Invoice Item')
""")
- # reload gst print format for Indian users
- company = frappe.get_all('Company', filters = {'country': 'India'})
- if company:
- frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
\ No newline at end of file
+def add_custom_fields():
+ hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
+ fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description')
+
+ custom_fields = {
+ 'Address': [
+ dict(fieldname='gst_state_number', label='GST State Number',
+ fieldtype='Int', insert_after='gst_state'),
+ ],
+ 'Sales Invoice': [
+ dict(fieldname='invoice_copy', label='Invoice Copy',
+ fieldtype='Select', insert_after='project', print_hide=1, allow_on_submit=1,
+ options='ORIGINAL FOR RECIPIENT\nDUPLICATE FOR TRANSPORTER\nTRIPLICATE FOR SUPPLIER'),
+ ],
+ 'Sales Order Item': [hsn_sac_field],
+ 'Delivery Note Item': [hsn_sac_field],
+ 'Purchase Order Item': [hsn_sac_field],
+ 'Purchase Receipt Item': [hsn_sac_field]
+ }
+
+ for doctype, fields in custom_fields.items():
+ for df in fields:
+ create_custom_field(doctype, df)
diff --git a/erpnext/patches/v8_1/remove_sales_invoice_from_returned_serial_no.py b/erpnext/patches/v8_1/remove_sales_invoice_from_returned_serial_no.py
new file mode 100644
index 0000000..3962f8f
--- /dev/null
+++ b/erpnext/patches/v8_1/remove_sales_invoice_from_returned_serial_no.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doctype("Serial No")
+
+ frappe.db.sql("""
+ update
+ `tabSerial No`
+ set
+ sales_invoice = NULL
+ where
+ sales_invoice in (select return_against from
+ `tabSales Invoice` where docstatus =1 and is_return=1)
+ and sales_invoice is not null and sales_invoice !='' """)
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 642ff1b..e917a75 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -689,7 +689,7 @@
return '<th style="min-width: 80px;" class="text-right">' + (head || "") + "</th>";
}
}
- ).join("\n");
+ ).join("");
var distinct_item_names = [];
var distinct_items = [];
@@ -705,14 +705,15 @@
if(!item_tax_record) { return null; }
return repl("<tr><td>%(item_name)s</td><td class='text-right'>%(taxable_amount)s</td>%(taxes)s</tr>", {
item_name: item.item_name,
- taxable_amount: item.net_amount,
+ taxable_amount: format_currency(item.net_amount,
+ company_currency, precision("net_amount", item)),
taxes: $.map(tax_accounts, function(head) {
return item_tax_record[head[0]] ?
"<td class='text-right'>(" + item_tax_record[head[0]][0] + ") " + item_tax_record[head[0]][1] + "</td>" :
"<td></td>";
- }).join("\n")
+ }).join("")
});
- }).join("\n");
+ }).join("");
if(!rows) return "";
return '<div class="tax-break-up" style="overflow-x: auto;">\
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index c4f9e8a..fd91227 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -63,37 +63,32 @@
});
frappe.ui.form.on(this.frm.doctype, "additional_discount_percentage", function(frm) {
- if (frm.via_discount_amount) {
- return;
- }
-
if(!frm.doc.apply_discount_on) {
frappe.msgprint(__("Please set 'Apply Additional Discount On'"));
- return
+ return;
}
frm.via_discount_percentage = true;
if(frm.doc.additional_discount_percentage && frm.doc.discount_amount) {
// Reset discount amount and net / grand total
- frm.set_value("discount_amount", 0);
+ frm.doc.discount_amount = 0;
+ frm.cscript.calculate_taxes_and_totals();
}
var total = flt(frm.doc[frappe.model.scrub(frm.doc.apply_discount_on)]);
var discount_amount = flt(total*flt(frm.doc.additional_discount_percentage) / 100,
precision("discount_amount"));
- frm.set_value("discount_amount", discount_amount);
- delete frm.via_discount_percentage;
+ frm.set_value("discount_amount", discount_amount)
+ .then(() => delete frm.via_discount_percentage);
});
frappe.ui.form.on(this.frm.doctype, "discount_amount", function(frm) {
frm.cscript.set_dynamic_labels();
if (!frm.via_discount_percentage) {
- frm.via_discount_amount = true;
- frm.set_value("additional_discount_percentage", 0);
- delete frm.via_discount_amount;
+ frm.doc.additional_discount_percentage = 0;
}
frm.cscript.calculate_taxes_and_totals();
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index e30daa2..43b45d9 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -139,17 +139,17 @@
var current_year = moment(new Date()).year();
var next_year = current_year + 1;
if (!fy) {
- fy = ["01-01", "31-12"];
+ fy = ["01-01", "12-31"];
next_year = current_year;
}
var year_start_date = current_year + "-" + fy[0];
if (year_start_date > frappe.datetime.get_today()) {
- next_year = current_year
+ next_year = current_year;
current_year -= 1;
}
- slide.get_field("fy_start_date").set_value(fy[0] + "-" + current_year);
- slide.get_field("fy_end_date").set_value(fy[1] + "-" + next_year);
+ slide.get_field("fy_start_date").set_value(current_year + '-' + fy[0]);
+ slide.get_field("fy_end_date").set_value(next_year + '-' + fy[1]);
}
},
@@ -180,13 +180,11 @@
},
bind_events: function (slide) {
-
- // TODO remove this
slide.get_input("fy_start_date").on("change", function () {
+ var start_date = slide.form.fields_dict.fy_start_date.get_value();
var year_end_date =
- frappe.datetime.add_days(frappe.datetime.add_months(
- frappe.datetime.user_to_obj(slide.get_input("fy_start_date").val()), 12), -1);
- slide.form.fields_dict.fy_end_date.set_value(frappe.datetime.obj_to_user(year_end_date));
+ frappe.datetime.add_days(frappe.datetime.add_months(start_date, 12), -1);
+ slide.form.fields_dict.fy_end_date.set_value(year_end_date);
});
}
},
@@ -356,23 +354,23 @@
// default 1st Jan - 31st Dec
erpnext.setup.fiscal_years = {
- "Afghanistan": ["20-12", "21-12"],
- "Australia": ["01-07", "30-06"],
- "Bangladesh": ["01-07", "30-06"],
- "Canada": ["01-04", "31-03"],
- "Costa Rica": ["01-10", "30-09"],
- "Egypt": ["01-07", "30-06"],
- "Hong Kong": ["01-04", "31-03"],
- "India": ["01-04", "31-03"],
- "Iran": ["23-06", "22-06"],
- "Italy": ["01-07", "30-06"],
- "Myanmar": ["01-04", "31-03"],
- "New Zealand": ["01-04", "31-03"],
- "Pakistan": ["01-07", "30-06"],
- "Singapore": ["01-04", "31-03"],
- "South Africa": ["01-03", "28-02"],
- "Thailand": ["01-10", "30-09"],
- "United Kingdom": ["01-04", "31-03"],
+ "Afghanistan": ["12-20", "12-21"],
+ "Australia": ["07-01", "06-30"],
+ "Bangladesh": ["07-01", "06-30"],
+ "Canada": ["04-01", "03-31"],
+ "Costa Rica": ["10-01", "09-30"],
+ "Egypt": ["07-01", "06-30"],
+ "Hong Kong": ["04-01", "03-31"],
+ "India": ["04-01", "03-31"],
+ "Iran": ["06-23", "06-22"],
+ "Italy": ["07-01", "06-30"],
+ "Myanmar": ["04-01", "03-31"],
+ "New Zealand": ["04-01", "03-31"],
+ "Pakistan": ["07-01", "06-30"],
+ "Singapore": ["04-01", "03-31"],
+ "South Africa": ["03-01", "02-28"],
+ "Thailand": ["10-01", "09-30"],
+ "United Kingdom": ["04-01", "03-31"],
};
frappe.setup.on("before_load", function () {
diff --git a/erpnext/regional/india/__init__.py b/erpnext/regional/india/__init__.py
index 0b1b163..9a6c376 100644
--- a/erpnext/regional/india/__init__.py
+++ b/erpnext/regional/india/__init__.py
@@ -72,5 +72,5 @@
"Tripura": "16",
"Uttar Pradesh": "35",
"Uttarakhand": "36",
- "West Bengal": "37"
+ "West Bengal": "19"
}
\ No newline at end of file
diff --git a/erpnext/regional/india/address_template.html b/erpnext/regional/india/address_template.html
index 46879ad..1bcc5ad 100644
--- a/erpnext/regional/india/address_template.html
+++ b/erpnext/regional/india/address_template.html
@@ -1,6 +1,7 @@
{{ address_line1 }}<br>{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}{{ city }}<br>
-{% if state %}{{ state }}<br>{% endif -%}
-{% if pincode %}{{ pincode }}<br>{% endif -%}
+{% if gst_state %}{{ gst_state }}{% endif -%},
+{% if gst_state_number %}State Code: {{ gst_state_number }}<br>{% endif -%}
+{% if pincode %}PIN: {{ pincode }}<br>{% endif -%}
{{ country }}<br>
{% if phone %}Phone: {{ phone }}<br>{% endif -%}
{% if fax %}Fax: {{ fax }}<br>{% endif -%}
diff --git a/erpnext/regional/india/gst_state_code_data.json b/erpnext/regional/india/gst_state_code_data.json
index 89dc193..196f8d0 100644
--- a/erpnext/regional/india/gst_state_code_data.json
+++ b/erpnext/regional/india/gst_state_code_data.json
@@ -15,7 +15,7 @@
"state_name": "Uttarakhand"
},
{
- "state_number": "37",
+ "state_number": "19",
"state_code": "WB",
"state_name": "West Bengal"
},
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 46cfdb8..93aea0d 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -74,12 +74,17 @@
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
def make_custom_fields():
+ hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
+ fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description')
+
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
insert_after='fax'),
dict(fieldname='gst_state', label='GST State', fieldtype='Select',
- options='\n'.join(states), insert_after='gstin')
+ options='\n'.join(states), insert_after='gstin'),
+ dict(fieldname='gst_state_number', label='GST State Number',
+ fieldtype='Int', insert_after='gst_state', read_only=1),
],
'Purchase Invoice': [
dict(fieldname='supplier_gstin', label='Supplier GSTIN',
@@ -96,21 +101,20 @@
dict(fieldname='company_gstin', label='Company GSTIN',
fieldtype='Data', insert_after='company_address',
options='company_address.gstin', print_hide=1),
+ dict(fieldname='invoice_copy', label='Invoice Copy',
+ fieldtype='Select', insert_after='project', print_hide=1, allow_on_submit=1,
+ options='ORIGINAL FOR RECIPIENT\nDUPLICATE FOR TRANSPORTER\nDUPLICATE FOR SUPPLIER\nTRIPLICATE FOR SUPPLIER')
],
'Item': [
- dict(fieldname='gst_hsn_code', label='HSN/SAC Code',
+ dict(fieldname='gst_hsn_code', label='HSN/SAC',
fieldtype='Link', options='GST HSN Code', insert_after='item_group'),
],
- 'Sales Invoice Item': [
- dict(fieldname='gst_hsn_code', label='HSN/SAC Code',
- fieldtype='Data', options='item_code.gst_hsn_code',
- insert_after='description'),
- ],
- 'Purchase Invoice Item': [
- dict(fieldname='gst_hsn_code', label='HSN/SAC Code',
- fieldtype='Data', options='item_code.gst_hsn_code',
- insert_after='description'),
- ]
+ 'Sales Order Item': [hsn_sac_field],
+ 'Delivery Note Item': [hsn_sac_field],
+ 'Sales Invoice Item': [hsn_sac_field],
+ 'Purchase Order Item': [hsn_sac_field],
+ 'Purchase Receipt Item': [hsn_sac_field],
+ 'Purchase Invoice Item': [hsn_sac_field]
}
for doctype, fields in custom_fields.items():
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index c4acafc..84e5f3e 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -7,6 +7,7 @@
return
if doc.gstin:
+ doc.gstin = doc.gstin.upper()
if doc.gstin != "NA":
p = re.compile("[0-9]{2}[a-zA-Z]{5}[0-9]{4}[a-zA-Z]{1}[1-9A-Za-z]{1}[Z]{1}[0-9a-zA-Z]{1}")
if not p.match(doc.gstin):
@@ -17,6 +18,7 @@
doc.gst_state = doc.state
if doc.gst_state:
- state_number = state_numbers[doc.gst_state]
- if state_number != doc.gstin[:2]:
- frappe.throw(_("First 2 digits of GSTIN should match with State number {0}").format(state_number))
+ doc.gst_state_number = state_numbers[doc.gst_state]
+ if doc.gstin != "NA" and doc.gst_state_number != doc.gstin[:2]:
+ frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
+ .format(doc.gst_state_number))
diff --git a/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json b/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json
index b16aada..3850847 100644
--- a/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json
+++ b/erpnext/regional/print_format/gst_tax_invoice/gst_tax_invoice.json
@@ -7,10 +7,10 @@
"docstatus": 0,
"doctype": "Print Format",
"font": "Default",
- "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\t\\t\\t\\t<h2>Sales Invoice<br><small>{{ doc.name }}</small>\\t\\t\\t\\t</h2></div>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"company_address_display\", \"label\": \"Company Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"posting_date\", \"label\": \"Date\"}, {\"print_hide\": 0, \"fieldname\": \"due_date\", \"label\": \"Payment Due Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"options\": \"<hr>\", \"fieldname\": \"_custom_html\", \"fieldtype\": \"HTML\", \"label\": \"Custom HTML\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\", \"label\": \"Customer Name\"}, {\"print_hide\": 0, \"fieldname\": \"address_display\", \"label\": \"Address\"}, {\"print_hide\": 0, \"fieldname\": \"contact_display\", \"label\": \"Contact\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"shipping_address\", \"label\": \"Shipping Address\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"200px\"}, {\"print_hide\": 0, \"fieldname\": \"gst_hsn_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\", \"label\": \"Items\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"label\": \"Total\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}], \"print_hide\": 0, \"fieldname\": \"taxes\", \"label\": \"Sales Taxes and Charges\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\", \"label\": \"Grand Total\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\", \"label\": \"In Words\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"other_charges_calculation\", \"align\": \"left\", \"label\": \"Item-wise Tax Breakup\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Terms\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"terms\", \"label\": \"Terms and Conditions Details\"}]",
+ "format_data": "[{\"fieldname\": \"print_heading_template\", \"fieldtype\": \"Custom HTML\", \"options\": \"<div class=\\\"print-heading\\\">\\n\\t<h2>\\n\\t\\tTAX INVOICE<br>\\n\\t\\t<small>{{ doc.name }}</small>\\n\\t</h2>\\n</div>\\n<h2 class=\\\"text-center\\\">\\n\\t{% if doc.invoice_copy -%}\\n\\t\\t<small>{{ doc.invoice_copy }}</small>\\n\\t{% endif -%}\\n</h2>\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"company\", \"label\": \"Company\"}, {\"print_hide\": 0, \"fieldname\": \"company_address_display\", \"label\": \"Company Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"posting_date\", \"label\": \"Date\"}, {\"print_hide\": 0, \"fieldname\": \"due_date\", \"label\": \"Payment Due Date\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"options\": \"<hr>\", \"fieldname\": \"_custom_html\", \"fieldtype\": \"HTML\", \"label\": \"Custom HTML\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Address\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"customer_name\", \"label\": \"Customer Name\"}, {\"print_hide\": 0, \"fieldname\": \"address_display\", \"label\": \"Address\"}, {\"print_hide\": 0, \"fieldname\": \"contact_display\", \"label\": \"Contact\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"shipping_address\", \"label\": \"Shipping Address\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"item_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"200px\"}, {\"print_hide\": 0, \"fieldname\": \"gst_hsn_code\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"qty\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"uom\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"rate\", \"print_width\": \"\"}, {\"print_hide\": 0, \"fieldname\": \"amount\", \"print_width\": \"\"}], \"print_hide\": 0, \"fieldname\": \"items\", \"label\": \"Items\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"total\", \"label\": \"Total\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"visible_columns\": [{\"print_hide\": 0, \"fieldname\": \"description\", \"print_width\": \"300px\"}], \"print_hide\": 0, \"fieldname\": \"taxes\", \"label\": \"Sales Taxes and Charges\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"grand_total\", \"label\": \"Grand Total\"}, {\"print_hide\": 0, \"fieldname\": \"rounded_total\", \"label\": \"Rounded Total\"}, {\"print_hide\": 0, \"fieldname\": \"in_words\", \"label\": \"In Words\"}, {\"fieldtype\": \"Section Break\", \"label\": \"\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"other_charges_calculation\", \"align\": \"left\", \"label\": \"Tax Breakup\"}, {\"fieldtype\": \"Section Break\", \"label\": \"Terms\"}, {\"fieldtype\": \"Column Break\"}, {\"print_hide\": 0, \"fieldname\": \"terms\", \"label\": \"Terms and Conditions Details\"}]",
"idx": 0,
"line_breaks": 0,
- "modified": "2017-07-04 17:13:44.911156",
+ "modified": "2017-07-07 13:06:20.042807",
"modified_by": "Administrator",
"module": "Regional",
"name": "GST Tax Invoice",
diff --git a/erpnext/schools/api.py b/erpnext/schools/api.py
index db65a69..c613c8c 100644
--- a/erpnext/schools/api.py
+++ b/erpnext/schools/api.py
@@ -114,13 +114,17 @@
return guardians
@frappe.whitelist()
-def get_student_group_students(student_group):
+def get_student_group_students(student_group, include_inactive=0):
"""Returns List of student, student_name in Student Group.
:param student_group: Student Group.
"""
- students = frappe.get_list("Student Group Student", fields=["student", "student_name"] ,
- filters={"parent": student_group, "active": 1}, order_by= "group_roll_number")
+ if include_inactive:
+ students = frappe.get_list("Student Group Student", fields=["student", "student_name"] ,
+ filters={"parent": student_group}, order_by= "group_roll_number")
+ else:
+ students = frappe.get_list("Student Group Student", fields=["student", "student_name"] ,
+ filters={"parent": student_group, "active": 1}, order_by= "group_roll_number")
return students
@frappe.whitelist()
diff --git a/erpnext/schools/doctype/assessment_plan/assessment_plan.py b/erpnext/schools/doctype/assessment_plan/assessment_plan.py
index f988886..a09f3ee 100644
--- a/erpnext/schools/doctype/assessment_plan/assessment_plan.py
+++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.py
@@ -11,6 +11,7 @@
def validate(self):
self.validate_overlap()
self.validate_max_score()
+ self.validate_assessment_criteria()
def validate_overlap(self):
"""Validates overlap for Student Group, Instructor, Room"""
@@ -37,3 +38,13 @@
max_score += d.maximum_score
if self.maximum_assessment_score != max_score:
frappe.throw(_("Sum of Scores of Assessment Criteria needs to be {0}.".format(self.maximum_assessment_score)))
+
+ def validate_assessment_criteria(self):
+ assessment_criteria_list = frappe.db.sql_list(''' select apc.assessment_criteria
+ from `tabAssessment Plan` ap , `tabAssessment Plan Criteria` apc
+ where ap.name = apc.parent and ap.course=%s and ap.student_group=%s and ap.assessment_group=%s
+ and ap.name != %s''', (self.course, self.student_group, self.assessment_group, self.name))
+ for d in self.assessment_criteria:
+ if d.assessment_criteria in assessment_criteria_list:
+ frappe.throw(_("You have already assessed for the assessment criteria {}.")
+ .format(frappe.bold(d.assessment_criteria)))
diff --git a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js
index 93c83f3..c5ff917 100644
--- a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js
+++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js
@@ -135,22 +135,24 @@
frappe.confirm(__("Do you want to update attendance?<br>Present: {0}\
<br>Absent: {1}", [students_present.length, students_absent.length]),
function() { //ifyes
- frappe.call({
- method: "erpnext.schools.api.mark_attendance",
- freeze: true,
- freeze_message: "Marking attendance",
- args: {
- "students_present": students_present,
- "students_absent": students_absent,
- "student_group": frm.doc.student_group,
- "course_schedule": frm.doc.course_schedule,
- "date": frm.doc.date
- },
- callback: function(r) {
- $(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
- frm.trigger("student_group");
- }
- });
+ if(!frappe.request.ajax_count) {
+ frappe.call({
+ method: "erpnext.schools.api.mark_attendance",
+ freeze: true,
+ freeze_message: "Marking attendance",
+ args: {
+ "students_present": students_present,
+ "students_absent": students_absent,
+ "student_group": frm.doc.student_group,
+ "course_schedule": frm.doc.course_schedule,
+ "date": frm.doc.date
+ },
+ callback: function(r) {
+ $(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
+ frm.trigger("student_group");
+ }
+ });
+ }
},
function() { //ifno
$(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
diff --git a/erpnext/schools/doctype/student_log/student_log.json b/erpnext/schools/doctype/student_log/student_log.json
index 43ac134..6c9d4b0 100644
--- a/erpnext/schools/doctype/student_log/student_log.json
+++ b/erpnext/schools/doctype/student_log/student_log.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "SLog.####",
@@ -13,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -43,64 +45,7 @@
"unique": 0
},
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "type",
- "fieldtype": "Select",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 1,
- "label": "Type",
- "length": 0,
- "no_copy": 0,
- "options": "General\nAcademic\nMedical\nAchievement",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "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,
- "unique": 0
- },
- {
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -131,6 +76,38 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "type",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "General\nAcademic\nMedical\nAchievement",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -160,6 +137,160 @@
"unique": 0
},
{
+ "allow_bulk_edit": 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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "academic_year",
+ "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": "Academic Year",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Academic Year",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "academic_term",
+ "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": "Academic Term",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Academic Term",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "program",
+ "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": "Program",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Program",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "student_batch",
+ "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": "Student Batch",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student Batch Name",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -188,6 +319,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -217,17 +349,17 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-02-17 17:18:19.596892",
+ "modified": "2017-07-06 12:42:05.777673",
"modified_by": "Administrator",
"module": "Schools",
"name": "Student Log",
diff --git a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
index 1e79a93..d869cec 100644
--- a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
+++ b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
@@ -15,19 +15,24 @@
to_date = get_last_day(filters["month"] + '-' + filters["year"])
total_days_in_month = date_diff(to_date, from_date) +1
columns = get_columns(total_days_in_month)
- students = get_student_group_students(filters.get("student_group"))
+ students = get_student_group_students(filters.get("student_group"),1)
students_list = get_students_list(students)
att_map = get_attendance_list(from_date, to_date, filters.get("student_group"), students_list)
data = []
for stud in students:
row = [stud.student, stud.student_name]
+ student_status = frappe.db.get_value("Student", stud.student, "enabled")
date = from_date
total_p = total_a = 0.0
for day in range(total_days_in_month):
status="None"
if att_map.get(stud.student):
status = att_map.get(stud.student).get(date, "None")
- status_map = {"Present": "P", "Absent": "A", "None": ""}
+ elif not student_status:
+ status = "Inactive"
+ else:
+ status = "None"
+ status_map = {"Present": "P", "Absent": "A", "None": "", "Inactive":"-"}
row.append(status_map[status])
if status == "Present":
total_p += 1
diff --git a/erpnext/selling/doctype/installation_note/installation_note.js b/erpnext/selling/doctype/installation_note/installation_note.js
index ab35574..9f0c050 100644
--- a/erpnext/selling/doctype/installation_note/installation_note.js
+++ b/erpnext/selling/doctype/installation_note/installation_note.js
@@ -30,12 +30,8 @@
setup_queries: function() {
var me = this;
- this.frm.set_query("customer_address", function() {
- return {
- filters: {'customer': me.frm.doc.customer }
- }
- });
-
+ frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
+ frm.set_query('customer_address', erpnext.queries.address_query);
this.frm.set_query('contact_person', erpnext.queries.contact_query);
this.frm.set_query("customer", function() {
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 9c2a400..92f4c2f 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -56,7 +56,7 @@
def validate_name_with_item(self):
if frappe.db.exists("Item", self.name):
- frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name))
+ frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name), frappe.NameError)
def get_context(self, context):
context.show_search=True
@@ -69,7 +69,7 @@
context.update({
"items": get_product_list_for_group(product_group = self.name, start=start,
limit=context.page_length + 1, search=frappe.form_dict.get("search")),
- "parent_groups": get_parent_item_groups(self.name),
+ "parents": get_parent_item_groups(self.parent_item_group),
"title": self.name,
"products_as_list": cint(frappe.db.get_single_value('Website Settings', 'products_as_list'))
})
@@ -136,7 +136,8 @@
def get_parent_item_groups(item_group_name):
item_group = frappe.get_doc("Item Group", item_group_name)
- return frappe.db.sql("""select name, route from `tabItem Group`
+ return [{"name": frappe._("Home"),"route":"/"}]+\
+ frappe.db.sql("""select name, route from `tabItem Group`
where lft <= %s and rgt >= %s
and show_in_website=1
order by lft asc""", (item_group.lft, item_group.rgt), as_dict=True)
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index 5c7697e..5134ee1 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -36,7 +36,7 @@
create_customers(args)
create_suppliers(args)
- if args.domain.lower() == 'education':
+ if args.get('domain').lower() == 'education':
create_academic_year()
create_academic_term()
create_program(args)
@@ -73,10 +73,10 @@
if (args.get('fy_start_date')):
curr_fiscal_year = get_fy_details(args.get('fy_start_date'), args.get('fy_end_date'))
frappe.get_doc({
- "doctype":"Fiscal Year",
- 'year': curr_fiscal_year,
- 'year_start_date': args.get('fy_start_date'),
- 'year_end_date': args.get('fy_end_date'),
+ "doctype":"Fiscal Year",
+ 'year': curr_fiscal_year,
+ 'year_start_date': args.get('fy_start_date'),
+ 'year_end_date': args.get('fy_end_date'),
}).insert()
args["curr_fiscal_year"] = curr_fiscal_year
@@ -150,7 +150,7 @@
global_defaults = frappe.get_doc("Global Defaults", "Global Defaults")
global_defaults.update({
- 'current_fiscal_year': args.curr_fiscal_year,
+ 'current_fiscal_year': args.get('curr_fiscal_year'),
'default_currency': args.get('currency'),
'default_company':args.get('company_name') ,
"country": args.get("country"),
@@ -196,7 +196,7 @@
hr_settings.save()
domain_settings = frappe.get_doc("Domain Settings")
- domain_settings.append('active_domains', dict(domain=_(args.domain)))
+ domain_settings.append('active_domains', dict(domain=_(args.get('domain'))))
domain_settings.save()
def create_feed_and_todo():
@@ -351,7 +351,7 @@
for i in xrange(1,6):
item = args.get("item_" + str(i))
if item:
- item_group = args.get("item_group_" + str(i))
+ item_group = _(args.get("item_group_" + str(i)))
is_sales_item = args.get("is_sales_item_" + str(i))
is_purchase_item = args.get("is_purchase_item_" + str(i))
is_stock_item = item_group!=_("Services")
@@ -373,7 +373,7 @@
"is_purchase_item": is_purchase_item,
"is_stock_item": is_stock_item and 1 or 0,
"item_group": item_group,
- "stock_uom": args.get("item_uom_" + str(i)),
+ "stock_uom": _(args.get("item_uom_" + str(i))),
"default_warehouse": default_warehouse
}).insert()
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index 71734f2..93dad16 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -93,4 +93,4 @@
return flt(value)
except:
frappe.msgprint(_("Unable to find exchange rate for {0} to {1} for key date {2}. Please create a Currency Exchange record manually").format(from_currency, to_currency, transaction_date))
- return 0.0
\ No newline at end of file
+ return 0.0
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index 75510de..9b49b69 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
import frappe
-from frappe import _
from frappe.utils import flt, nowdate
import frappe.defaults
from frappe.model.document import Document
@@ -15,7 +14,6 @@
self.validate_mandatory()
self.set_projected_qty()
- self.block_transactions_against_group_warehouse()
def on_update(self):
update_item_projected_qty(self.item_code)
@@ -26,10 +24,6 @@
if (not getattr(self, f, None)) or (not self.get(f)):
self.set(f, 0.0)
- def block_transactions_against_group_warehouse(self):
- from erpnext.stock.utils import is_group_warehouse
- is_group_warehouse(self.warehouse)
-
def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False):
'''Called from erpnext.stock.utils.update_bin'''
self.update_qty(args)
@@ -91,7 +85,8 @@
item.item_code = %s
and item.parent = pro.name
and pro.docstatus = 1
- and pro.source_warehouse = %s''', (self.item_code, self.warehouse))[0][0]
+ and item.source_warehouse = %s
+ and pro.status not in ("Stopped", "Completed")''', (self.item_code, self.warehouse))[0][0]
self.set_projected_qty()
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 19d3f47..b168631 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -1138,7 +1138,7 @@
"in_standard_filter": 0,
"label": "Has Batch No",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"oldfieldname": "has_batch_no",
"oldfieldtype": "Select",
"options": "",
@@ -1234,7 +1234,7 @@
"in_standard_filter": 0,
"label": "Has Serial No",
"length": 0,
- "no_copy": 0,
+ "no_copy": 1,
"oldfieldname": "has_serial_no",
"oldfieldtype": "Select",
"options": "",
@@ -3143,7 +3143,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
- "modified": "2017-06-13 14:29:03.003680",
+ "modified": "2017-07-06 18:28:36.645217",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
@@ -3320,4 +3320,4 @@
"title_field": "item_name",
"track_changes": 1,
"track_seen": 0
-}
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 9328194..2c6aab5 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -146,10 +146,6 @@
return cstr(frappe.db.get_value('Item Group', self.item_group,
'route')) + '/' + self.scrub(self.item_name + '-' + random_string(5))
- def get_parents(self, context):
- item_group, route = frappe.db.get_value('Item Group', self.item_group, ['name', 'route'])
- context.parents = [{'name': route, 'label': item_group}]
-
def validate_website_image(self):
"""Validate if the website image is a public file"""
auto_set_website_image = False
@@ -242,15 +238,12 @@
context.show_search=True
context.search_link = '/product_search'
- context.parent_groups = get_parent_item_groups(self.item_group) + \
- [{"name": self.name}]
+ context.parents = get_parent_item_groups(self.item_group)
self.set_variant_context(context)
self.set_attribute_context(context)
self.set_disabled_attributes(context)
- self.get_parents(context)
-
return context
def set_variant_context(self, context):
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index b74be39..7c7e630 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -708,13 +708,11 @@
issue (item quantity) that is pending to issue or desire to transfer,
whichever is less
"""
- item_dict = self.get_bom_raw_materials(1)
- issued_item_qty = self.get_issued_qty()
-
+ item_dict = self.get_pro_order_required_items()
max_qty = flt(self.pro_doc.qty)
- for item in item_dict:
- pending_to_issue = (max_qty * item_dict[item]["qty"]) - issued_item_qty.get(item, 0)
- desire_to_transfer = flt(self.fg_completed_qty) * item_dict[item]["qty"]
+ for item, item_details in item_dict.items():
+ pending_to_issue = flt(item_details.required_qty) - flt(item_details.transferred_qty)
+ desire_to_transfer = flt(self.fg_completed_qty) * flt(item_details.required_qty) / max_qty
if desire_to_transfer <= pending_to_issue:
item_dict[item]["qty"] = desire_to_transfer
@@ -734,34 +732,43 @@
return item_dict
- def get_issued_qty(self):
- issued_item_qty = {}
- result = frappe.db.sql("""select t1.item_code, sum(t1.qty)
- from `tabStock Entry Detail` t1, `tabStock Entry` t2
- where t1.parent = t2.name and t2.production_order = %s and t2.docstatus = 1
- and t2.purpose = 'Material Transfer for Manufacture'
- group by t1.item_code""", self.production_order)
- for t in result:
- issued_item_qty[t[0]] = flt(t[1])
-
- return issued_item_qty
+ def get_pro_order_required_items(self):
+ item_dict = frappe._dict()
+ pro_order = frappe.get_doc("Production Order", self.production_order)
+ if not frappe.db.get_value("Warehouse", pro_order.wip_warehouse, "is_group"):
+ wip_warehouse = pro_order.wip_warehouse
+ else:
+ wip_warehouse = None
+
+ for d in pro_order.get("required_items"):
+ if flt(d.required_qty) > flt(d.transferred_qty):
+ 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
+
+ item_row["to_warehouse"] = wip_warehouse
+ item_dict.setdefault(d.item_code, item_row)
+
+ return item_dict
def add_to_stock_entry_detail(self, item_dict, bom_no=None):
expense_account, cost_center = frappe.db.get_values("Company", self.company, \
["default_expense_account", "cost_center"])[0]
-
+
for d in item_dict:
+ stock_uom = item_dict[d].get("stock_uom") or frappe.db.get_value("Item", d, "stock_uom")
+
se_child = self.append('items')
se_child.s_warehouse = item_dict[d].get("from_warehouse")
se_child.t_warehouse = item_dict[d].get("to_warehouse")
se_child.item_code = cstr(d)
se_child.item_name = item_dict[d]["item_name"]
se_child.description = item_dict[d]["description"]
- se_child.uom = item_dict[d]["stock_uom"]
- se_child.stock_uom = item_dict[d]["stock_uom"]
+ se_child.uom = stock_uom
+ se_child.stock_uom = stock_uom
se_child.qty = flt(item_dict[d]["qty"])
- se_child.expense_account = item_dict[d]["expense_account"] or expense_account
- se_child.cost_center = item_dict[d]["cost_center"] or cost_center
+ se_child.expense_account = item_dict[d].get("expense_account") or expense_account
+ se_child.cost_center = item_dict[d].get("cost_center") or cost_center
if se_child.s_warehouse==None:
se_child.s_warehouse = self.from_warehouse
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index a9d0522..403d5cb 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -132,7 +132,7 @@
def get_planned_qty(item_code, warehouse):
planned_qty = frappe.db.sql("""
select sum(qty - produced_qty) from `tabProduction Order`
- where production_item = %s and fg_warehouse = %s and status != "Stopped"
+ where production_item = %s and fg_warehouse = %s and status not in ("Stopped", "Completed")
and docstatus=1 and qty > produced_qty""", (item_code, warehouse))
return flt(planned_qty[0][0]) if planned_qty else 0
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 2b9def3..01a18b9 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -41,7 +41,8 @@
sle_map = {}
for sle in stock_ledger_entries:
- sle_map[sle.item_code] = sle_map.get(sle.item_code, 0.0) + flt(sle.stock_value)
+ if not sle_map.has_key((sle.item_code, sle.warehouse)):
+ sle_map[(sle.item_code, sle.warehouse)] = flt(sle.stock_value)
return sum(sle_map.values())
@@ -67,6 +68,28 @@
else:
return last_entry.qty_after_transaction if last_entry else 0.0
+@frappe.whitelist()
+def get_latest_stock_qty(item_code, warehouse=None):
+ values, condition = [item_code], ""
+ if warehouse:
+ lft, rgt, is_group = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt", "is_group"])
+
+ if is_group:
+ values.extend([lft, rgt])
+ condition += "and exists (\
+ select name from `tabWarehouse` wh where wh.name = tabBin.warehouse\
+ and wh.lft >= %s and wh.rgt <= %s)"
+
+ else:
+ values.append(warehouse)
+ condition += " AND warehouse = %s"
+
+ actual_qty = frappe.db.sql("""select sum(actual_qty) from tabBin
+ where item_code=%s {0}""".format(condition), values)[0][0]
+
+ return actual_qty
+
+
def get_latest_stock_balance():
bin_map = {}
for d in frappe.db.sql("""SELECT item_code, warehouse, stock_value as stock_value
diff --git a/erpnext/templates/pages/rfq.py b/erpnext/templates/pages/rfq.py
index abc2890..aaf4110 100644
--- a/erpnext/templates/pages/rfq.py
+++ b/erpnext/templates/pages/rfq.py
@@ -29,7 +29,7 @@
def check_supplier_has_docname_access(supplier):
status = True
if frappe.form_dict.name not in frappe.db.sql_list("""select parent from `tabRequest for Quotation Supplier`
- where supplier = '{supplier}'""".format(supplier=supplier)):
+ where supplier = %s""", (supplier,)):
status = False
return status