Merge pull request #9489 from rohitwaghchaure/billed_amt_issue_in_pr
[fix] Billed Amt does not get updated in Purchase Receipt, if Invoice exists and item has been returned once before
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 36bf1bf..71323d1 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
import frappe
-__version__ = '8.1.3'
+__version__ = '8.2.2'
def get_default_company(user=None):
diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py
index 11dcfe7..0aaed8f 100644
--- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py
+++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py
@@ -62,13 +62,13 @@
for d in entries:
row = self.append('payment_entries', {})
-
- d.amount = fmt_money(d.debit if d.debit else d.credit, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
+ amount = d.debit if d.debit else d.credit
+ d.amount = fmt_money(amount, 2, d.account_currency) + " " + (_("Dr") if d.debit else _("Cr"))
d.pop("credit")
d.pop("debit")
d.pop("account_currency")
row.update(d)
- self.total_amount += flt(d.amount)
+ self.total_amount += flt(amount)
def update_clearance_date(self):
clearance_date_updated = False
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index ad5ecc1..ac5f5dd 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -224,9 +224,9 @@
return {
filters: [
["Account", "account_type", "in", ["Cash", "Bank"]],
- ["Account", "root_type", "=", "Asset"],
["Account", "is_group", "=",0],
- ["Account", "company", "=", doc.company]
+ ["Account", "company", "=", doc.company],
+ ["Account", "report_type", "=", "Balance Sheet"]
]
}
}
diff --git a/erpnext/buying/doctype/supplier/regional/india.js b/erpnext/buying/doctype/supplier/regional/india.js
new file mode 100644
index 0000000..bd710e0
--- /dev/null
+++ b/erpnext/buying/doctype/supplier/regional/india.js
@@ -0,0 +1,3 @@
+{% include "erpnext/regional/india/party.js" %}
+
+erpnext.setup_gst_reminder_button('Supplier');
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier/supplier_list.js b/erpnext/buying/doctype/supplier/supplier_list.js
index dd98c43..ab25d2c 100644
--- a/erpnext/buying/doctype/supplier/supplier_list.js
+++ b/erpnext/buying/doctype/supplier/supplier_list.js
@@ -1,3 +1,3 @@
frappe.listview_settings['Supplier'] = {
- add_fields: ["supplier_name", "supplier_type"],
+ add_fields: ["supplier_name", "supplier_type", "image"],
};
diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py
index a17679e..6d16e92 100644
--- a/erpnext/config/accounts.py
+++ b/erpnext/config/accounts.py
@@ -203,6 +203,10 @@
"items": [
{
"type": "doctype",
+ "name": "GST Settings",
+ },
+ {
+ "type": "doctype",
"name": "GST HSN Code",
},
{
diff --git a/erpnext/config/schools.py b/erpnext/config/schools.py
index c54f808..b984578 100644
--- a/erpnext/config/schools.py
+++ b/erpnext/config/schools.py
@@ -137,7 +137,14 @@
{
"type": "doctype",
"name": "Assessment Result Tool"
- }
+ },
+ {
+ "type": "report",
+ "is_query_report": True,
+ "name": "Course wise Assessment Report",
+ "doctype": "Assessment Result"
+ },
+
]
},
{
diff --git a/erpnext/config/support.py b/erpnext/config/support.py
index c1f56f0..b85c430 100644
--- a/erpnext/config/support.py
+++ b/erpnext/config/support.py
@@ -49,6 +49,12 @@
"doctype": "Issue",
"is_query_report": True
},
+ {
+ "type": "report",
+ "name": "Support Hours",
+ "doctype": "Issue",
+ "is_query_report": True
+ },
]
},
]
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 553c7b3..9ccf7f4 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -255,7 +255,7 @@
def get_items_from_bom(self, item_code, bom):
bom_items = frappe.db.sql("""select t2.item_code,
- t2.qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
+ t2.stock_qty / ifnull(t1.quantity, 1) as qty_consumed_per_unit,
t2.rate, t2.stock_uom, t2.name, t2.description
from `tabBOM` t1, `tabBOM Item` t2, tabItem t3
where t2.parent = t1.name and t1.item = %s
diff --git a/erpnext/docs/assets/img/regional/india/gst-settings.png b/erpnext/docs/assets/img/regional/india/gst-settings.png
new file mode 100644
index 0000000..c7f59ad
--- /dev/null
+++ b/erpnext/docs/assets/img/regional/india/gst-settings.png
Binary files differ
diff --git a/erpnext/docs/assets/img/regional/india/gstin-portal-update.png b/erpnext/docs/assets/img/regional/india/gstin-portal-update.png
new file mode 100644
index 0000000..28302c8
--- /dev/null
+++ b/erpnext/docs/assets/img/regional/india/gstin-portal-update.png
Binary files differ
diff --git a/erpnext/docs/assets/img/regional/india/gstin-reminder-email.png b/erpnext/docs/assets/img/regional/india/gstin-reminder-email.png
new file mode 100644
index 0000000..97bcd24
--- /dev/null
+++ b/erpnext/docs/assets/img/regional/india/gstin-reminder-email.png
Binary files differ
diff --git a/erpnext/docs/assets/img/support/support_hours.png b/erpnext/docs/assets/img/support/support_hours.png
new file mode 100644
index 0000000..44cfbbb
--- /dev/null
+++ b/erpnext/docs/assets/img/support/support_hours.png
Binary files differ
diff --git a/erpnext/docs/user/manual/en/regional/india/gst-remimders.md b/erpnext/docs/user/manual/en/regional/india/gst-remimders.md
new file mode 100644
index 0000000..97f016d
--- /dev/null
+++ b/erpnext/docs/user/manual/en/regional/india/gst-remimders.md
@@ -0,0 +1,21 @@
+# Sending GST Reminders
+
+You can send email reminders to your Customers and Suppliers so that they can directly add or update their GSTIN numbers
+
+To send GSTIN Reminders, you can either open the Customer / Supplier record or **GST Settings**
+
+<img class="screenshot" alt="GST Settings" src="{{docs_base_url}}/assets/img/regional/india/gst-settings.png">
+
+Here you can click on the "Send GSTIN Update Reminders" button to send email reminders to all your customers
+
+### Updating GSTIN
+
+Your customers will receive an email asking them to update their GSTIN and that email will link them to a portal page:
+
+<img class="screenshot" alt="GST Portal Page" src="{{docs_base_url}}/assets/img/regional/india/gstin-portal-update.png">
+
+Here they can update their GSTIN and it will automatically be added to your customer GSTIN record.
+
+#### Sample GSTIN Reminder Email
+
+<img class="screenshot" alt="GST Reminder Email" src="{{docs_base_url}}/assets/img/regional/india/gstin-reminder-email.png">
diff --git a/erpnext/docs/user/manual/en/regional/india/gst-setup.md b/erpnext/docs/user/manual/en/regional/india/gst-setup.md
new file mode 100644
index 0000000..48e5066
--- /dev/null
+++ b/erpnext/docs/user/manual/en/regional/india/gst-setup.md
@@ -0,0 +1,67 @@
+# GST Features in ERPNext
+
+### 1. Setting up GSTIN
+
+GST Law requires that you maintain the GSTIN number for all your suppliers and vendors. In ERPNext, GSTIN is linked to the **Address**
+
+<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gstin-customer.gif">
+
+**GST for your Company Address**
+
+You also need to set the Address for your own Company and your Company's GST Number
+
+Go to the Company master and add the GSTIN to your default address.
+
+<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/gstin-company.gif">
+
+### 2. Setting up HSN Codes
+
+According to the GST Law, your itemised invoices must contain the HSN Code related to that Item. ERPNext comes pre-installed with all 12,000+ HSN Codes so that you can easily select the relevant HSN Code in your Item
+
+<img class="screenshot" alt="HSN in Item" src="{{docs_base_url}}/assets/img/regional/india/hsn-item.gif">
+
+### 3. Making Tax Masters
+
+To setup Billing in GST, you need to create 3 Tax Accounts for the various GST reporting heads CGST - Central GST, SGST - State GST, IGST - Inter-state GST
+
+Go to your **Chart of Accounts**, under the Duties and Taxes head of your account, create 3 Accounts
+
+**Note:** Usually the rate in CGST and SGST is half of IGST. For example if most of your items are billed at 18%, then create IGST at 18%, CGST and SGST at 9% each.
+
+<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-in-coa.png">
+
+### 4. Make Tax Templates
+
+You will have have to make two tax templates for both your sales and purchase, one for in state sales and other for out of state sales.
+
+In your **In State GST** template, select 2 accounts, SGST and CGST
+
+<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-template-in-state.png">
+
+In your **Out of State GST** template, select IGST
+
+### 5. Making GST Ready Invoices
+
+If you have setup the GSTIN of your Customers and Suppliers, and your tax template, you are ready to go for making GST Ready Invoices!
+
+For **Sales Invoice**,
+
+1. Select the correct Customer and Item and the address where the transaction will happen.
+2. Check if the GSTIN of your Company and Supplier have been correctly set.
+3. Check if the HSN Number has been set in the Item
+4. Select the the **In State GST** or **Out of State GST** template that you have created based on the type of transaction
+5. Save and Submit the Invoice
+
+<img class="screenshot" alt="GST Invoice" src="{{docs_base_url}}/assets/img/regional/india/gst-invoice.gif">
+
+### Reports
+
+ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list.
+
+<img class="screenshot" alt="GST Menus" src="{{docs_base_url}}/assets/img/regional/india/gst-menu.png">
+
+You can check the impact of your invoice in the **GST Sales Register** and **GST Itemised Sales Register**
+
+<img class="screenshot" alt="GST Itemised Sales Register" src="{{docs_base_url}}/assets/img/regional/india/gst-itemised.png">
+
+
diff --git a/erpnext/docs/user/manual/en/regional/india/index.md b/erpnext/docs/user/manual/en/regional/india/index.md
index 1642207..4207a2f 100644
--- a/erpnext/docs/user/manual/en/regional/india/index.md
+++ b/erpnext/docs/user/manual/en/regional/india/index.md
@@ -2,70 +2,4 @@
As of 2017, India will fall under the new GST (Goods and Services Tax) regime and ERPNext makes it easy for users to track the details of its Supplier and Customers across Invoices and make the required reports.
-## GST Features in ERPNext
-
-### 1. Setting up GSTIN
-
-GST Law requires that you maintain the GSTIN number for all your suppliers and vendors. In ERPNext, GSTIN is linked to the **Address**
-
-<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gstin-customer.gif">
-
-**GST for your Company Address**
-
-You also need to set the Address for your own Company and your Company's GST Number
-
-Go to the Company master and add the GSTIN to your default address.
-
-<img class="screenshot" alt="GST in Company" src="{{docs_base_url}}/assets/img/regional/india/gstin-company.gif">
-
-### 2. Setting up HSN Codes
-
-According to the GST Law, your itemised invoices must contain the HSN Code related to that Item. ERPNext comes pre-installed with all 12,000+ HSN Codes so that you can easily select the relevant HSN Code in your Item
-
-<img class="screenshot" alt="HSN in Item" src="{{docs_base_url}}/assets/img/regional/india/hsn-item.gif">
-
-### 3. Making Tax Masters
-
-To setup Billing in GST, you need to create 3 Tax Accounts for the various GST reporting heads CGST - Central GST, SGST - State GST, IGST - Inter-state GST
-
-Go to your **Chart of Accounts**, under the Duties and Taxes head of your account, create 3 Accounts
-
-**Note:** Usually the rate in CGST and SGST is half of IGST. For example if most of your items are billed at 18%, then create IGST at 18%, CGST and SGST at 9% each.
-
-<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-in-coa.png">
-
-### 4. Make Tax Templates
-
-You will have have to make two tax templates for both your sales and purchase, one for in state sales and other for out of state sales.
-
-In your **In State GST** template, select 2 accounts, SGST and CGST
-
-<img class="screenshot" alt="GST in Customer" src="{{docs_base_url}}/assets/img/regional/india/gst-template-in-state.png">
-
-In your **Out of State GST** template, select IGST
-
-### 5. Making GST Ready Invoices
-
-If you have setup the GSTIN of your Customers and Suppliers, and your tax template, you are ready to go for making GST Ready Invoices!
-
-For **Sales Invoice**,
-
-1. Select the correct Customer and Item and the address where the transaction will happen.
-2. Check if the GSTIN of your Company and Supplier have been correctly set.
-3. Check if the HSN Number has been set in the Item
-4. Select the the **In State GST** or **Out of State GST** template that you have created based on the type of transaction
-5. Save and Submit the Invoice
-
-<img class="screenshot" alt="GST Invoice" src="{{docs_base_url}}/assets/img/regional/india/gst-invoice.gif">
-
-### Reports
-
-ERPNext comes with most of your reports you need to prepare your GST Returns. Go to Accounts > GST India head for the list.
-
-<img class="screenshot" alt="GST Menus" src="{{docs_base_url}}/assets/img/regional/india/gst-menu.png">
-
-You can check the impact of your invoice in the **GST Sales Register** and **GST Itemised Sales Register**
-
-<img class="screenshot" alt="GST Itemised Sales Register" src="{{docs_base_url}}/assets/img/regional/india/gst-itemised.png">
-
-
+{index}
\ No newline at end of file
diff --git a/erpnext/docs/user/manual/en/regional/india/index.txt b/erpnext/docs/user/manual/en/regional/india/index.txt
new file mode 100644
index 0000000..8d72c56
--- /dev/null
+++ b/erpnext/docs/user/manual/en/regional/india/index.txt
@@ -0,0 +1,2 @@
+gst-setup
+gst-reminders
\ No newline at end of file
diff --git a/erpnext/docs/user/manual/en/support/support_reports.md b/erpnext/docs/user/manual/en/support/support_reports.md
new file mode 100644
index 0000000..2be72e1
--- /dev/null
+++ b/erpnext/docs/user/manual/en/support/support_reports.md
@@ -0,0 +1,8 @@
+
+
+### Support Hours
+This report provide the information about the time slot along with the count of issues has been reported during the slot daywise.
+
+> Support > Reports > Support Hours
+
+<img class="screenshot" alt="Maintenance Visit" src="{{docs_base_url}}/assets/img/support/support_hours.png">
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 83e0950..87dd565 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -5,7 +5,7 @@
frappe.ui.form.on("BOM", {
setup: function(frm) {
- frm.add_fetch('buying_price_list', 'currency', 'currency')
+ frm.add_fetch('buying_price_list', 'currency', 'currency');
frm.fields_dict["items"].grid.get_field("bom_no").get_query = function(doc, cdt, cdn){
return {
filters: {'currency': frm.doc.currency}
@@ -74,6 +74,15 @@
get_bom_material_detail(doc, cdt, cdn, scrap_items);
},
+ conversion_factor: function(doc, cdt, cdn, dont_fetch_price_list_rate) {
+ if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
+ var item = frappe.get_doc(cdt, cdn);
+ frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
+ item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item));
+ refresh_field("stock_qty", item.name, item.parentfield);
+ this.toggle_conversion_factor(item);
+ }
+ },
})
$.extend(cur_frm.cscript, new erpnext.bom.BomController({frm: cur_frm}));
@@ -300,6 +309,13 @@
})
});
+frappe.ui.form.on("BOM Item", "qty", function(frm, cdt, cdn) {
+ var d = locals[cdt][cdn];
+ d.stock_qty = d.qty * d.conversion_factor;
+ refresh_field("items");
+});
+
+
frappe.ui.form.on("BOM Operation", "operations_remove", function(frm) {
erpnext.bom.calculate_op_cost(frm.doc);
erpnext.bom.calculate_total(frm.doc);
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index bbfdc9a..41eec8d 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -7,6 +7,7 @@
from frappe import _
from erpnext.setup.utils import get_exchange_rate
from frappe.website.website_generator import WebsiteGenerator
+from erpnext.stock.get_item_details import get_conversion_factor
from operator import itemgetter
@@ -48,7 +49,7 @@
self.set_conversion_rate()
from erpnext.utilities.transaction_base import validate_uom_is_integer
- validate_uom_is_integer(self, "stock_uom", "qty", "BOM Item")
+ validate_uom_is_integer(self, "stock_uom", "stock_qty", "BOM Item")
self.validate_materials()
self.set_bom_material_details()
@@ -60,6 +61,7 @@
def on_update(self):
self.check_recursion()
+ self.update_stock_qty()
self.update_exploded_items()
def on_submit(self):
@@ -94,7 +96,7 @@
def set_bom_material_details(self):
for item in self.get("items"):
ret = self.get_bom_material_detail({"item_code": item.item_code, "item_name": item.item_name, "bom_no": item.bom_no,
- "qty": item.qty})
+ "stock_qty": item.stock_qty})
for r in ret:
if not item.get(r):
item.set(r, ret[r])
@@ -122,8 +124,11 @@
'description' : item and args['description'] or '',
'image' : item and args['image'] or '',
'stock_uom' : item and args['stock_uom'] or '',
+ 'uom' : item and args['stock_uom'] or '',
+ 'conversion_factor' : 1,
'bom_no' : args['bom_no'],
'rate' : rate,
+ 'stock_qty' : args.get("qty") or args.get("stock_qty") or 1,
'base_rate' : rate if self.company_currency() == self.currency else rate * self.conversion_rate
}
return ret_item
@@ -160,7 +165,7 @@
for d in self.get("items"):
rate = self.get_bom_material_detail({'item_code': d.item_code, 'bom_no': d.bom_no,
- 'qty': d.qty})["rate"]
+ 'stock_qty': d.stock_qty})["rate"]
if rate:
d.rate = rate
@@ -240,6 +245,19 @@
frappe.db.get_value('Price List', self.buying_price_list, 'currency') != self.currency:
frappe.throw(_("Currency of the price list {0} is not similar with the selected currency {1}").format(self.buying_price_list, self.currency))
+
+ def update_stock_qty(self):
+ for m in self.get('items'):
+
+ if not m.conversion_factor:
+ m.conversion_factor = flt(get_conversion_factor(m.item_code, m.uom)['conversion_factor'])
+ if m.uom and m.qty:
+ m.stock_qty = flt(m.conversion_factor)*flt(m.qty)
+ if not m.uom and m.stock_uom:
+ m.uom = m.stock_uom
+ m.qty = m.stock_qty
+
+
def set_conversion_rate(self):
self.conversion_rate = get_exchange_rate(self.currency, self.company_currency())
@@ -259,7 +277,7 @@
for m in self.get('items'):
if m.bom_no:
validate_bom_no(m.item_code, m.bom_no)
- if flt(m.qty) <= 0:
+ if flt(m.stock_qty) <= 0:
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
check_list.append(m)
@@ -351,9 +369,9 @@
d.rate = self.get_bom_unitcost(d.bom_no)
d.base_rate = flt(d.rate) * flt(self.conversion_rate)
- d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.qty, self.precision("qty", d))
+ d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.stock_qty, self.precision("stock_qty", d))
d.base_amount = d.amount * flt(self.conversion_rate)
- d.qty_consumed_per_unit = flt(d.qty, self.precision("qty", d)) / flt(self.quantity, self.precision("quantity"))
+ d.qty_consumed_per_unit = flt(d.stock_qty, self.precision("stock_qty", d)) / flt(self.quantity, self.precision("quantity"))
total_rm_cost += d.amount
base_total_rm_cost += d.base_amount
@@ -367,7 +385,7 @@
for d in self.get('scrap_items'):
d.base_rate = d.rate * self.conversion_rate
- d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.qty, self.precision("qty", d))
+ d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.stock_qty, self.precision("stock_qty", d))
d.base_amount = d.amount * self.conversion_rate
total_sm_cost += d.amount
base_total_sm_cost += d.base_amount
@@ -385,7 +403,7 @@
self.cur_exploded_items = {}
for d in self.get('items'):
if d.bom_no:
- self.get_child_exploded_items(d.bom_no, d.qty)
+ self.get_child_exploded_items(d.bom_no, d.stock_qty)
else:
self.add_to_cur_exploded_items(frappe._dict({
'item_code' : d.item_code,
@@ -393,7 +411,7 @@
'description' : d.description,
'image' : d.image,
'stock_uom' : d.stock_uom,
- 'qty' : flt(d.qty),
+ 'stock_qty' : flt(d.stock_qty),
'rate' : d.base_rate,
}))
@@ -402,16 +420,16 @@
def add_to_cur_exploded_items(self, args):
if self.cur_exploded_items.get(args.item_code):
- self.cur_exploded_items[args.item_code]["qty"] += args.qty
+ self.cur_exploded_items[args.item_code]["stock_qty"] += args.stock_qty
else:
self.cur_exploded_items[args.item_code] = args
- def get_child_exploded_items(self, bom_no, qty):
+ 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,
- bom_item.stock_uom, bom_item.qty, bom_item.rate,
- bom_item.qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
+ 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
where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1)
@@ -421,7 +439,7 @@
'item_name' : d['item_name'],
'description' : d['description'],
'stock_uom' : d['stock_uom'],
- 'qty' : d['qty_consumed_per_unit']*qty,
+ 'stock_qty' : d['qty_consumed_per_unit']*stock_qty,
'rate' : flt(d['rate']),
}))
@@ -433,8 +451,8 @@
ch = self.append('exploded_items', {})
for i in self.cur_exploded_items[d].keys():
ch.set(i, self.cur_exploded_items[d][i])
- ch.amount = flt(ch.qty) * flt(ch.rate)
- ch.qty_consumed_per_unit = flt(ch.qty) / flt(self.quantity)
+ ch.amount = flt(ch.stock_qty) * flt(ch.rate)
+ ch.qty_consumed_per_unit = flt(ch.stock_qty) / flt(self.quantity)
ch.docstatus = self.docstatus
ch.db_insert()
@@ -468,7 +486,7 @@
query = """select
bom_item.item_code,
item.item_name,
- sum(bom_item.qty/ifnull(bom.quantity, 1)) * %(qty)s as qty,
+ sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(qty)s as qty,
item.description,
item.image,
item.stock_uom,
@@ -478,13 +496,13 @@
from
`tab{table}` bom_item, `tabBOM` bom, `tabItem` item
where
- bom_item.parent = bom.name
- and bom_item.docstatus < 2
- and bom_item.parent = %(bom)s
+ bom_item.docstatus < 2
+ and bom.name = %(bom)s
+ 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"""
+ group by item_code, stock_uom"""
if fetch_exploded:
query = query.format(table="BOM Explosion Item",
@@ -536,7 +554,7 @@
return frappe.db.sql("""select
bom_item.item_code,
bom_item.bom_no as value,
- bom_item.qty,
+ bom_item.stock_qty,
if(ifnull(bom_item.bom_no, "")!="", 1, 0) as expandable,
item.image,
item.description
diff --git a/erpnext/manufacturing/doctype/bom/test_records.json b/erpnext/manufacturing/doctype/bom/test_records.json
index 5baa0cb..0f1143e 100644
--- a/erpnext/manufacturing/doctype/bom/test_records.json
+++ b/erpnext/manufacturing/doctype/bom/test_records.json
@@ -6,7 +6,7 @@
"doctype": "BOM Item",
"item_code": "_Test Serialized Item With Series",
"parentfield": "items",
- "qty": 1.0,
+ "stock_qty": 1.0,
"rate": 5000.0,
"stock_uom": "_Test UOM"
},
@@ -15,7 +15,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item 2",
"parentfield": "items",
- "qty": 2.0,
+ "stock_qty": 2.0,
"rate": 1000.0,
"stock_uom": "_Test UOM"
}
@@ -35,7 +35,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item Home Desktop 100",
"parentfield": "items",
- "qty": 1.0,
+ "stock_qty": 1.0,
"rate": 2000.0,
"stock_uom": "_Test UOM"
}
@@ -46,7 +46,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item",
"parentfield": "items",
- "qty": 1.0,
+ "stock_qty": 1.0,
"rate": 5000.0,
"stock_uom": "_Test UOM"
},
@@ -55,7 +55,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item Home Desktop 100",
"parentfield": "items",
- "qty": 2.0,
+ "stock_qty": 2.0,
"rate": 1000.0,
"stock_uom": "_Test UOM"
}
@@ -84,7 +84,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item",
"parentfield": "items",
- "qty": 1.0,
+ "stock_qty": 1.0,
"rate": 5000.0,
"stock_uom": "_Test UOM"
},
@@ -94,7 +94,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item Home Desktop Manufactured",
"parentfield": "items",
- "qty": 3.0,
+ "stock_qty": 3.0,
"rate": 1000.0,
"stock_uom": "_Test UOM"
}
@@ -124,7 +124,7 @@
"doctype": "BOM Item",
"item_code": "_Test Item",
"parentfield": "items",
- "qty": 2.0,
+ "stock_qty": 2.0,
"rate": 3000.0,
"stock_uom": "_Test UOM"
}
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 f075840..e1a3d4d 100644
--- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
+++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "hash",
@@ -13,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -44,6 +46,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -72,6 +75,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -101,6 +105,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -129,6 +134,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -161,6 +167,7 @@
"width": "300px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -189,6 +196,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -218,6 +226,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -248,6 +257,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -276,11 +286,12 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "qty",
+ "fieldname": "stock_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -289,7 +300,7 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
- "label": "Qty",
+ "label": "Stock Qty",
"length": 0,
"no_copy": 0,
"oldfieldname": "qty",
@@ -306,6 +317,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -337,6 +349,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -365,6 +378,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -393,6 +407,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -424,6 +439,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -455,17 +471,17 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2017-02-17 17:27:43.757983",
+ "modified": "2017-06-02 19:29:34.498719",
"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 2fc29a8..966b89b 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.json
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -11,6 +12,7 @@
"editable_grid": 1,
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -20,7 +22,8 @@
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
- "in_filter": 1,
+ "in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Item Code",
@@ -41,6 +44,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -51,6 +55,7 @@
"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",
@@ -69,6 +74,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -79,6 +85,7 @@
"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,
@@ -96,6 +103,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -105,7 +113,8 @@
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
- "in_filter": 1,
+ "in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "BOM No",
@@ -128,6 +137,7 @@
"width": "150px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -138,6 +148,7 @@
"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,
@@ -155,6 +166,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -165,6 +177,7 @@
"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 Description",
@@ -186,6 +199,7 @@
"width": "250px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -196,6 +210,7 @@
"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,
@@ -212,6 +227,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -222,6 +238,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Image",
@@ -240,6 +257,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -250,6 +268,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Image View",
@@ -269,6 +288,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -279,6 +299,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quantity and Rate",
@@ -296,6 +317,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -306,6 +328,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Qty",
@@ -319,16 +342,170 @@
"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": 1,
+ "fieldname": "uom",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "UOM",
+ "length": 0,
+ "no_copy": 0,
+ "options": "UOM",
+ "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": "col_break2",
+ "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": "stock_qty",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Stock Qty",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "stock_qty",
+ "oldfieldtype": "Currency",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "columns": 2,
+ "columns": 0,
+ "fieldname": "conversion_factor",
+ "fieldtype": "Float",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Conversion Factor",
+ "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": "stock_uom",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Stock UOM",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "stock_uom",
+ "oldfieldtype": "Data",
+ "options": "UOM",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"description": "See \"Rate Of Materials Based On\" in Costing Section",
"fieldname": "rate",
"fieldtype": "Currency",
@@ -336,7 +513,8 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
- "in_list_view": 1,
+ "in_global_search": 0,
+ "in_list_view": 0,
"in_standard_filter": 0,
"label": "Rate",
"length": 0,
@@ -354,6 +532,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -364,6 +543,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Amount",
@@ -386,62 +566,7 @@
"width": "150px"
},
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "col_break2",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "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": "stock_uom",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Stock UOM",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "stock_uom",
- "oldfieldtype": "Data",
- "options": "UOM",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -452,6 +577,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Basic Rate (Company Currency)",
@@ -471,6 +597,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -481,6 +608,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Amount (Company Currency)",
@@ -500,6 +628,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -510,6 +639,7 @@
"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,
@@ -527,6 +657,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -537,6 +668,7 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Scrap %",
@@ -556,6 +688,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -566,6 +699,7 @@
"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 Consumed Per Unit",
@@ -585,18 +719,18 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 1,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2016-12-20 12:54:34.859076",
- "modified_by": "rmehta@gmail.com",
+ "modified": "2017-05-23 15:59:37.946963",
+ "modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",
"owner": "Administrator",
@@ -604,7 +738,9 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
+ "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
+ "track_changes": 0,
"track_seen": 0
}
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/bom_replace_tool/bom_replace_tool.py b/erpnext/manufacturing/doctype/bom_replace_tool/bom_replace_tool.py
index d4d5329..f0a834c 100644
--- a/erpnext/manufacturing/doctype/bom_replace_tool/bom_replace_tool.py
+++ b/erpnext/manufacturing/doctype/bom_replace_tool/bom_replace_tool.py
@@ -33,7 +33,7 @@
from `tabBOM` where name = %s""", self.current_bom)
current_bom_unitcost = current_bom_unitcost and flt(current_bom_unitcost[0][0]) or 0
frappe.db.sql("""update `tabBOM Item` set bom_no=%s,
- rate=%s, amount=qty*%s where bom_no = %s and docstatus < 2""",
+ rate=%s, amount=stock_qty*%s where bom_no = %s and docstatus < 2""",
(self.new_bom, current_bom_unitcost, current_bom_unitcost, self.current_bom))
def get_parent_boms(self):
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 fe81592..e9aebfe 100644
--- a/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.json
+++ b/erpnext/manufacturing/doctype/bom_scrap_item/bom_scrap_item.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -11,6 +12,7 @@
"editable_grid": 1,
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -21,7 +23,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
@@ -31,6 +35,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -38,6 +43,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -48,7 +54,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Item Name",
"length": 0,
"no_copy": 0,
@@ -57,6 +65,7 @@
"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,
@@ -64,6 +73,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -74,7 +84,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Quantity and Rate",
"length": 0,
"no_copy": 0,
@@ -83,6 +95,7 @@
"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,
@@ -90,17 +103,20 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "qty",
+ "fieldname": "stock_qty",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Qty",
"length": 0,
"no_copy": 0,
@@ -109,6 +125,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -116,6 +133,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -126,7 +144,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Rate",
"length": 0,
"no_copy": 0,
@@ -136,6 +156,7 @@
"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,
@@ -143,6 +164,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -153,7 +175,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
@@ -163,6 +187,7 @@
"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,
@@ -170,6 +195,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -180,7 +206,9 @@
"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,
@@ -188,6 +216,7 @@
"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,
@@ -195,6 +224,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -205,7 +235,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Stock UOM",
"length": 0,
"no_copy": 0,
@@ -215,6 +247,7 @@
"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,
@@ -222,6 +255,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -232,7 +266,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Basic Rate (Company Currency)",
"length": 0,
"no_copy": 0,
@@ -242,6 +278,7 @@
"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,
@@ -249,6 +286,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -259,7 +297,9 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Basic Amount (Company Currency)",
"length": 0,
"no_copy": 0,
@@ -269,6 +309,7 @@
"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,
@@ -276,17 +317,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": 1,
"max_attachments": 0,
- "modified": "2016-10-25 00:27:53.712140",
+ "modified": "2017-05-23 16:04:32.442287",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Scrap Item",
@@ -296,7 +337,9 @@
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
+ "show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
+ "track_changes": 1,
"track_seen": 0
}
\ 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 40e8393..cdadba4 100644
--- a/erpnext/manufacturing/doctype/production_order/test_production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/test_production_order.py
@@ -266,9 +266,9 @@
def get_scrap_item_details(bom_no):
scrap_items = {}
- for item in frappe.db.sql("""select item_code, qty from `tabBOM Scrap Item`
+ for item in frappe.db.sql("""select item_code, stock_qty from `tabBOM Scrap Item`
where parent = %s""", bom_no, as_dict=1):
- scrap_items[item.item_code] = item.qty
+ scrap_items[item.item_code] = item.stock_qty
return scrap_items
@@ -287,8 +287,7 @@
pro_order.stock_uom = args.stock_uom or "_Test UOM"
pro_order.use_multi_level_bom=0
pro_order.set_production_order_operations()
-
-
+
if args.source_warehouse:
pro_order.source_warehouse = args.source_warehouse
@@ -297,6 +296,7 @@
if not args.do_not_save:
pro_order.insert()
+
if not args.do_not_submit:
pro_order.submit()
return pro_order
diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
index dd4b2b6..050c3c1 100644
--- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
+++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
@@ -321,7 +321,7 @@
# get all raw materials with sub assembly childs
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
for d in frappe.db.sql("""select fb.item_code,
- ifnull(sum(fb.qty/ifnull(bom.quantity, 1)), 0) as qty,
+ ifnull(sum(fb.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
fb.description, fb.stock_uom, item.min_order_qty
from `tabBOM Explosion Item` fb, `tabBOM` bom, `tabItem` item
where bom.name = fb.parent and item.name = fb.item_code
@@ -348,7 +348,7 @@
SELECT
bom_item.item_code,
default_material_request_type,
- ifnull(%(parent_qty)s * sum(bom_item.qty/ifnull(bom.quantity, 1)), 0) as qty,
+ ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
item.is_sub_contracted_item as is_sub_contracted,
item.default_bom as default_bom,
bom_item.description as description,
diff --git a/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py
index ea4da0c..4f80b6a 100644
--- a/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py
+++ b/erpnext/manufacturing/doctype/production_planning_tool/test_production_planning_tool.py
@@ -235,9 +235,9 @@
"is_active": 1,
"is_default": 1,
"docstatus": 1,
- "with_operations": 0}, [{"item_code": "_Test PPT Item Raw B", "doctype":"BOM Item", "qty":1,
+ "with_operations": 0}, [{"item_code": "_Test PPT Item Raw B", "doctype":"BOM Item", "stock_qty":1,
"rate":100, "amount": 100, "stock_uom": "_Test UOM"},
- {"item_code": "_Test PPT Item Raw C", "doctype":"BOM Item", "qty":4, "rate":100,
+ {"item_code": "_Test PPT Item Raw C", "doctype":"BOM Item", "stock_qty":4, "rate":100,
"amount": 400,"stock_uom": "_Test UOM"}])
bom_subC = make_bom("BOM-_Test PPT Item Sub C-001",{"quantity":1,
@@ -247,9 +247,9 @@
"docstatus": 1,
"with_operations": 0}, [
{"item_code": "_Test PPT Item Raw A","item_name": "_Test PPT Item Raw A",
- "doctype":"BOM Item", "qty":6, "rate":100, "amount": 600},
+ "doctype":"BOM Item", "stock_qty":6, "rate":100, "amount": 600},
{"item_code": "_Test PPT Item Sub B","item_name": "_Test PPT Item Sub B",
- "bom_no":"BOM-_Test PPT Item Sub B-001", "doctype":"BOM Item", "qty":2,
+ "bom_no":"BOM-_Test PPT Item Sub B-001", "doctype":"BOM Item", "stock_qty":2,
"rate":100, "amount": 200}])
bom_sCA = make_bom("BOM-_Test PPT Item SC A-001",{"quantity":1,
@@ -259,7 +259,7 @@
"docstatus": 1,
"with_operations": 0}, [
{"item_code": "_Test PPT Item Raw D","item_name": "_Test PPT Item Raw D",
- "doctype":"BOM Item", "qty":1, "rate":100, "amount": 100}])
+ "doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100}])
bom_sCB = make_bom("BOM-_Test PPT Item SC B-001",{"quantity":1,
"item": "_Test PPT Item SC B",
@@ -268,9 +268,9 @@
"docstatus": 1,
"with_operations": 0}, [
{"item_code": "_Test PPT Item Raw B","item_name": "_Test PPT Item Raw B",
- "doctype":"BOM Item", "qty":1, "rate":100, "amount": 100},
+ "doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100},
{"item_code": "_Test PPT Item Raw C","item_name": "_Test PPT Item Raw C",
- "doctype":"BOM Item", "qty":4, "rate":100, "amount": 400}])
+ "doctype":"BOM Item", "stock_qty":4, "rate":100, "amount": 400}])
bom_subA = make_bom("BOM-_Test PPT Item Sub A-001",{"quantity":1,
"item": "_Test PPT Item Sub A",
@@ -278,11 +278,11 @@
"is_default": 1,
"docstatus": 1,
"with_operations": 0}, [
- {"item_code": "_Test PPT Item Sub C","item_name": "_Test PPT Item Sub C",
+ {"item_code": "_Test PPT Item Sub C","item_name": "_Test PPT Item Sub C",
"bom_no":"BOM-_Test PPT Item Sub C-001", "doctype":"BOM Item",
- "qty":1, "rate":100, "amount": 100},
+ "stock_qty":1, "rate":100, "amount": 100},
{"item_code": "_Test PPT Item SC B","item_name": "_Test PPT Item SC B",
- "bom_no":"BOM-_Test PPT Item SC B-001", "doctype":"BOM Item", "qty":2,
+ "bom_no":"BOM-_Test PPT Item SC B-001", "doctype":"BOM Item", "stock_qty":2,
"rate":100, "amount": 200}])
bom_master = make_bom("BOM-_Test PPT Item Master-001",{"quantity":1,
@@ -293,16 +293,16 @@
"with_operations": 0}, [
{"item_code": "_Test PPT Item Sub A","item_name": "_Test PPT Item Sub A",
"bom_no":"BOM-_Test PPT Item Sub A-001",
- "doctype":"BOM Item", "qty":2, "rate":100, "amount": 200},
+ "doctype":"BOM Item", "stock_qty":2, "rate":100, "amount": 200},
{"item_code": "_Test PPT Item Sub B","item_name": "_Test PPT Item Sub B",
"bom_no":"BOM-_Test PPT Item Sub B-001",
- "doctype":"BOM Item", "qty":1, "rate":100, "amount": 100},
+ "doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100},
{"item_code": "_Test PPT Item Raw A","item_name": "_Test PPT Item Raw A",
- "doctype":"BOM Item", "qty":2, "rate":100,
+ "doctype":"BOM Item", "stock_qty":2, "rate":100,
"amount": 200},
{"item_code": "_Test PPT Item SC A","item_name": "_Test PPT Item SC A",
"bom_no":"BOM-_Test PPT Item SC A-001",
- "doctype":"BOM Item", "qty":1, "rate":100, "amount": 100}
+ "doctype":"BOM Item", "stock_qty":1, "rate":100, "amount": 100}
])
@@ -388,4 +388,4 @@
where item.item_code = %(item_code)s and item.parent = mat_req.name""", {"item_code":item_code}, as_dict=1):
types.append(d.type)
return types
-
\ No newline at end of file
+
diff --git a/erpnext/manufacturing/report/production_order_stock_report/production_order_stock_report.py b/erpnext/manufacturing/report/production_order_stock_report/production_order_stock_report.py
index 6d586dd..bb79a49 100644
--- a/erpnext/manufacturing/report/production_order_stock_report/production_order_stock_report.py
+++ b/erpnext/manufacturing/report/production_order_stock_report/production_order_stock_report.py
@@ -23,7 +23,7 @@
item_list = frappe.db.sql("""SELECT
bom_item.item_code as item_code,
- ifnull(ledger.actual_qty*bom.quantity/bom_item.qty,0) as build_qty
+ ifnull(ledger.actual_qty*bom.quantity/bom_item.stock_qty,0) as build_qty
FROM
`tabBOM` as bom, `tabBOM Item` AS bom_item
LEFT JOIN `tabBin` AS ledger
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 181cfce..130554f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -403,8 +403,9 @@
erpnext.patches.v8_0.delete_bin_indexes
erpnext.patches.v8_0.move_account_head_from_account_to_warehouse_for_inventory
erpnext.patches.v8_0.change_in_words_varchar_length
+erpnext.patches.v8_0.update_stock_qty_value_in_bom_item
erpnext.patches.v8_0.create_domain_docs #16-05-2017
erpnext.patches.v8_0.update_sales_cost_in_project
erpnext.patches.v8_0.save_system_settings
erpnext.patches.v8_1.delete_deprecated_reports
-erpnext.patches.v8_1.setup_gst_india
+erpnext.patches.v8_1.setup_gst_india #2017-06-27
diff --git a/erpnext/patches/v7_2/contact_address_links.py b/erpnext/patches/v7_2/contact_address_links.py
index 07d9341..cf23e88 100644
--- a/erpnext/patches/v7_2/contact_address_links.py
+++ b/erpnext/patches/v7_2/contact_address_links.py
@@ -4,8 +4,8 @@
def execute():
frappe.reload_doc('core', 'doctype', 'dynamic_link')
- frappe.reload_doc('email', 'doctype', 'contact')
- frappe.reload_doc('contact', 'doctype', 'address')
+ frappe.reload_doc('contacts', 'doctype', 'contact')
+ frappe.reload_doc('contacts', 'doctype', 'address')
map_fields = (
('Customer', 'customer'),
('Supplier', 'supplier'),
diff --git a/erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py b/erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py
new file mode 100644
index 0000000..9e95eb0
--- /dev/null
+++ b/erpnext/patches/v8_0/update_stock_qty_value_in_bom_item.py
@@ -0,0 +1,13 @@
+# 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_doc('manufacturing', 'doctype', 'bom_item')
+ frappe.reload_doc('manufacturing', 'doctype', 'bom_explosion_item')
+ frappe.reload_doc('manufacturing', 'doctype', 'bom_scrap_item')
+ frappe.db.sql("update `tabBOM Item` set stock_qty = qty, uom = stock_uom, conversion_factor = 1")
+ frappe.db.sql("update `tabBOM Explosion Item` set stock_qty = qty")
+ frappe.db.sql("update `tabBOM Scrap Item` set stock_qty = qty")
\ No newline at end of file
diff --git a/erpnext/patches/v8_1/delete_deprecated_reports.py b/erpnext/patches/v8_1/delete_deprecated_reports.py
index 2cb84a9..887277a 100644
--- a/erpnext/patches/v8_1/delete_deprecated_reports.py
+++ b/erpnext/patches/v8_1/delete_deprecated_reports.py
@@ -7,9 +7,48 @@
def execute():
""" delete deprecated reports """
- reports = ["Monthly Salary Register", "Customer Addresses And Contacts",
- "Supplier Addresses And Contacts"]
+ reports = [
+ "Monthly Salary Register", "Customer Addresses And Contacts",
+ "Supplier Addresses And Contacts"
+ ]
for report in reports:
if frappe.db.exists("Report", report):
- frappe.delete_doc("Report", report, ignore_permissions=True)
\ No newline at end of file
+ check_and_update_desktop_icon_for_report(report)
+ check_and_update_auto_email_report(report)
+ frappe.db.commit()
+
+ frappe.delete_doc("Report", report, ignore_permissions=True)
+
+def check_and_update_desktop_icon_for_report(report):
+ """ delete or update desktop icon"""
+ desktop_icons = frappe.db.sql_list("""select name from `tabDesktop Icon`
+ where _report='{0}'""".format(report))
+
+ if not desktop_icons:
+ return
+
+ if report == "Monthly Salary Register":
+ for icon in desktop_icons:
+ frappe.delete_doc("Desktop Icon", icon)
+
+ elif report in ["Customer Addresses And Contacts", "Supplier Addresses And Contacts"]:
+ frappe.db.sql("""update `tabDesktop Icon` set _report='{value}'
+ where name in ({docnames})""".format(
+ value="Addresses And Contacts",
+ docnames=",".join(["'%s'"%icon for icon in desktop_icons])
+ )
+ )
+
+def check_and_update_auto_email_report(report):
+ """ delete or update auto email report for deprecated report """
+
+ auto_email_report = frappe.db.get_value("Auto Email Report", {"report": report})
+ if not auto_email_report:
+ return
+
+ if report == "Monthly Salary Register":
+ frappe.delete_doc("Auto Email Report", auto_email_report)
+
+ elif report in ["Customer Addresses And Contacts", "Supplier Addresses And Contacts"]:
+ frapppe.db.set_value("Auto Email Report", auto_email_report, "report", report)
\ No newline at end of file
diff --git a/erpnext/patches/v8_1/setup_gst_india.py b/erpnext/patches/v8_1/setup_gst_india.py
index 9e54815..ce27d37 100644
--- a/erpnext/patches/v8_1/setup_gst_india.py
+++ b/erpnext/patches/v8_1/setup_gst_india.py
@@ -2,7 +2,9 @@
from frappe.email import sendmail_to_system_managers
def execute():
+ frappe.reload_doc('regional', 'doctype', 'gst_settings')
frappe.reload_doc('regional', 'doctype', 'gst_hsn_code')
+ frappe.reload_doc('stock', 'doctype', 'item')
for report_name in ('GST Sales Register', 'GST Purchase Register',
'GST Itemised Sales Register', 'GST Itemised Purchase Register'):
@@ -11,15 +13,23 @@
if frappe.db.get_single_value('System Settings', 'country')=='India':
from erpnext.regional.india.setup import setup
- setup()
+ delete_custom_field_tax_id_if_exists()
+ setup(patch=True)
send_gst_update_email()
+def delete_custom_field_tax_id_if_exists():
+ for field in frappe.db.sql_list("""select name from `tabCustom Field` where fieldname='tax_id'
+ and dt in ('Sales Order', 'Sales Invoice', 'Delivery Note')"""):
+ frappe.delete_doc("Custom Field", field, ignore_permissions=True)
+ frappe.db.commit()
+
def send_gst_update_email():
message = """Hello,
-<p>ERPNext is now GST Ready.</p>
+<p>ERPNext is now GST Ready!</p>
-<p>To start making GST Invoices from 1st of July, you just need to create new Tax Accounts, Templates and update your Customer's and Supplier's GST Numbers.</p>
+<p>To start making GST Invoices from 1st of July, you just need to create new Tax Accounts,
+Templates and update your Customer's and Supplier's GST Numbers.</p>
<p>Please refer {gst_document_link} to know more about how to setup and implement GST in ERPNext.</p>
@@ -29,5 +39,7 @@
ERPNext Team.
""".format(gst_document_link="<a href='http://frappe.github.io/erpnext/user/manual/en/regional/india/'> ERPNext GST Document </a>")
- sendmail_to_system_managers("[Important] ERPNext GST updates", message)
-
+ try:
+ sendmail_to_system_managers("[Important] ERPNext GST updates", message)
+ except Exception as e:
+ pass
\ No newline at end of file
diff --git a/erpnext/public/images/erpnext-logo.jpg b/erpnext/public/images/erpnext-logo.jpg
new file mode 100644
index 0000000..811eca8
--- /dev/null
+++ b/erpnext/public/images/erpnext-logo.jpg
Binary files differ
diff --git a/erpnext/regional/doctype/gst_settings/__init__.py b/erpnext/regional/doctype/gst_settings/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/doctype/gst_settings/__init__.py
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.js b/erpnext/regional/doctype/gst_settings/gst_settings.js
new file mode 100644
index 0000000..ab2358f
--- /dev/null
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.js
@@ -0,0 +1,25 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('GST Settings', {
+ refresh: function(frm) {
+ frm.add_custom_button('Send GST Update Reminder', () => {
+ return new Promise((resolve) => {
+ return frappe.call({
+ method: 'erpnext.regional.doctype.gst_settings.gst_settings.send_reminder'
+ }).always(() => { resolve(); });
+ });
+ });
+
+ $(frm.fields_dict.gst_summary.wrapper).empty().html(
+ `<table class="table table-bordered">
+ <tbody>
+ <tr>
+ <td>Total Addresses</td><td>${frm.doc.__onload.data.total_addresses}</td>
+ </tr><tr>
+ <td>Total Addresses with GST</td><td>${frm.doc.__onload.data.total_addresses_with_gstin}</td>
+ </tr>
+ </tbody></table>`
+ );
+ }
+});
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.json b/erpnext/regional/doctype/gst_settings/gst_settings.json
new file mode 100644
index 0000000..61af138
--- /dev/null
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.json
@@ -0,0 +1,101 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2017-06-27 15:09:01.318003",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "gst_summary",
+ "fieldtype": "HTML",
+ "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": "GST Summary",
+ "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": "gstin_email_sent_on",
+ "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": "GSTIN Email Sent On",
+ "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,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-06-28 16:20:21.206397",
+ "modified_by": "Administrator",
+ "module": "Regional",
+ "name": "GST Settings",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.py b/erpnext/regional/doctype/gst_settings/gst_settings.py
new file mode 100644
index 0000000..45c565d
--- /dev/null
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, os
+from frappe.utils import get_url, nowdate, date_diff
+from frappe.model.document import Document
+from frappe.contacts.doctype.contact.contact import get_default_contact
+
+class EmailMissing(frappe.ValidationError): pass
+
+class GSTSettings(Document):
+ def onload(self):
+ data = frappe._dict()
+ data.total_addresses = frappe.db.sql('''select count(*) from tabAddress where country = "India"''')
+ data.total_addresses_with_gstin = frappe.db.sql('''select distinct count(*)
+ from tabAddress where country = "India" and ifnull(gstin, '')!='' ''')
+ self.set_onload('data', data)
+
+@frappe.whitelist()
+def send_reminder():
+ frappe.has_permission('GST Settings', throw=True)
+
+ last_sent = frappe.db.get_single_value('GST Settings', 'gstin_email_sent_on')
+ if last_sent and date_diff(nowdate(), last_sent) < 3:
+ frappe.throw("Please wait 3 days before resending the reminder.")
+
+ frappe.db.set_value('GST Settings', 'GST Settings', 'gstin_email_sent_on', nowdate())
+
+ # enqueue if large number of customers, suppliser
+ frappe.enqueue('erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder_to_all_parties')
+ frappe.msgprint('Email Reminders will be sent to all parties with email contacts')
+
+def send_gstin_reminder_to_all_parties():
+ parties = []
+ for address_name in frappe.db.sql('''select name
+ from tabAddress where country = "India" and ifnull(gstin, '')='' '''):
+ address = frappe.get_doc('Address', address_name[0])
+ for link in address.links:
+ party = frappe.get_doc(link.link_doctype, link.link_name)
+ if link.link_doctype in ('Customer', 'Supplier'):
+ t = (link.link_doctype, link.link_name, address.email_id)
+ if not t in parties:
+ parties.append(t)
+
+ sent_to = []
+ for party in parties:
+ # get email from default contact
+ try:
+ email_id = _send_gstin_reminder(party[0], party[1], party[2], sent_to)
+ sent_to.append(email_id)
+ except EmailMissing:
+ pass
+
+
+@frappe.whitelist()
+def send_gstin_reminder(party_type, party):
+ '''Send GSTIN reminder to one party (called from Customer, Supplier form)'''
+ frappe.has_permission(party_type, throw=True)
+ email = _send_gstin_reminder(party_type ,party)
+ if email:
+ frappe.msgprint('Reminder to update GSTIN Sent', title='Reminder sent', indicator='green')
+
+def _send_gstin_reminder(party_type, party, default_email_id=None, sent_to=None):
+ '''Send GST Reminder email'''
+ email_id = frappe.db.get_value('Contact', get_default_contact(party_type, party), 'email_id')
+ if not email_id:
+ # get email from address
+ email_id = default_email_id
+
+ if not email_id:
+ frappe.throw('Email not found in default contact', exc=EmailMissing)
+
+ if sent_to and email_id in sent_to:
+ return
+
+ frappe.sendmail(
+ subject='Please update your GSTIN',
+ recipients=email_id,
+ message='''
+ <p>Hello,</p>
+ <p>Please help us send you GST Ready Invoices.</p>
+ <p>
+ <a href="{0}?party={1}">
+ Click here to update your GSTIN Number in our system
+ </a>
+ </p>
+ <p style="color: #aaa; font-size: 11px; margin-top: 30px;">
+ Get your GST Ready ERP system at <a href="https://erpnext.com">https://erpnext.com</a>
+ <br>
+ ERPNext is a free and open source ERP system.
+ </p>
+ '''.format(os.path.join(get_url(), '/regional/india/update-gstin'), party)
+ )
+
+ return email_id
diff --git a/erpnext/regional/india/party.js b/erpnext/regional/india/party.js
new file mode 100644
index 0000000..402a387
--- /dev/null
+++ b/erpnext/regional/india/party.js
@@ -0,0 +1,25 @@
+erpnext.setup_gst_reminder_button = (doctype) => {
+ frappe.ui.form.on(doctype, {
+ refresh: (frm) => {
+ if(!frm.is_new()) {
+ var missing = false;
+ frm.doc.__onload.addr_list && frm.doc.__onload.addr_list.forEach((d) => {
+ if(!d.gstin) missing = true;
+ });
+ if (!missing) return;
+
+ frm.add_custom_button('Send GST Update Reminder', () => {
+ return new Promise((resolve) => {
+ return frappe.call({
+ method: 'erpnext.regional.doctype.gst_settings.gst_settings.send_gstin_reminder',
+ args: {
+ party_type: frm.doc.doctype,
+ party: frm.doc.name,
+ }
+ }).always(() => { resolve(); });
+ });
+ });
+ }
+ }
+ });
+};
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 46f0a96..a9f3a30 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -8,13 +8,14 @@
from frappe.permissions import add_permission
from erpnext.regional.india import states
-def setup(company=None):
+def setup(company=None, patch=True):
make_custom_fields()
- make_fixtures()
add_permissions()
add_custom_roles_for_reports()
add_hsn_codes()
update_address_template()
+ if not patch:
+ make_fixtures()
def update_address_template():
with open(os.path.join(os.path.dirname(__file__), 'address_template.html'), 'r') as f:
@@ -64,7 +65,7 @@
)).insert()
def add_permissions():
- for doctype in ('GST HSN Code',):
+ for doctype in ('GST HSN Code', 'GST Settings'):
add_permission(doctype, 'Accounts Manager', 0)
add_permission(doctype, 'All', 0)
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 26c5794..4d37498 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -7,9 +7,10 @@
return
if doc.gstin:
- 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):
- frappe.throw(_("Invalid GSTIN"))
+ 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):
+ frappe.throw(_("Invalid GSTIN or Enter NA for Unregistered"))
if not doc.gst_state:
if doc.state in states:
diff --git a/erpnext/schools/doctype/program_enrollment/program_enrollment.js b/erpnext/schools/doctype/program_enrollment/program_enrollment.js
index dcdaabc..d1b703b 100644
--- a/erpnext/schools/doctype/program_enrollment/program_enrollment.js
+++ b/erpnext/schools/doctype/program_enrollment/program_enrollment.js
@@ -30,6 +30,16 @@
}
});
}
+
+ frm.set_query("student", function() {
+ return{
+ query: "erpnext.schools.doctype.program_enrollment.program_enrollment.get_students",
+ filters: {
+ 'academic_year': frm.doc.academic_year,
+ 'academic_term': frm.doc.academic_term
+ }
+ }
+ });
},
program: function(frm) {
diff --git a/erpnext/schools/doctype/program_enrollment/program_enrollment.py b/erpnext/schools/doctype/program_enrollment/program_enrollment.py
index feb4c2f..4e67908 100644
--- a/erpnext/schools/doctype/program_enrollment/program_enrollment.py
+++ b/erpnext/schools/doctype/program_enrollment/program_enrollment.py
@@ -77,3 +77,34 @@
"_txt": txt.replace('%', ''),
"program": filters['program']
})
+
+
+@frappe.whitelist()
+def get_students(doctype, txt, searchfield, start, page_len, filters):
+ if not filters.get("academic_term"):
+ filters["academic_term"] = frappe.defaults.get_defaults().academic_term
+
+ if not filters.get("academic_year"):
+ filters["academic_year"] = frappe.defaults.get_defaults().academic_year
+
+ enrolled_students = frappe.get_list("Program Enrollment", filters={
+ "academic_term": filters.get('academic_term'),
+ "academic_year": filters.get('academic_year')
+ }, fields=["student"])
+
+ students = [d.student for d in enrolled_students] if enrolled_students else [""]
+
+ return frappe.db.sql("""select
+ name, title from tabStudent
+ where
+ name not in (%s)
+ and
+ `%s` LIKE %s
+ order by
+ idx desc, name
+ limit %s, %s"""%(
+ ", ".join(['%s']*len(students)), searchfield, "%s", "%s", "%s"),
+ tuple(students + ["%%%s%%" % txt, start, page_len]
+ )
+ )
+
diff --git a/erpnext/schools/doctype/school_settings/school_settings.json b/erpnext/schools/doctype/school_settings/school_settings.json
index 8607a76..8d4d4f5 100644
--- a/erpnext/schools/doctype/school_settings/school_settings.json
+++ b/erpnext/schools/doctype/school_settings/school_settings.json
@@ -139,8 +139,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "default": "1",
- "fieldname": "validation_from_pe",
+ "description": "For Batch based Student Group, the Student Batch will be validated for every Student from the Program Enrollment.",
+ "fieldname": "validate_batch",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -149,7 +149,38 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Validate the Student Group from Program Enrollment",
+ "label": "Validate Batch for Students in Student Group",
+ "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,
+ "description": "For Course based Student Group, the Course will be validated for every Student from the enrolled Courses in Program Enrollment.",
+ "fieldname": "validate_course",
+ "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": "Validate Enrolled Course for Students in Student Group",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -175,7 +206,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-04-27 15:37:00.159072",
+ "modified": "2017-06-26 14:07:36.542314",
"modified_by": "Administrator",
"module": "Schools",
"name": "School Settings",
diff --git a/erpnext/schools/doctype/school_settings/school_settings.py b/erpnext/schools/doctype/school_settings/school_settings.py
index 6d8efb4..999014a 100644
--- a/erpnext/schools/doctype/school_settings/school_settings.py
+++ b/erpnext/schools/doctype/school_settings/school_settings.py
@@ -11,7 +11,8 @@
# "key in defaults": "key in Global Defaults"
"academic_year": "current_academic_year",
"academic_term": "current_academic_term",
- "student_validation_setting": "validation_from_pe",
+ "validate_batch": "validate_batch",
+ "validate_course": "validate_course"
}
class SchoolSettings(Document):
diff --git a/erpnext/schools/doctype/student_attendance/student_attendance.py b/erpnext/schools/doctype/student_attendance/student_attendance.py
index 2688123..6960296 100644
--- a/erpnext/schools/doctype/student_attendance/student_attendance.py
+++ b/erpnext/schools/doctype/student_attendance/student_attendance.py
@@ -35,9 +35,7 @@
student_group = frappe.db.get_value("Course Schedule", self.course_schedule, "student_group")
else:
student_group = self.student_group
- student_group_students = []
- for d in get_student_group_students(student_group):
- student_group_students.append(d.student)
+ student_group_students = [d.student for d in get_student_group_students(student_group)]
if student_group and self.student not in student_group_students:
frappe.throw(_('''Student {0}: {1} does not belong to Student Group {2}'''.format(self.student, self.student_name, student_group)))
diff --git a/erpnext/schools/doctype/student_group/student_group.js b/erpnext/schools/doctype/student_group/student_group.js
index 83fe094..80355a8 100644
--- a/erpnext/schools/doctype/student_group/student_group.js
+++ b/erpnext/schools/doctype/student_group/student_group.js
@@ -9,6 +9,22 @@
}
};
});
+ if (!frm.__islocal) {
+ frm.set_query("student", "students", function() {
+ return{
+ query: "erpnext.schools.doctype.student_group.student_group.fetch_students",
+ filters: {
+ 'academic_year': frm.doc.academic_year,
+ 'group_based_on': frm.doc.group_based_on,
+ 'academic_term': frm.doc.academic_term,
+ 'program': frm.doc.program,
+ 'batch': frm.doc.batch,
+ 'course': frm.doc.course,
+ 'student_group': frm.doc.name
+ }
+ }
+ });
+ }
},
refresh: function(frm) {
diff --git a/erpnext/schools/doctype/student_group/student_group.py b/erpnext/schools/doctype/student_group/student_group.py
index 9cdf9c7..55f1b66 100644
--- a/erpnext/schools/doctype/student_group/student_group.py
+++ b/erpnext/schools/doctype/student_group/student_group.py
@@ -12,8 +12,7 @@
def validate(self):
self.validate_mandatory_fields()
self.validate_strength()
- if frappe.defaults.get_defaults().student_validation_setting:
- self.validate_students()
+ self.validate_students()
self.validate_and_set_child_table_fields()
validate_duplicate_student(self.students)
@@ -31,12 +30,14 @@
def validate_students(self):
program_enrollment = get_program_enrollment(self.academic_year, self.academic_term, self.program, self.batch, self.course)
- students = [d.student for d in program_enrollment] if program_enrollment else None
+ students = [d.student for d in program_enrollment] if program_enrollment else []
for d in self.students:
- if self.group_based_on != "Activity" and students and d.student not in students and d.active == 1:
- frappe.throw(_("{0} - {1} is not enrolled in the given {2}".format(d.group_roll_number, d.student_name, self.group_based_on)))
if not frappe.db.get_value("Student", d.student, "enabled") and d.active:
frappe.throw(_("{0} - {1} is inactive student".format(d.group_roll_number, d.student_name)))
+ if self.group_based_on == "Batch" and d.student not in students and frappe.defaults.get_defaults().validate_batch:
+ frappe.throw(_("{0} - {1} is not enrolled in the Batch {2}".format(d.group_roll_number, d.student_name, self.batch)))
+ if self.group_based_on == "Course" and d.student not in students and frappe.defaults.get_defaults().validate_course:
+ frappe.throw(_("{0} - {1} is not enrolled in the Course {2}".format(d.group_roll_number, d.student_name, self.course)))
def validate_and_set_child_table_fields(self):
roll_numbers = [d.group_roll_number for d in self.students if d.group_roll_number]
@@ -95,3 +96,25 @@
'''.format(condition1=condition1, condition2=condition2),
({"academic_year": academic_year, "academic_term":academic_term, "program": program, "batch": batch, "course": course}), as_dict=1)
+
+@frappe.whitelist()
+def fetch_students(doctype, txt, searchfield, start, page_len, filters):
+ if filters.get("group_based_on") != "Activity":
+ enrolled_students = get_program_enrollment(filters.get('academic_year'), filters.get('academic_term'),
+ filters.get('program'), filters.get('batch'))
+ student_group_student = frappe.db.sql_list('''select student from `tabStudent Group Student` where parent=%s''',
+ (filters.get('student_group')))
+ students = ([d.student for d in enrolled_students if d.student not in student_group_student]
+ if enrolled_students else [""]) or [""]
+ return frappe.db.sql("""select name, title from tabStudent
+ where name in ({0}) and `{1}` LIKE %s
+ order by idx desc, name
+ limit %s, %s""".format(", ".join(['%s']*len(students)), searchfield),
+ tuple(students + ["%%%s%%" % txt, start, page_len]))
+ else:
+ return frappe.db.sql("""select name, title from tabStudent
+ where `{0}` LIKE %s
+ order by idx desc, name
+ limit %s, %s""".format(searchfield),
+ tuple(["%%%s%%" % txt, start, page_len]))
+
diff --git a/erpnext/schools/report/course_wise_assessment_report/__init__.py b/erpnext/schools/report/course_wise_assessment_report/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/schools/report/course_wise_assessment_report/__init__.py
diff --git a/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.js b/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.js
new file mode 100644
index 0000000..42b19eb
--- /dev/null
+++ b/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.js
@@ -0,0 +1,34 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.query_reports["Course wise Assessment Report"] = {
+ "filters": [
+ {
+ "fieldname":"assessment_group",
+ "label": __("Assessment Group"),
+ "fieldtype": "Link",
+ "options": "Assessment Group",
+ "reqd": 1,
+ "get_query": function() {
+ return{
+ filters: {
+ 'is_group': 0
+ }
+ };
+ }
+ },
+ {
+ "fieldname":"course",
+ "label": __("Course"),
+ "fieldtype": "Link",
+ "options": "Course",
+ "reqd": 1
+ },
+ {
+ "fieldname":"student_group",
+ "label": __("Student Group"),
+ "fieldtype": "Link",
+ "options": "Student Group"
+ }
+ ]
+};
diff --git a/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.json b/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.json
new file mode 100644
index 0000000..6b089d2
--- /dev/null
+++ b/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.json
@@ -0,0 +1,23 @@
+{
+ "add_total_row": 0,
+ "apply_user_permissions": 1,
+ "creation": "2017-05-05 14:46:13.776133",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2017-05-05 14:47:18.080385",
+ "modified_by": "Administrator",
+ "module": "Schools",
+ "name": "Course wise Assessment Report",
+ "owner": "Administrator",
+ "ref_doctype": "Assessment Result",
+ "report_name": "Course wise Assessment Report",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Academics User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.py b/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.py
new file mode 100644
index 0000000..b5a2fc1
--- /dev/null
+++ b/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.py
@@ -0,0 +1,122 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from collections import defaultdict
+
+def execute(filters=None):
+ args = frappe._dict()
+ args["assessment_group"] = filters.get("assessment_group")
+ if args["assessment_group"] == "All Assessment Groups":
+ frappe.throw(_("Please select the assessment group other than 'All Assessment Groups'"))
+
+ args["course"] = filters.get("course")
+ args["student_group"] = filters.get("student_group")
+ if args["student_group"]:
+ cond = "and ap.student_group=%(student_group)s"
+ else:
+ cond = ''
+
+ # find all assessment plan linked with the filters provided
+ assessment_plan = frappe.db.sql('''
+ select
+ ap.name, ap.student_group, apc.assessment_criteria, apc.maximum_score as max_score
+ from
+ `tabAssessment Plan` ap, `tabAssessment Plan Criteria` apc
+ where
+ ap.assessment_group=%(assessment_group)s and ap.course=%(course)s and
+ ap.name=apc.parent and ap.docstatus=1 {0}
+ order by
+ apc.assessment_criteria'''.format(cond), (args), as_dict=1)
+
+ assessment_plan_list = set([d["name"] for d in assessment_plan])
+ if not assessment_plan_list:
+ frappe.throw(_("No assessment plan linked with this assessment group"))
+
+ student_group_list = set([d["student_group"] for d in assessment_plan])
+ assessment_result = frappe.db.sql('''select ar.student, ard.assessment_criteria, ard.grade, ard.score
+ from `tabAssessment Result` ar, `tabAssessment Result Detail` ard
+ where ar.assessment_plan in (%s) and ar.name=ard.parent and ar.docstatus=1
+ order by ard.assessment_criteria''' %', '.join(['%s']*len(assessment_plan_list)),
+ tuple(assessment_plan_list), as_dict=1)
+
+ result_dict = defaultdict(dict)
+ kounter = defaultdict(dict)
+ for result in assessment_result:
+ result_dict[result.student].update({frappe.scrub(result.assessment_criteria): result.grade,
+ frappe.scrub(result.assessment_criteria)+"_score": result.score})
+ if result.grade in kounter[result.assessment_criteria]:
+ kounter[result.assessment_criteria][result.grade] += 1
+ else:
+ kounter[result.assessment_criteria].update({result.grade: 1})
+
+ student_list = frappe.db.sql('''select sgs.student, sgs.student_name
+ from `tabStudent Group` sg, `tabStudent Group Student` sgs
+ where sg.name = sgs.parent and sg.name in (%s)
+ order by sgs.group_roll_number asc''' %', '.join(['%s']*len(student_group_list)),
+ tuple(student_group_list), as_dict=1)
+
+ for student in student_list:
+ student.update(result_dict[student.student])
+ data = student_list
+
+ columns = get_column(list(set([(d["assessment_criteria"],d["max_score"]) for d in assessment_plan])))
+
+ grading_scale = frappe.db.get_value("Assessment Plan", list(assessment_plan_list)[0], "grading_scale")
+ grades = frappe.db.sql_list('''select grade_code from `tabGrading Scale Interval` where parent=%s''',
+ (grading_scale))
+ assessment_criteria_list = list(set([d["assessment_criteria"] for d in assessment_plan]))
+ chart = get_chart_data(grades, assessment_criteria_list, kounter)
+
+ return columns, data, None, chart
+
+def get_column(assessment_criteria):
+ columns = [{
+ "fieldname": "student",
+ "label": _("Student ID"),
+ "fieldtype": "Link",
+ "options": "Student",
+ "width": 90
+ },
+ {
+ "fieldname": "student_name",
+ "label": _("Student Name"),
+ "fieldtype": "Data",
+ "width": 160
+ }]
+ for d in assessment_criteria:
+ columns.append({
+ "fieldname": frappe.scrub(d[0]),
+ "label": d[0],
+ "fieldtype": "Data",
+ "width": 110
+ })
+ columns.append({
+ "fieldname": frappe.scrub(d[0]) +"_score",
+ "label": "Score(" + str(int(d[1])) + ")",
+ "fieldtype": "Float",
+ "width": 100
+ })
+ return columns
+
+def get_chart_data(grades, assessment_criteria_list, kounter):
+ grades = sorted(grades)
+ chart_data = []
+ chart_data.append(["x"] + assessment_criteria_list)
+ for grade in grades:
+ tmp = [grade]
+ for ac in assessment_criteria_list:
+ if grade in kounter[ac]:
+ tmp.append(kounter[ac][grade])
+ else:
+ tmp.append(0)
+ chart_data.append(tmp)
+ return {
+ "data": {
+ "x": "x",
+ "columns": chart_data
+ },
+ "chart_type": 'bar',
+ }
diff --git a/erpnext/selling/doctype/customer/regional/india.js b/erpnext/selling/doctype/customer/regional/india.js
new file mode 100644
index 0000000..edb8383
--- /dev/null
+++ b/erpnext/selling/doctype/customer/regional/india.js
@@ -0,0 +1,3 @@
+{% include "erpnext/regional/india/party.js" %}
+
+erpnext.setup_gst_reminder_button('Customer')
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index 47e64d7..5c7697e 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -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.domain)))
domain_settings.save()
def create_feed_and_todo():
diff --git a/erpnext/support/report/support_hours/__init__.py b/erpnext/support/report/support_hours/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/support/report/support_hours/__init__.py
diff --git a/erpnext/support/report/support_hours/support_hours.js b/erpnext/support/report/support_hours/support_hours.js
new file mode 100644
index 0000000..439b767
--- /dev/null
+++ b/erpnext/support/report/support_hours/support_hours.js
@@ -0,0 +1,39 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Support Hours"] = {
+ "filters": [
+ {
+ 'lable': __("From Date"),
+ 'fieldname': 'from_date',
+ 'fieldtype': 'Date',
+ 'default': frappe.datetime.nowdate(),
+ 'reqd': 1
+ },
+ {
+ 'lable': __("To Date"),
+ 'fieldname': 'to_date',
+ 'fieldtype': 'Date',
+ 'default': frappe.datetime.nowdate(),
+ 'reqd': 1
+ }
+ ],
+ get_chart_data: function(columns, result) {
+ return {
+ data: {
+ x: 'Date',
+ columns: [
+ ['Date'].concat($.map(result, function(d) { return d.date; })),
+ [columns[3].label].concat($.map(result, function(d) { return d[columns[3].label]; })),
+ [columns[4].label].concat($.map(result, function(d) { return d[columns[4].label]; })),
+ [columns[5].label].concat($.map(result, function(d) { return d[columns[5].label]; })),
+ [columns[6].label].concat($.map(result, function(d) { return d[columns[6].label]; })),
+ [columns[7].label].concat($.map(result, function(d) { return d[columns[7].label]; }))
+ ]
+ },
+ chart_type: 'bar',
+
+ }
+ }
+}
diff --git a/erpnext/support/report/support_hours/support_hours.json b/erpnext/support/report/support_hours/support_hours.json
new file mode 100644
index 0000000..01e4bb4
--- /dev/null
+++ b/erpnext/support/report/support_hours/support_hours.json
@@ -0,0 +1,27 @@
+{
+ "add_total_row": 0,
+ "apply_user_permissions": 1,
+ "creation": "2017-06-23 14:21:37.558691",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "letter_head": "",
+ "modified": "2017-06-23 16:33:31.211390",
+ "modified_by": "Administrator",
+ "module": "Support",
+ "name": "Support Hours",
+ "owner": "Administrator",
+ "ref_doctype": "Issue",
+ "report_name": "Support Hours",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Support Team"
+ },
+ {
+ "role": "System Manager"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/support/report/support_hours/support_hours.py b/erpnext/support/report/support_hours/support_hours.py
new file mode 100644
index 0000000..f1606cd
--- /dev/null
+++ b/erpnext/support/report/support_hours/support_hours.py
@@ -0,0 +1,73 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.utils import add_to_date, getdate, get_datetime
+
+time_slots = {
+ '12AM - 3AM': '00:00:00-03:00:00',
+ '3AM - 6AM': '03:00:00-06:00:00',
+ '6AM - 9AM': '06:00:00-09:00:00',
+ '9AM - 12PM': '09:00:00-12:00:00',
+ '12PM - 3PM': '12:00:00-15:00:00',
+ '3PM - 6PM': '15:00:00-18:00:00',
+ '6PM - 9PM': '18:00:00-21:00:00',
+ '9PM - 12AM': '21:00:00-23:00:00'
+}
+
+def execute(filters=None):
+ columns, data = [], []
+ if not filters.get('periodicity'):
+ filters['periodicity'] = 'Daily'
+
+ columns = get_columns()
+ data = get_data(filters)
+ return columns, data
+
+def get_data(filters):
+ start_date = getdate(filters.from_date)
+ data = []
+ while(start_date <= getdate(filters.to_date)):
+ hours_count = {'date': start_date}
+ for key, value in time_slots.items():
+ start_time, end_time = value.split('-')
+ start_time = get_datetime("{0} {1}".format(start_date.strftime("%Y-%m-%d"), start_time))
+ end_time = get_datetime("{0} {1}".format(start_date.strftime("%Y-%m-%d"), end_time))
+ hours_count[key] = get_hours_count(start_time, end_time)
+
+ if hours_count:
+ data.append(hours_count)
+
+ start_date = add_to_date(start_date, days=1)
+
+ return data
+
+def get_hours_count(start_time, end_time):
+ data = frappe.db.sql(""" select count(*) from `tabIssue` where creation
+ between %(start_time)s and %(end_time)s""", {
+ 'start_time': start_time,
+ 'end_time': end_time
+ }, as_list=1) or []
+
+ return data[0][0] if len(data) > 0 else 0
+
+def get_columns():
+ columns = [{
+ "fieldname": "date",
+ "label": _("Date"),
+ "fieldtype": "Date",
+ "width": 100
+ }]
+
+ for label in ['12AM - 3AM', '3AM - 6AM', '6AM - 9AM',
+ '9AM - 12PM', '12PM - 3PM', '3PM - 6PM', '6PM - 9PM', '9PM - 12AM']:
+ columns.append({
+ "fieldname": label,
+ "label": _(label),
+ "fieldtype": "Data",
+ "width": 120
+ })
+
+ return columns
\ No newline at end of file
diff --git a/erpnext/templates/pages/regional/__init__.py b/erpnext/templates/pages/regional/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/templates/pages/regional/__init__.py
diff --git a/erpnext/templates/pages/regional/india/__init__.py b/erpnext/templates/pages/regional/india/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/templates/pages/regional/india/__init__.py
diff --git a/erpnext/templates/pages/regional/india/update-gstin.html b/erpnext/templates/pages/regional/india/update-gstin.html
new file mode 100644
index 0000000..3d9ab5d
--- /dev/null
+++ b/erpnext/templates/pages/regional/india/update-gstin.html
@@ -0,0 +1,45 @@
+{% extends "templates/web.html" %}
+
+{% block title %}Update GSTIN{% endblock %}
+
+{% block header %}<h2>Update GSTIN</h2>{% endblock %}
+
+{% block page_content %}
+<h3>{{ party_name }}</h3>
+{% if not_found %}
+ <p class='alert alert-danger' style='max-width: 300px;'>
+ Company Not Found
+ </p>
+ <p>
+ If this problem persists, please contact the company.
+ </p>
+
+{% elif invalid_gstin %}
+ <p class='alert alert-danger' style='max-width: 300px;'>
+ Invalid GSTIN
+ </p>
+ <p>
+ <a href="?party={{ party.name }}">Edit Again</a>
+ </p>
+{% elif updated %}
+ <p class='alert alert-success' style='max-width: 300px;'>
+ <i class='octicon octicon-check'></i> GSTIN Updated
+ </p>
+ <p>
+ <a href="?party={{ party.name }}">Edit Again</a>
+ </p>
+{% else %}
+ <p class='text-muted'>Please update your GSTIN for us to issue correct tax invoice</p>
+ <form method='GET' action='/regional/india/update-gstin.html'>
+ <input type='hidden' value='{{ party.name }}' name='party'>
+ {% for address in party.__onload.addr_list %}
+ <div class='bordered' style='max-width: 300px; margin-bottom: 15px;'>
+ {{ address.display }}
+ <p><input type='text' class='form-control'
+ value='{{ address.gstin or "" }}' name='{{ address.name }}' placeholder='GSTIN'></p>
+ </div>
+ {% endfor %}
+ <p><input type='submit' class='btn btn-primary' value='Update'></p>
+ </form>
+{% endif %}
+{% endblock %}
diff --git a/erpnext/templates/pages/regional/india/update_gstin.py b/erpnext/templates/pages/regional/india/update_gstin.py
new file mode 100644
index 0000000..8dcd48e
--- /dev/null
+++ b/erpnext/templates/pages/regional/india/update_gstin.py
@@ -0,0 +1,42 @@
+import frappe
+from frappe import _
+
+def get_context(context):
+ context.no_cache = 1
+ party = frappe.form_dict.party
+ context.party_name = party
+
+ try:
+ update_gstin(context)
+ except frappe.ValidationError:
+ context.invalid_gstin = 1
+
+ party_type = 'Customer'
+ party_name = frappe.db.get_value('Customer', party)
+
+ if not party_name:
+ party_type = 'Supplier'
+ party_name = frappe.db.get_value('Supplier', party)
+
+ if not party_name:
+ context.not_found = 1
+ return
+
+ context.party = frappe.get_doc(party_type, party_name)
+ context.party.onload()
+
+
+def update_gstin(context):
+ dirty = False
+ for key, value in frappe.form_dict.items():
+ if key != 'party':
+ address_name = frappe.get_value('Address', key)
+ if address_name:
+ address = frappe.get_doc('Address', address_name)
+ address.gstin = value.upper()
+ address.save(ignore_permissions=True)
+ dirty = True
+
+ if dirty:
+ frappe.db.commit()
+ context.updated = True