Merge branch 'develop'
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 6f73741..7046172 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
import frappe
-__version__ = '8.0.26'
+__version__ = '8.0.27'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 50bfbd3..2eef79c 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -147,6 +147,7 @@
var currency_field = (frm.doc.payment_type=="Receive") ? "paid_from_account_currency" : "paid_to_account_currency"
frm.set_df_property("total_allocated_amount", "options", currency_field);
frm.set_df_property("unallocated_amount", "options", currency_field);
+ frm.set_df_property("party_balance", "options", currency_field);
frm.set_currency_labels(["total_amount", "outstanding_amount", "allocated_amount"],
party_account_currency, "references");
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index b913b6b..71897d4 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -285,9 +285,10 @@
def filter_pricing_rules(args, pricing_rules):
# filter for qty
+ stock_qty = args.get('qty') * args.get('conversion_factor', 1)
if pricing_rules:
- pricing_rules = filter(lambda x: (flt(args.get("qty"))>=flt(x.min_qty)
- and (flt(args.get("qty"))<=x.max_qty if x.max_qty else True)), pricing_rules)
+ pricing_rules = filter(lambda x: (flt(stock_qty)>=flt(x.min_qty)
+ and (flt(stock_qty)<=x.max_qty if x.max_qty else True)), pricing_rules)
# add variant_of property in pricing rule
for p in pricing_rules:
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index 814c5c0..31b1d46 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -5,6 +5,9 @@
from __future__ import unicode_literals
import unittest
import frappe
+from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+from erpnext.stock.get_item_details import get_item_details
+from frappe import MandatoryError
class TestPricingRule(unittest.TestCase):
def test_pricing_rule_for_discount(self):
@@ -203,3 +206,46 @@
details = get_item_details(args)
self.assertEquals(details.get("discount_percentage"), 17.5)
+
+ def test_pricing_rule_for_stock_qty(self):
+ frappe.db.sql("delete from `tabPricing Rule`")
+
+ test_record = {
+ "doctype": "Pricing Rule",
+ "title": "_Test Pricing Rule",
+ "apply_on": "Item Code",
+ "item_code": "_Test Item",
+ "selling": 1,
+ "price_or_discount": "Discount Percentage",
+ "price": 0,
+ "min_qty": 5,
+ "max_qty": 7,
+ "discount_percentage": 17.5,
+ "company": "_Test Company"
+ }
+ frappe.get_doc(test_record.copy()).insert()
+
+ if not frappe.db.get_value('UOM Conversion Detail',
+ {'parent': '_Test Item', 'uom': 'box'}):
+ item = frappe.get_doc('Item', '_Test Item')
+ item.append('uoms', {
+ 'uom': 'Box',
+ 'conversion_factor': 5
+ })
+ item.save(ignore_permissions=True)
+
+ # With pricing rule
+ so = make_sales_order(item_code="_Test Item", qty=1, uom="Box", do_not_submit=True)
+ so.items[0].price_list_rate = 100
+ so.submit()
+ so = frappe.get_doc('Sales Order', so.name)
+ self.assertEquals(so.items[0].discount_percentage, 17.5)
+ self.assertEquals(so.items[0].rate, 82.5)
+
+ # Without pricing rule
+ so = make_sales_order(item_code="_Test Item", qty=2, uom="Box", do_not_submit=True)
+ so.items[0].price_list_rate = 100
+ so.submit()
+ so = frappe.get_doc('Sales Order', so.name)
+ self.assertEquals(so.items[0].discount_percentage, 0)
+ self.assertEquals(so.items[0].rate, 100)
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 3762b48..63de878 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -49,29 +49,37 @@
}
if(doc.docstatus===0) {
- cur_frm.add_custom_button(__('Purchase Order'), function() {
+ var me = this;
+ this.frm.add_custom_button(__('Purchase Order'), function() {
erpnext.utils.map_current_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_invoice",
source_doctype: "Purchase Order",
+ target: me.frm,
+ setters: {
+ supplier: me.frm.doc.supplier || undefined,
+ },
get_query_filters: {
- supplier: cur_frm.doc.supplier || undefined,
docstatus: 1,
status: ["!=", "Closed"],
per_billed: ["<", 99.99],
- company: cur_frm.doc.company
+ company: me.frm.doc.company
}
})
}, __("Get items from"));
- cur_frm.add_custom_button(__('Purchase Receipt'), function() {
+ this.frm.add_custom_button(__('Purchase Receipt'), function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.purchase_receipt.purchase_receipt.make_purchase_invoice",
source_doctype: "Purchase Receipt",
+ target: me.frm,
+ date_field: "posting_date",
+ setters: {
+ supplier: me.frm.doc.supplier || undefined,
+ },
get_query_filters: {
- supplier: cur_frm.doc.supplier || undefined,
docstatus: 1,
status: ["!=", "Closed"],
- company: cur_frm.doc.company
+ company: me.frm.doc.company
}
})
}, __("Get items from"));
@@ -120,7 +128,7 @@
hide_fields(this.frm.doc);
if(cint(this.frm.doc.is_paid)) {
if(!this.frm.doc.company) {
- cur_frm.set_value("is_paid", 0)
+ this.frm.set_value("is_paid", 0)
msgprint(__("Please specify Company to proceed"));
}
}
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index e8163f0..f235722 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -112,33 +112,43 @@
},
sales_order_btn: function() {
- this.$sales_order_btn = cur_frm.add_custom_button(__('Sales Order'),
+ var me = this;
+ this.$sales_order_btn = this.frm.add_custom_button(__('Sales Order'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
source_doctype: "Sales Order",
+ target: me.frm,
+ setters: {
+ customer: me.frm.doc.customer || undefined,
+ },
get_query_filters: {
docstatus: 1,
status: ["!=", "Closed"],
per_billed: ["<", 99.99],
- customer: cur_frm.doc.customer || undefined,
- company: cur_frm.doc.company
+ company: me.frm.doc.company
}
})
}, __("Get items from"));
},
delivery_note_btn: function() {
- this.$delivery_note_btn = cur_frm.add_custom_button(__('Delivery Note'),
+ var me = this;
+ this.$delivery_note_btn = this.frm.add_custom_button(__('Delivery Note'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
source_doctype: "Delivery Note",
+ target: me.frm,
+ date_field: "posting_date",
+ setters: {
+ company: me.frm.doc.company
+ },
get_query: function() {
var filters = {
- company: cur_frm.doc.company
+ docstatus: 1,
};
- if(cur_frm.doc.customer) filters["customer"] = cur_frm.doc.customer;
+ if(me.frm.doc.customer) filters["customer"] = me.frm.doc.customer;
return {
query: "erpnext.controllers.queries.get_delivery_notes_to_be_billed",
filters: filters
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 295f649..285722b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -52,7 +52,7 @@
def validate(self):
super(SalesInvoice, self).validate()
- self.validate_posting_time()
+ self.validate_auto_set_posting_time()
self.so_dn_required()
self.validate_proj_cust()
self.validate_with_previous_doc()
@@ -378,6 +378,12 @@
def add_remarks(self):
if not self.remarks: self.remarks = 'No Remarks'
+ def validate_auto_set_posting_time(self):
+ # Don't auto set the posting date and time if invoice is amended
+ if self.is_new() and self.amended_from:
+ self.set_posting_time = 1
+
+ self.validate_posting_time()
def so_dn_required(self):
"""check in manage account if sales order / delivery note required or not."""
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index c632e45..da4a3b7 100644
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -78,8 +78,16 @@
make_menu_list: function () {
var me = this;
-
this.page.clear_menu();
+
+ // for mobile
+ this.page.add_menu_item(__("Pay"), function () {
+ me.validate();
+ me.update_paid_amount_status(true);
+ me.create_invoice();
+ me.make_payment();
+ }).addClass('visible-xs');
+
this.page.add_menu_item(__("New Sales Invoice"), function () {
me.save_previous_entry();
me.create_new();
@@ -788,7 +796,8 @@
add_customer: function() {
this.frm.doc.customer = "";
- this.update_customer(true)
+ this.update_customer(true);
+ this.numeric_keypad.show();
},
update_customer: function (new_customer) {
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 85a6329..cfd3336 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -153,30 +153,37 @@
},
add_from_mappers: function() {
- cur_frm.add_custom_button(__('Material Request'),
+ var me = this;
+ this.frm.add_custom_button(__('Material Request'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
source_doctype: "Material Request",
+ target: me.frm,
+ setters: {
+ company: me.frm.doc.company
+ },
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
per_ordered: ["<", 99.99],
- company: cur_frm.doc.company
}
})
}, __("Add items from"));
- cur_frm.add_custom_button(__('Supplier Quotation'),
+ this.frm.add_custom_button(__('Supplier Quotation'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.buying.doctype.supplier_quotation.supplier_quotation.make_purchase_order",
source_doctype: "Supplier Quotation",
+ target: me.frm,
+ setters: {
+ company: me.frm.doc.company
+ },
get_query_filters: {
docstatus: 1,
status: ["!=", "Stopped"],
- company: cur_frm.doc.company
}
})
}, __("Add items from"));
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index 92600b7..593f667 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -48,7 +48,7 @@
});
});
}
-
+
},
make_suppplier_quotation: function(frm) {
@@ -124,24 +124,28 @@
erpnext.buying.RequestforQuotationController = erpnext.buying.BuyingController.extend({
refresh: function() {
+ var me = this;
this._super();
if (this.frm.doc.docstatus===0) {
- cur_frm.add_custom_button(__('Material Request'),
+ this.frm.add_custom_button(__('Material Request'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_request_for_quotation",
source_doctype: "Material Request",
+ target: me.frm,
+ setters: {
+ company: me.frm.doc.company
+ },
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99],
- company: cur_frm.doc.company
+ per_ordered: ["<", 99.99]
}
})
}, __("Get items from"));
// Get items from open Material Requests based on supplier
- cur_frm.add_custom_button(__('Possible Supplier'), function() {
+ this.frm.add_custom_button(__('Possible Supplier'), function() {
// Create a dialog window for the user to pick their supplier
var d = new frappe.ui.Dialog({
title: __('Select Possible Supplier'),
@@ -150,32 +154,35 @@
{fieldname: 'ok_button', fieldtype:'Button', label:'Get Items from Material Requests'},
]
});
-
+
// On the user clicking the ok button
d.fields_dict.ok_button.input.onclick = function() {
var btn = d.fields_dict.ok_button.input;
var v = d.get_values();
if(v) {
$(btn).set_working();
-
+
erpnext.utils.map_current_doc({
method: "erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_item_from_material_requests_based_on_supplier",
source_name: v.supplier,
+ target: me.frm,
+ setters: {
+ company: me.frm.doc.company
+ },
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99],
- company: cur_frm.doc.company
+ per_ordered: ["<", 99.99]
}
});
$(btn).done_working();
d.hide();
}
- }
+ }
d.show();
}, __("Get items from"));
-
+
}
},
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index 1e2379e..6bcbdba 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -14,6 +14,7 @@
erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
refresh: function() {
+ var me = this;
this._super();
if (this.frm.doc.docstatus === 1) {
cur_frm.add_custom_button(__("Purchase Order"), this.make_purchase_order,
@@ -24,18 +25,21 @@
}
else if (this.frm.doc.docstatus===0) {
-
- cur_frm.add_custom_button(__('Material Request'),
+
+ this.frm.add_custom_button(__('Material Request'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.material_request.material_request.make_supplier_quotation",
source_doctype: "Material Request",
+ target: me.frm,
+ setters: {
+ company: me.frm.doc.company
+ },
get_query_filters: {
material_request_type: "Purchase",
docstatus: 1,
status: ["!=", "Stopped"],
- per_ordered: ["<", 99.99],
- company: cur_frm.doc.company
+ per_ordered: ["<", 99.99]
}
})
}, __("Get items from"));
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index d58ba4b..4034306 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -46,8 +46,8 @@
["Draft", None],
["Submitted", "eval:self.docstatus==1"],
["Return", "eval:self.is_return==1 and self.docstatus==1"],
- ["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"],
- ["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1 and self.is_return==0"],
+ ["Paid", "eval:self.outstanding_amount<=0 and self.docstatus==1 and self.is_return==0"],
+ ["Credit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1 and self.is_return==0 and get_value('Sales Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
["Cancelled", "eval:self.docstatus==2"],
@@ -56,8 +56,8 @@
["Draft", None],
["Submitted", "eval:self.docstatus==1"],
["Return", "eval:self.is_return==1 and self.docstatus==1"],
- ["Debit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1"],
- ["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1 and self.is_return==0"],
+ ["Paid", "eval:self.outstanding_amount<=0 and self.docstatus==1 and self.is_return==0"],
+ ["Debit Note Issued", "eval:self.outstanding_amount < 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
["Cancelled", "eval:self.docstatus==2"],
@@ -119,7 +119,8 @@
self.status = s[0]
break
elif s[1].startswith("eval:"):
- if frappe.safe_eval(s[1][5:], None, { "self": self.as_dict(), "getdate": getdate, "nowdate": nowdate }):
+ if frappe.safe_eval(s[1][5:], None, { "self": self.as_dict(), "getdate": getdate,
+ "nowdate": nowdate, "get_value": frappe.db.get_value }):
self.status = s[0]
break
elif getattr(self, s[1])():
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 7889ead..c1c1fd7 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -465,6 +465,8 @@
payment.base_amount = flt(payment.amount * self.doc.conversion_rate)
paid_amount += payment.amount
base_paid_amount += payment.base_amount
+ elif not self.doc.is_return:
+ self.doc.set('payments', [])
self.doc.paid_amount = flt(paid_amount, self.doc.precision("paid_amount"))
self.doc.base_paid_amount = flt(base_paid_amount, self.doc.precision("base_paid_amount"))
diff --git a/erpnext/controllers/tests/test_mapper.py b/erpnext/controllers/tests/test_mapper.py
new file mode 100644
index 0000000..0e2d6d0
--- /dev/null
+++ b/erpnext/controllers/tests/test_mapper.py
@@ -0,0 +1,73 @@
+from __future__ import unicode_literals
+import unittest
+import frappe
+
+import random, json
+import frappe.utils
+from frappe.utils import nowdate
+from frappe.model import mapper
+from frappe.test_runner import make_test_records
+
+class TestMapper(unittest.TestCase):
+ def test_map_docs(self):
+ '''Test mapping of multiple source docs on a single target doc'''
+
+ make_test_records("Item")
+ items = frappe.get_all("Item", fields = ["name", "item_code"], filters = {'is_sales_item': 1, 'has_variants': 0})
+ customers = frappe.get_all("Customer")
+ if items and customers:
+ # Make source docs (quotations) and a target doc (sales order)
+ customer = random.choice(customers).name
+ qtn1, item_list_1 = self.make_quotation(items, customer)
+ qtn2, item_list_2 = self.make_quotation(items, customer)
+ so, item_list_3 = self.make_sales_order()
+
+ # Map source docs to target with corresponding mapper method
+ method = "erpnext.selling.doctype.quotation.quotation.make_sales_order"
+ updated_so = mapper.map_docs(method, json.dumps([qtn1.name, qtn2.name]), so)
+
+ # Assert that all inserted items are present in updated sales order
+ src_items = item_list_1 + item_list_2 + item_list_3
+ self.assertEqual(set([d.item_code for d in src_items]),
+ set([d.item_code for d in updated_so.items]))
+
+ def get_random_items(self, items, limit):
+ '''Get a number of random items from a list of given items'''
+ random_items = []
+ for i in range(0, limit):
+ random_items.append(random.choice(items))
+ return random_items
+
+ def make_quotation(self, items, customer):
+ item_list = self.get_random_items(items, 3)
+ qtn = frappe.get_doc({
+ "doctype": "Quotation",
+ "quotation_to": "Customer",
+ "customer": customer,
+ "order_type": "Sales"
+ })
+ for item in item_list:
+ qtn.append("items", {"qty": "2", "item_code": item.item_code})
+
+ qtn.submit()
+ return qtn, item_list
+
+ def make_sales_order(self):
+ item = frappe.get_doc({
+ "base_amount": 1000.0,
+ "base_rate": 100.0,
+ "description": "CPU",
+ "doctype": "Sales Order Item",
+ "item_code": "_Test Item Home Desktop 100",
+ "item_name": "CPU",
+ "parentfield": "items",
+ "qty": 10.0,
+ "rate": 100.0,
+ "warehouse": "_Test Warehouse - _TC",
+ "stock_uom": "_Test UOM",
+ "conversion_factor": 1.0,
+ "uom": "_Test UOM"
+ })
+ so = frappe.get_doc(frappe.get_test_records('Sales Order')[0])
+ so.insert(ignore_permissions=True)
+ return so, [item]
diff --git a/erpnext/docs/assets/img/setup/integrations/payment_gateway_account_stripe.png b/erpnext/docs/assets/img/setup/integrations/payment_gateway_account_stripe.png
new file mode 100644
index 0000000..8ecf8df
--- /dev/null
+++ b/erpnext/docs/assets/img/setup/integrations/payment_gateway_account_stripe.png
Binary files differ
diff --git a/erpnext/docs/assets/img/setup/integrations/stripe_coa.png b/erpnext/docs/assets/img/setup/integrations/stripe_coa.png
new file mode 100644
index 0000000..27e79c5
--- /dev/null
+++ b/erpnext/docs/assets/img/setup/integrations/stripe_coa.png
Binary files differ
diff --git a/erpnext/docs/assets/img/setup/integrations/stripe_setting.png b/erpnext/docs/assets/img/setup/integrations/stripe_setting.png
new file mode 100644
index 0000000..b6aa124
--- /dev/null
+++ b/erpnext/docs/assets/img/setup/integrations/stripe_setting.png
Binary files differ
diff --git a/erpnext/docs/user/manual/en/setting-up/email/email-account.md b/erpnext/docs/user/manual/en/setting-up/email/email-account.md
index 0fafa53..f020362 100644
--- a/erpnext/docs/user/manual/en/setting-up/email/email-account.md
+++ b/erpnext/docs/user/manual/en/setting-up/email/email-account.md
@@ -8,7 +8,7 @@
ERPNext will create templates for a bunch of email accounts by default. Not all of them are enabled. To enable them, you must set your account details.
-There are 2 types of email accounts, outgoing and incoming. Outgoing email accounts use an SMTP service to send emails and emails are retrived from your inbox using a POP service. Most email providers such as GMail, Outlook or Yahoo provide these services.
+There are 2 types of email accounts, outgoing and incoming. Outgoing email accounts use an SMTP service to send emails and emails are retrived from your inbox using a IMAP or POP service. Most email providers such as GMail, Outlook or Yahoo provide these services.
<img class="screenshot" alt="Defining Criteria" src="{{docs_base_url}}/assets/img/setup/email/email-account-list.png">
@@ -28,7 +28,7 @@
### How ERPNext handles replies
-In ERPNext when you send an email to a contact like a customer, the sender will be the user who sent the email. In the **Reply-To** property, the Email Address will be of the default incoming account (like `replies@yourcompany.com`). ERPNext will automatically extract these emails from the incoming account and tag it to the relvant communication
+In ERPNext when you send an email to a contact like a customer, the sender will be the user who sent the email. In the **Reply-To** property, the Email Address will be of the default incoming account (like `replies@yourcompany.com`). ERPNext will automatically extract these emails from the incoming account and tag it to the relevant communication
### Notification for unreplied messages
diff --git a/erpnext/docs/user/manual/en/setting-up/integrations/stripe-integration.md b/erpnext/docs/user/manual/en/setting-up/integrations/stripe-integration.md
new file mode 100644
index 0000000..05f70f0
--- /dev/null
+++ b/erpnext/docs/user/manual/en/setting-up/integrations/stripe-integration.md
@@ -0,0 +1,30 @@
+#Setting up Stripe
+
+To setup Stripe,
+`Explore > Integrations > Stripe Settings`
+
+#### Setup Stripe
+
+To enable Stripe payment service, you need to configure parameters like Publishable Key, Secret Key
+<img class="screenshot" alt="Razorpay Settings" src="{{docs_base_url}}/assets/img/setup/integrations/stripe_setting.png">
+
+On enabling service, the system will create Payment Gateway record and Account head in chart of account with account type as Bank.
+
+<img class="screenshot" alt="Stripe COA" src="{{docs_base_url}}/assets/img/setup/integrations/stripe_coa.png">
+
+Also it will create Payment Gateway Account entry. Payment Gateway Account is configuration hub from this you can set account head from existing COA, default Payment Request email body template.
+
+<img class="screenshot" alt="Payment Gateway Account" src="{{docs_base_url}}/assets/img/setup/integrations/payment_gateway_account_stripe.png">
+
+After configuring Payment Gateway Account your system is able to accept online payments.
+
+####Supporting transaction currencies
+ "AED", "ALL", "ANG", "ARS", "AUD", "AWG", "BBD", "BDT", "BIF", "BMD", "BND",
+ "BOB", "BRL", "BSD", "BWP", "BZD", "CAD", "CHF", "CLP", "CNY", "COP", "CRC", "CVE", "CZK", "DJF",
+ "DKK", "DOP", "DZD", "EGP", "ETB", "EUR", "FJD", "FKP", "GBP", "GIP", "GMD", "GNF", "GTQ", "GYD",
+ "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "ISK", "JMD", "JPY", "KES", "KHR", "KMF",
+ "KRW", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "MAD", "MDL", "MNT", "MOP", "MRO", "MUR", "MVR",
+ "MWK", "MXN", "MYR", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "PAB", "PEN", "PGK", "PHP", "PKR",
+ "PLN", "PYG", "QAR", "RUB", "SAR", "SBD", "SCR", "SEK", "SGD", "SHP", "SLL", "SOS", "STD", "SVC",
+ "SZL", "THB", "TOP", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VND", "VUV", "WST",
+ "XAF", "XOF", "XPF", "YER", "ZAR"
diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.js b/erpnext/hr/doctype/vehicle_log/vehicle_log.js
index 56c30ff..818a595 100644
--- a/erpnext/hr/doctype/vehicle_log/vehicle_log.js
+++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.js
@@ -16,7 +16,15 @@
}
})
}
+
+ if(frm.doc.docstatus == 1) {
+ frm.add_custom_button(__('Expense Claim'), function() {
+ frm.events.expense_claim(frm)
+ }, __("Make"));
+ frm.page.set_inner_btn_group_as_primary(__("Make"));
+ }
},
+
expense_claim: function(frm){
frappe.call({
method: "erpnext.hr.doctype.vehicle_log.vehicle_log.make_expense_claim",
diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.json b/erpnext/hr/doctype/vehicle_log/vehicle_log.json
index 3610da4..fde34d7 100644
--- a/erpnext/hr/doctype/vehicle_log/vehicle_log.json
+++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "naming_series:",
@@ -12,6 +13,7 @@
"editable_grid": 1,
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -41,6 +43,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -71,6 +74,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,
@@ -131,6 +136,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -159,6 +165,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -187,6 +194,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -216,6 +224,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -245,6 +254,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -274,6 +284,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -303,6 +314,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -332,6 +344,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -361,6 +374,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -390,6 +404,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -419,6 +434,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -447,6 +463,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -477,6 +494,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -506,6 +524,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -519,7 +538,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Service_Details",
+ "label": "Service Details",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -535,6 +554,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -565,64 +585,7 @@
"unique": 0
},
{
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "section_break_20",
- "fieldtype": "Section Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "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_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.docstatus==1",
- "fieldname": "expense_claim",
- "fieldtype": "Button",
- "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": "Make Expense Claim",
- "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,
@@ -652,17 +615,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": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-02-17 16:53:17.975663",
+ "modified": "2017-05-15 13:17:59.575317",
"modified_by": "Administrator",
"module": "HR",
"name": "Vehicle Log",
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
index 9639e7f..da7d133 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
@@ -33,10 +33,13 @@
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
source_doctype: "Sales Order",
+ target: me.frm,
+ setters: {
+ customer: me.frm.doc.customer || undefined,
+ order_type: me.frm.doc.order_type,
+ },
get_query_filters: {
docstatus: 1,
- order_type: me.frm.doc.order_type,
- customer: me.frm.doc.customer || undefined,
company: me.frm.doc.company
}
});
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
index 62cdf86..e1f501b 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
@@ -27,41 +27,53 @@
refresh: function() {
frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
+ var me = this;
+
if (this.frm.doc.docstatus===0) {
- cur_frm.add_custom_button(__('Maintenance Schedule'),
+ this.frm.add_custom_button(__('Maintenance Schedule'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
source_doctype: "Maintenance Schedule",
+ target: me.frm,
+ setters: {
+ customer: me.frm.doc.customer || undefined,
+ },
get_query_filters: {
docstatus: 1,
- customer: cur_frm.doc.customer || undefined,
- company: cur_frm.doc.company
+ company: me.frm.doc.company
}
})
}, __("Get items from"));
- cur_frm.add_custom_button(__('Warranty Claim'),
+ this.frm.add_custom_button(__('Warranty Claim'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.support.doctype.warranty_claim.warranty_claim.make_maintenance_visit",
source_doctype: "Warranty Claim",
+ target: me.frm,
+ date_field: "complaint_date",
+ setters: {
+ customer: me.frm.doc.customer || undefined,
+ },
get_query_filters: {
status: ["in", "Open, Work in Progress"],
- customer: cur_frm.doc.customer || undefined,
- company: cur_frm.doc.company
+ company: me.frm.doc.company
}
})
}, __("Get items from"));
- cur_frm.add_custom_button(__('Sales Order'),
+ this.frm.add_custom_button(__('Sales Order'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
source_doctype: "Sales Order",
+ target: me.frm,
+ setters: {
+ customer: me.frm.doc.customer || undefined,
+ },
get_query_filters: {
docstatus: 1,
- order_type: cur_frm.doc.order_type,
- customer: cur_frm.doc.customer || undefined,
- company: cur_frm.doc.company
+ company: me.frm.doc.company,
+ order_type: me.frm.doc.order_type,
}
})
}, __("Get items from"));
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 5181cf4..576e46d 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -33,9 +33,7 @@
});
}
- if(frm.doc.docstatus==2) {
- // show duplicate button when BOM is cancelled,
- // its not very intuitive
+ if(frm.doc.docstatus!=0) {
frm.add_custom_button(__("Duplicate"), function() {
frm.copy_doc();
});
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 8907cf3..ac91f60 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -393,4 +393,6 @@
erpnext.patches.v8_0.revert_manufacturers_table_from_item
erpnext.patches.v8_0.disable_instructor_role
erpnext.patches.v8_0.merge_student_batch_and_student_group
-erpnext.patches.v8_0.rename_total_margin_to_rate_with_margin # 11-05-2017
\ No newline at end of file
+erpnext.patches.v8_0.rename_total_margin_to_rate_with_margin # 11-05-2017
+erpnext.patches.v8_0.fix_status_for_invoices_with_negative_outstanding
+erpnext.patches.v8_0.make_payments_table_blank_for_non_pos_invoice
diff --git a/erpnext/patches/v7_2/mark_students_active.py b/erpnext/patches/v7_2/mark_students_active.py
index 12057ed..3513cde 100644
--- a/erpnext/patches/v7_2/mark_students_active.py
+++ b/erpnext/patches/v7_2/mark_students_active.py
@@ -1,7 +1,5 @@
import frappe
def execute():
- frappe.reload_doc('schools', 'doctype', 'student_batch_student')
frappe.reload_doc('schools', 'doctype', 'student_group_student')
- frappe.db.sql("update `tabStudent Batch Student` set active=1")
frappe.db.sql("update `tabStudent Group Student` set active=1")
diff --git a/erpnext/patches/v8_0/fix_status_for_invoices_with_negative_outstanding.py b/erpnext/patches/v8_0/fix_status_for_invoices_with_negative_outstanding.py
new file mode 100644
index 0000000..2e7f360
--- /dev/null
+++ b/erpnext/patches/v8_0/fix_status_for_invoices_with_negative_outstanding.py
@@ -0,0 +1,23 @@
+# Copyright (c) 2017, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ for dt, status in [["Sales Invoice", "Credit Note Issued"], ["Purchase Invoice", "Debit Note Issued"]]:
+ invoices = frappe.db.sql("""
+ select name
+ from `tab{0}`
+ where
+ status = %s
+ and outstanding_amount < 0
+ and docstatus=1
+ and is_return=0
+ """.format(dt), status)
+
+ for inv in invoices:
+ return_inv = frappe.db.sql("""select name from `tab{0}`
+ where is_return=1 and return_against=%s and docstatus=1""".format(dt), inv[0])
+ if not return_inv:
+ frappe.db.sql("update `tab{0}` set status='Paid' where name = %s".format(dt), inv[0])
\ No newline at end of file
diff --git a/erpnext/patches/v8_0/make_payments_table_blank_for_non_pos_invoice.py b/erpnext/patches/v8_0/make_payments_table_blank_for_non_pos_invoice.py
new file mode 100644
index 0000000..9750fb7
--- /dev/null
+++ b/erpnext/patches/v8_0/make_payments_table_blank_for_non_pos_invoice.py
@@ -0,0 +1,15 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.reload_doctype('Sales Invoice')
+
+ frappe.db.sql("""
+ delete from
+ `tabSales Invoice Payment`
+ where
+ parent in (select name from `tabSales Invoice` where is_pos = 0)
+ """)
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 40493e1..0345f05 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -216,9 +216,19 @@
# duplicated project
dependency_map = {}
for task in self.tasks:
- name, depends_on_tasks = frappe.db.get_value(
- 'Task', { "subject": task.title, "project": self.copied_from }, ['name', 'depends_on_tasks']
+ _task = frappe.db.get_value(
+ 'Task',
+ {"subject": task.title, "project": self.copied_from},
+ ['name', 'depends_on_tasks'],
+ as_dict=True
)
+
+ if _task is None:
+ continue
+
+ name = _task.name
+ depends_on_tasks = _task.depends_on_tasks
+
depends_on_tasks = [x for x in depends_on_tasks.split(',') if x]
dependency_map[task.title] = [ x['subject'] for x in frappe.get_list(
'Task Depends On', {"parent": name}, ['subject'])]
diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css
index fd24006..86dec05 100644
--- a/erpnext/public/css/erpnext.css
+++ b/erpnext/public/css/erpnext.css
@@ -270,6 +270,11 @@
border: 1px solid #d1d8dd;
border-top: none;
}
+@media (max-width: 767px) {
+ body[data-route="pos"] .item-cart-items {
+ height: 30vh;
+ }
+}
body[data-route="pos"] .no-items-message {
min-height: 200px;
display: flex;
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index c925f45..849275f 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -594,6 +594,8 @@
paid_amount += data.amount;
base_paid_amount += data.base_amount;
})
+ } else if(!this.frm.doc.is_return){
+ this.frm.doc.payments = [];
}
this.frm.doc.paid_amount = flt(paid_amount, precision("paid_amount"));
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 8865b50..3a2254e 100644
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -114,63 +114,68 @@
}
}
var _map = function() {
- // remove first item row if empty
if($.isArray(cur_frm.doc.items) && cur_frm.doc.items.length > 0) {
+ // remove first item row if empty
if(!cur_frm.doc.items[0].item_code) {
cur_frm.doc.items = cur_frm.doc.items.splice(1);
}
// find the doctype of the items table
var items_doctype = frappe.meta.get_docfield(cur_frm.doctype, 'items').options;
-
+
// find the link fieldname from items table for the given
// source_doctype
var link_fieldname = null;
- frappe.get_meta(items_doctype).fields.forEach(function(d) {
+ frappe.get_meta(items_doctype).fields.forEach(function(d) {
if(d.options===opts.source_doctype) link_fieldname = d.fieldname; });
// search in existing items if the source_name is already set and full qty fetched
var already_set = false;
var item_qty_map = {};
-
- $.each(cur_frm.doc.items, function(i, d) {
- if(d[link_fieldname]==opts.source_name) {
- already_set = true;
- if (item_qty_map[d.item_code])
- item_qty_map[d.item_code] += flt(d.qty);
- else
- item_qty_map[d.item_code] = flt(d.qty);
- }
- });
-
- if(already_set) {
- frappe.model.with_doc(opts.source_doctype, opts.source_name, function(r) {
- var source_doc = frappe.model.get_doc(opts.source_doctype, opts.source_name);
- $.each(source_doc.items || [], function(i, row) {
- if(row.qty > flt(item_qty_map[row.item_code])) {
- already_set = false;
- return false;
- }
- })
- })
- if(already_set) {
- frappe.msgprint(__("You have already selected items from {0} {1}",
- [opts.source_doctype, opts.source_name]));
- return;
- }
+ $.each(cur_frm.doc.items, function(i, d) {
+ opts.source_name.forEach(function(src) {
+ if(d[link_fieldname]==src) {
+ already_set = true;
+ if (item_qty_map[d.item_code])
+ item_qty_map[d.item_code] += flt(d.qty);
+ else
+ item_qty_map[d.item_code] = flt(d.qty);
+ }
+ });
+ });
+
+ if(already_set) {
+ opts.source_name.forEach(function(src) {
+ frappe.model.with_doc(opts.source_doctype, src, function(r) {
+ var source_doc = frappe.model.get_doc(opts.source_doctype, src);
+ $.each(source_doc.items || [], function(i, row) {
+ if(row.qty > flt(item_qty_map[row.item_code])) {
+ already_set = false;
+ return false;
+ }
+ })
+ })
+
+ if(already_set) {
+ frappe.msgprint(__("You have already selected items from {0} {1}",
+ [opts.source_doctype, src]));
+ return;
+ }
+
+ })
}
}
-
return frappe.call({
// Sometimes we hit the limit for URL length of a GET request
// as we send the full target_doc. Hence this is a POST request.
type: "POST",
- method: opts.method,
+ method: 'frappe.model.mapper.map_docs',
args: {
- "source_name": opts.source_name,
- "target_doc": cur_frm.doc
+ "method": opts.method,
+ "source_names": opts.source_name,
+ "target_doc": cur_frm.doc,
},
callback: function(r) {
if(!r.exc) {
@@ -181,29 +186,26 @@
});
}
if(opts.source_doctype) {
- var d = new frappe.ui.Dialog({
- title: __("Get From ") + __(opts.source_doctype),
- fields: [
- {
- fieldtype: "Link",
- label: __(opts.source_doctype),
- fieldname: opts.source_doctype,
- options: opts.source_doctype,
- get_query: opts.get_query,
- reqd:1
- },
- ]
+ var d = new frappe.ui.form.MultiSelectDialog({
+ doctype: opts.source_doctype,
+ target: opts.target,
+ date_field: opts.date_field || undefined,
+ setters: opts.setters,
+ get_query: opts.get_query,
+ action: function(selections, args) {
+ let values = selections;
+ if(values.length === 0){
+ frappe.msgprint(__("Please select Quotations"))
+ return;
+ }
+ opts.source_name = values;
+ opts.setters = args;
+ d.dialog.hide();
+ _map();
+ },
});
- d.set_primary_action(__('Get Items'), function() {
- var values = d.get_values();
- if(!values)
- return;
- opts.source_name = values[opts.source_doctype];
- d.hide();
- _map();
- })
- d.show();
} else if(opts.source_name) {
+ opts.source_name = [opts.source_name];
_map();
}
}
diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less
index 0431848..f6482eb 100644
--- a/erpnext/public/less/erpnext.less
+++ b/erpnext/public/less/erpnext.less
@@ -321,6 +321,10 @@
overflow: auto;
border: 1px solid @border-color;
border-top: none;
+
+ @media (max-width: @screen-xs) {
+ height: 30vh;
+ }
}
.no-items-message {
diff --git a/erpnext/schools/doctype/program/program.json b/erpnext/schools/doctype/program/program.json
index 9d6ba1c..672994b 100644
--- a/erpnext/schools/doctype/program/program.json
+++ b/erpnext/schools/doctype/program/program.json
@@ -14,6 +14,7 @@
"engine": "InnoDB",
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -43,6 +44,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -73,6 +75,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -101,6 +104,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -130,6 +134,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -159,6 +164,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -188,6 +194,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -218,6 +225,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -247,6 +255,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -288,7 +297,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-04-12 20:40:53.542488",
+ "modified": "2017-05-12 15:39:15.542274",
"modified_by": "Administrator",
"module": "Schools",
"name": "Program",
diff --git a/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.js b/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.js
index 9c796bb..dd909b2 100644
--- a/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.js
+++ b/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.js
@@ -6,20 +6,27 @@
doc:frm.doc
})
});
-
+ frappe.realtime.on("student_group_creation_progress", function(data) {
+ if(data.progress) {
+ frappe.hide_msgprint(true);
+ frappe.show_progress(__("Creating student groups"), data.progress[0],data.progress[1]);
+ }
+ });
});
frappe.ui.form.on("Student Group Creation Tool", "get_courses", function(frm) {
frm.set_value("courses",[]);
- frappe.call({
- method: "get_courses",
- doc:frm.doc,
- callback: function(r) {
- if(r.message) {
- frm.set_value("courses", r.message);
+ if (frm.doc.academic_year && frm.doc.program) {
+ frappe.call({
+ method: "get_courses",
+ doc:frm.doc,
+ callback: function(r) {
+ if(r.message) {
+ frm.set_value("courses", r.message);
+ }
}
- }
- })
+ })
+ }
});
frappe.ui.form.on("Student Group Creation Tool", "onload", function(frm){
diff --git a/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.json b/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.json
index dd011c3..2d543ac 100644
--- a/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.json
+++ b/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.json
@@ -1,5 +1,6 @@
{
"allow_copy": 1,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -9,18 +10,23 @@
"doctype": "DocType",
"document_type": "",
"editable_grid": 0,
+ "engine": "InnoDB",
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "academic_year",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Academic Year",
"length": 0,
"no_copy": 0,
@@ -30,6 +36,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,
@@ -37,16 +44,21 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
+ "description": "Leave blank if you make students groups per year",
"fieldname": "academic_term",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Academic Term",
"length": 0,
"no_copy": 0,
@@ -56,23 +68,28 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "get_courses",
"fieldtype": "Button",
"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": "Get Courses",
"length": 0,
"no_copy": 0,
@@ -81,6 +98,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,
@@ -88,16 +106,20 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "column_break_4",
"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,
@@ -105,6 +127,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,
@@ -112,17 +135,21 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
- "description": "Leave blank if you wish to fetch all courses for selected academic term",
+ "columns": 0,
+ "description": "",
"fieldname": "program",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Program",
"length": 0,
"no_copy": 0,
@@ -132,6 +159,39 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "Leave unchecked if you don't want to consider batch while making course based groups. ",
+ "fieldname": "separate_groups",
+ "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": "Separate course based Group for every Batch",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "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,
@@ -139,16 +199,20 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "section_break_4",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -156,6 +220,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,
@@ -163,16 +228,20 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "courses",
"fieldtype": "Table",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Courses",
"length": 0,
"no_copy": 0,
@@ -182,6 +251,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,
@@ -189,17 +259,17 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 1,
"hide_toolbar": 1,
"idx": 0,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-07-25 06:40:46.107131",
+ "modified": "2017-05-15 12:43:32.317942",
"modified_by": "Administrator",
"module": "Schools",
"name": "Student Group Creation Tool",
@@ -230,7 +300,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": 1,
"track_seen": 0
}
\ No newline at end of file
diff --git a/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.py b/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.py
index 65cf755..a236508 100644
--- a/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.py
+++ b/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.py
@@ -9,40 +9,63 @@
class StudentGroupCreationTool(Document):
def get_courses(self):
- if self.program:
- courses = frappe.db.sql("""select course, course_code, parent as program, "student_group_name"
- from `tabProgram Course` where academic_term= %s and parent= %s""",
- (self.academic_term, self.program), as_dict=1)
+ group_list = []
+
+ batches = frappe.db.sql('''select name as batch from `tabStudent Batch Name`''', as_dict=1)
+ for batch in batches:
+ group_list.append({"group_based_on":"Batch", "batch":batch.batch})
+
+ courses = frappe.db.sql('''select course, course_name from `tabProgram Course` where parent=%s''',
+ (self.program), as_dict=1)
+ if self.separate_groups:
+ from itertools import product
+ course_list = product(courses,batches)
+ for course in course_list:
+ temp_dict = {}
+ temp_dict.update({"group_based_on":"Course"})
+ temp_dict.update(course[0])
+ temp_dict.update(course[1])
+ group_list.append(temp_dict)
else:
- courses = frappe.db.sql("""select course, course_code, parent as program, "student_group_name"
- from `tabProgram Course` where academic_term= %s""",
- self.academic_term, as_dict=1)
+ for course in courses:
+ course.update({"group_based_on":"Course"})
+ group_list.append(course)
- for d in courses:
- if d.course_code:
- d.student_group_name = d.course_code + "-" + self.academic_year
- else:
- d.student_group_name = None
+ for group in group_list:
+ if group.get("group_based_on") == "Batch":
+ student_group_name = self.program + "/" + group.get("batch") + "/" + (self.academic_term if self.academic_term else self.academic_year)
+ group.update({"student_group_name": student_group_name})
+ elif group.get("group_based_on") == "Course":
+ student_group_name = group.get("course") + "/" + self.program + ("/" + group.get("batch") if group.get("batch") else "") + "/" + (self.academic_term if self.academic_term else self.academic_year)
+ group.update({"student_group_name": student_group_name})
- return courses
+ return group_list
def create_student_groups(self):
if not self.courses:
frappe.throw(_("""No Student Groups created."""))
+ l = len(self.courses)
for d in self.courses:
- if not d.course:
- frappe.throw(_("""Course is mandatory in row {0}""".format(d.idx)))
-
if not d.student_group_name:
frappe.throw(_("""Student Group Name is mandatory in row {0}""".format(d.idx)))
+ if d.group_based_on == "Course" and not d.course:
+ frappe.throw(_("""Course is mandatory in row {0}""".format(d.idx)))
+
+ if d.group_based_on == "Batch" and not d.batch:
+ frappe.throw(_("""Batch is mandatory in row {0}""".format(d.idx)))
+
+ frappe.publish_realtime('student_group_creation_progress', {"progress": [d.idx, l]}, user=frappe.session.user)
+
student_group = frappe.new_doc("Student Group")
- student_group.group_name = d.student_group_name
+ student_group.student_group_name = d.student_group_name
+ student_group.group_based_on = d.group_based_on
+ student_group.program = self.program
student_group.course = d.course
- student_group.max_strength = d.max_strength
+ student_group.batch = d.batch
student_group.academic_term = self.academic_term
student_group.academic_year = self.academic_year
student_group.save()
- frappe.msgprint(_("Student Groups created."))
+ frappe.msgprint(_("{0} Student Groups created.".format(l)))
diff --git a/erpnext/schools/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json b/erpnext/schools/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json
index 88466b6..d945d4b 100644
--- a/erpnext/schools/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json
+++ b/erpnext/schools/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -9,18 +10,54 @@
"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": "group_based_on",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Group Based On",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nBatch\nCourse",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "course",
"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": "Course",
"length": 0,
"no_copy": 0,
@@ -30,32 +67,7 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
- "report_hide": 0,
- "reqd": 1,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "fieldname": "course_code",
- "fieldtype": "Read Only",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "label": "Course Code",
- "length": 0,
- "no_copy": 0,
- "options": "course.course_code",
- "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,
@@ -63,16 +75,51 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
+ "fieldname": "batch",
+ "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": "Batch",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student Batch Name",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
+ "in_global_search": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -80,6 +127,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,
@@ -87,16 +135,20 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "student_group_name",
"fieldtype": "Data",
"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": "Student Group Name",
"length": 0,
"no_copy": 0,
@@ -105,6 +157,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,
@@ -112,16 +165,51 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
+ "fieldname": "course_code",
+ "fieldtype": "Read Only",
+ "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": "Course Code",
+ "length": 0,
+ "no_copy": 0,
+ "options": "course.course_name",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "max_strength",
"fieldtype": "Int",
"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": "Max Strength",
"length": 0,
"no_copy": 0,
@@ -130,6 +218,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,
@@ -137,17 +226,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-07-25 06:40:49.000588",
+ "modified": "2017-05-15 14:18:23.435415",
"modified_by": "Administrator",
"module": "Schools",
"name": "Student Group Creation Tool Course",
@@ -157,7 +246,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": 1,
"track_seen": 0
}
\ No newline at end of file
diff --git a/erpnext/schools/report/student_batch_wise_attendance/student_batch_wise_attendance.py b/erpnext/schools/report/student_batch_wise_attendance/student_batch_wise_attendance.py
index ddb4889..646e3f7 100644
--- a/erpnext/schools/report/student_batch_wise_attendance/student_batch_wise_attendance.py
+++ b/erpnext/schools/report/student_batch_wise_attendance/student_batch_wise_attendance.py
@@ -38,7 +38,7 @@
def get_columns(filters):
columns = [
- _("Student Group") + ":Link/Student Batch:250",
+ _("Student Group") + ":Link/Student Group:250",
_("Student Group Strength") + "::170",
_("Present") + "::90",
_("Absent") + "::90",
diff --git a/erpnext/selling/doctype/installation_note/installation_note.js b/erpnext/selling/doctype/installation_note/installation_note.js
index d4b2179..9aff74a 100644
--- a/erpnext/selling/doctype/installation_note/installation_note.js
+++ b/erpnext/selling/doctype/installation_note/installation_note.js
@@ -42,18 +42,23 @@
},
refresh: function() {
+ var me = this;
if (this.frm.doc.docstatus===0) {
- cur_frm.add_custom_button(__('From Delivery Note'),
+ this.frm.add_custom_button(__('From Delivery Note'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.stock.doctype.delivery_note.delivery_note.make_installation_note",
source_doctype: "Delivery Note",
+ target: me.frm,
+ date_field: "posting_date",
+ setters: {
+ customer: me.frm.doc.customer || undefined,
+ },
get_query_filters: {
docstatus: 1,
status: ["not in", ["Stopped", "Closed"]],
per_installed: ["<", 99.99],
- customer: cur_frm.doc.customer || undefined,
- company: cur_frm.doc.company
+ company: me.frm.doc.company
}
})
}, "fa fa-download", "btn-default"
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index 9c37365..940daaa 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -25,6 +25,8 @@
refresh: function(doc, dt, dn) {
this._super(doc, dt, dn);
+ var me = this;
+
if(doc.docstatus == 1 && doc.status!=='Lost') {
cur_frm.add_custom_button(__('Make Sales Order'),
cur_frm.cscript['Make Sales Order']);
@@ -36,17 +38,24 @@
}
if (this.frm.doc.docstatus===0) {
- cur_frm.add_custom_button(__('Opportunity'),
+ this.frm.add_custom_button(__('Opportunity'),
function() {
+ var setters = {};
+ if(me.frm.doc.customer) {
+ setters.customer = me.frm.doc.customer || undefined;
+ } else if (me.frm.doc.lead) {
+ setters.lead = me.frm.doc.lead || undefined;
+ }
erpnext.utils.map_current_doc({
method: "erpnext.crm.doctype.opportunity.opportunity.make_quotation",
source_doctype: "Opportunity",
+ target: me.frm,
+ setters: setters,
get_query_filters: {
status: ["not in", ["Lost", "Closed"]],
- enquiry_type: cur_frm.doc.order_type,
- customer: cur_frm.doc.customer || undefined,
- lead: cur_frm.doc.lead || undefined,
- company: cur_frm.doc.company
+ company: me.frm.doc.company,
+ // cannot set enquiry_type as setter, as the fieldname is order_type
+ enquiry_type: me.frm.doc.order_type,
}
})
}, __("Get items from"), "btn-default");
diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json
index ee194f3..2f2a7ed 100644
--- a/erpnext/selling/doctype/quotation/quotation.json
+++ b/erpnext/selling/doctype/quotation/quotation.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
"autoname": "naming_series:",
@@ -12,6 +13,7 @@
"editable_grid": 1,
"fields": [
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -41,6 +43,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -71,6 +74,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -102,6 +106,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -134,6 +139,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -166,6 +172,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -198,6 +205,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -226,6 +234,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -255,6 +264,7 @@
"width": "50%"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -287,6 +297,7 @@
"width": "150px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -320,6 +331,7 @@
"width": "150px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -352,6 +364,7 @@
"width": "100px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -384,6 +397,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -415,6 +429,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -444,6 +459,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -474,6 +490,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -506,6 +523,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -534,6 +552,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -562,6 +581,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -591,6 +611,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -620,6 +641,7 @@
"width": "50%"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -649,6 +671,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -677,6 +700,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -710,6 +734,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -740,6 +765,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -769,6 +795,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -801,6 +828,7 @@
"width": "100px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -834,6 +862,7 @@
"width": "100px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -862,6 +891,7 @@
"width": "50%"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -894,6 +924,7 @@
"width": "100px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -923,6 +954,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -953,6 +985,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -981,6 +1014,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1011,6 +1045,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1036,13 +1071,14 @@
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 0,
+ "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "40px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1070,6 +1106,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1100,6 +1137,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1132,6 +1170,7 @@
"width": "100px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1159,6 +1198,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1189,6 +1229,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1218,6 +1259,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1248,6 +1290,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1279,6 +1322,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1306,6 +1350,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1336,6 +1381,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1363,6 +1409,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1394,6 +1441,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1423,6 +1471,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1450,6 +1499,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1481,6 +1531,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1508,6 +1559,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1537,6 +1589,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1567,6 +1620,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1598,6 +1652,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1628,6 +1683,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1656,6 +1712,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1685,6 +1742,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1714,6 +1772,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1744,6 +1803,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1776,6 +1836,7 @@
"width": "200px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1808,6 +1869,7 @@
"width": "200px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1840,6 +1902,7 @@
"width": "200px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1869,6 +1932,7 @@
"width": "50%"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1901,6 +1965,7 @@
"width": "200px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
@@ -1933,6 +1998,7 @@
"width": "200px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1964,6 +2030,7 @@
"width": "200px"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -1995,6 +2062,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2026,6 +2094,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2056,6 +2125,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -2085,6 +2155,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -2116,6 +2187,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -2147,6 +2219,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2175,6 +2248,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2204,6 +2278,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
@@ -2234,6 +2309,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2265,6 +2341,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2296,6 +2373,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -2327,6 +2405,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2356,6 +2435,7 @@
"width": "50%"
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2388,6 +2468,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2418,6 +2499,7 @@
"unique": 0
},
{
+ "allow_bulk_edit": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -2448,19 +2530,19 @@
"unique": 0
}
],
+ "has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "fa fa-shopping-cart",
"idx": 82,
"image_view": 0,
"in_create": 0,
- "in_dialog": 0,
"is_submittable": 1,
"issingle": 0,
"istable": 0,
"max_attachments": 1,
"menu_index": 0,
- "modified": "2017-02-20 13:22:18.466192",
+ "modified": "2017-05-15 13:05:39.469590",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index d32fe77..b5b24f8 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -102,7 +102,7 @@
target.run_method("calculate_taxes_and_totals")
def update_item(obj, target, source_parent):
- target.stock_qty = flt(obj.qty) * flt(obj.conversion_factor)
+ target.stock_qty = flt(obj.qty) * flt(obj.conversion_factor)
doclist = get_mapped_doc("Quotation", source_name, {
"Quotation": {
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 0175976..5a4de0b 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -136,12 +136,15 @@
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.quotation.quotation.make_sales_order",
source_doctype: "Quotation",
+ target: me.frm,
+ setters: {
+ customer: me.frm.doc.customer || undefined,
+ order_type: me.frm.doc.order_type,
+ },
get_query_filters: {
+ company: me.frm.doc.company,
docstatus: 1,
status: ["!=", "Lost"],
- order_type: me.frm.doc.order_type,
- customer: me.frm.doc.customer || undefined,
- company: me.frm.doc.company
}
})
}, __("Get items from"));
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index c18ae0c..0417e5e 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -529,8 +529,8 @@
"item_code": args.item or args.item_code or "_Test Item",
"warehouse": args.warehouse,
"qty": args.qty or 10,
- "rate": args.rate or 100,
- "conversion_factor": 1.0,
+ "uom": args.uom or None,
+ "rate": args.rate or 100
})
if not args.do_not_save:
diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.js b/erpnext/selling/page/sales_funnel/sales_funnel.js
index 67ba1c8..e37e88d 100644
--- a/erpnext/selling/page/sales_funnel/sales_funnel.js
+++ b/erpnext/selling/page/sales_funnel/sales_funnel.js
@@ -163,6 +163,10 @@
draw_legend: function(x_mid, y_mid, width, height, title) {
var context = this.elements.context;
+ if(y_mid == 0) {
+ y_mid = 7;
+ }
+
// draw line
context.beginPath();
context.moveTo(x_mid, y_mid);
diff --git a/erpnext/setup/doctype/naming_series/naming_series.py b/erpnext/setup/doctype/naming_series/naming_series.py
index d6e7ea7..536b72f 100644
--- a/erpnext/setup/doctype/naming_series/naming_series.py
+++ b/erpnext/setup/doctype/naming_series/naming_series.py
@@ -8,6 +8,7 @@
from frappe import msgprint, throw, _
from frappe.model.document import Document
+from frappe.model.naming import parse_naming_series
from frappe.permissions import get_doctypes_with_read
class NamingSeriesNotSetError(frappe.ValidationError): pass
@@ -136,8 +137,9 @@
def get_current(self, arg=None):
"""get series current"""
if self.prefix:
+ prefix = self.parse_naming_series()
self.current_value = frappe.db.get_value("Series",
- self.prefix.split('.')[0], "current", order_by = "name")
+ prefix, "current", order_by = "name")
def insert_series(self, series):
"""insert series if missing"""
@@ -146,7 +148,7 @@
def update_series_start(self):
if self.prefix:
- prefix = self.prefix.split('.')[0]
+ prefix = self.parse_naming_series()
self.insert_series(prefix)
frappe.db.sql("update `tabSeries` set current = %s where name = %s",
(self.current_value, prefix))
@@ -154,6 +156,17 @@
else:
msgprint(_("Please select prefix first"))
+ def parse_naming_series(self):
+ parts = self.prefix.split('.')
+ # If series contain date format like INV.YYYY.MM.#####
+ if len(parts) > 2:
+ del parts[-1] # Removed ### from the series
+ prefix = parse_naming_series(parts)
+ else:
+ prefix = parts[0]
+
+ return prefix
+
def set_by_naming_series(doctype, fieldname, naming_series, hide_name_field=True):
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
if naming_series:
diff --git a/erpnext/setup/doctype/territory/territory.json b/erpnext/setup/doctype/territory/territory.json
index 030f936..b123d5e 100644
--- a/erpnext/setup/doctype/territory/territory.json
+++ b/erpnext/setup/doctype/territory/territory.json
@@ -79,7 +79,7 @@
"bold": 1,
"collapsible": 0,
"columns": 0,
- "description": "Only leaf nodes are allowed in transaction",
+ "description": "",
"fieldname": "is_group",
"fieldtype": "Check",
"hidden": 0,
@@ -478,4 +478,4 @@
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 5236031..eb8a750 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -119,13 +119,16 @@
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note",
source_doctype: "Sales Order",
+ target: me.frm,
+ setters: {
+ customer: me.frm.doc.customer || undefined,
+ },
get_query_filters: {
docstatus: 1,
status: ["!=", "Closed"],
per_delivered: ["<", 99.99],
+ company: me.frm.doc.company,
project: me.frm.doc.project || undefined,
- customer: me.frm.doc.customer || undefined,
- company: me.frm.doc.company
}
})
}, __("Get items from"));
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 3402619..460f1c3 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -65,7 +65,8 @@
frm.page.set_inner_btn_group_as_primary(__("Make"));
}
if (frm.doc.variant_of) {
- frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set", [frm.doc.variant_of]), true);
+ frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set",
+ [frm.doc.variant_of]), true);
}
if (frappe.defaults.get_default("item_naming_by")!="Naming Series" || frm.doc.variant_of) {
@@ -96,6 +97,8 @@
}
frappe.set_route('Form', 'Item', new_item.name);
});
+
+ frm.trigger('make_variant_fields_read_only');
},
validate: function(frm){
@@ -106,6 +109,16 @@
refresh_field("image_view");
},
+ make_variant_fields_read_only: function(frm) {
+ if(frm.doc.variant_of) {
+ frm.meta.fields.forEach(function(df) {
+ if (!df.no_copy) {
+ frm.toggle_enable(df.fieldname, false);
+ }
+ });
+ }
+ },
+
is_fixed_asset: function(frm) {
if (frm.doc.is_fixed_asset) {
frm.set_value("is_stock_item", 0);
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index d42e60d..25f3055 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -519,6 +519,39 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval:!doc.__islocal",
+ "description": "",
+ "fieldname": "tolerance",
+ "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": "Allow over delivery or receipt upto this percent",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "tolerance",
+ "oldfieldtype": "Currency",
+ "permlevel": 0,
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 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": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@@ -807,39 +840,6 @@
"collapsible": 0,
"columns": 0,
"depends_on": "is_stock_item",
- "description": "",
- "fieldname": "tolerance",
- "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": "Allow over delivery or receipt upto this percent",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "tolerance",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "is_stock_item",
"fieldname": "valuation_method",
"fieldtype": "Select",
"hidden": 0,
@@ -3143,7 +3143,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
- "modified": "2017-05-03 09:55:11.624283",
+ "modified": "2017-05-15 11:49:47.525859",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index f864171..ef85dd9 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -86,6 +86,7 @@
self.validate_has_variants()
self.validate_attributes()
self.validate_variant_attributes()
+ self.copy_variant_attributes()
self.validate_website_image()
self.make_thumbnail()
self.validate_fixed_asset()
@@ -616,7 +617,9 @@
template_item.save()
def update_variants(self):
- if self.has_variants and not self.flags.dont_update_variants:
+ if self.flags.dont_update_variants:
+ return
+ if self.has_variants:
updated = []
variants = frappe.db.get_all("Item", fields=["item_code"], filters={"variant_of": self.name })
for d in variants:
@@ -625,7 +628,7 @@
variant.save()
updated.append(d.item_code)
if updated:
- frappe.msgprint(_("Item Variants {0} updated").format(", ".join(updated)))
+ frappe.msgprint(_("Item Variants {0} updated").format(", ".join(updated)))
def validate_has_variants(self):
if not self.has_variants and frappe.db.get_value("Item", self.name, "has_variants"):
@@ -670,6 +673,12 @@
validate_item_variant_attributes(self, args)
+ def copy_variant_attributes(self):
+ '''Copy attributes from template (if they have been changed before saving)'''
+ if self.variant_of:
+ template = frappe.get_doc('Item', self.variant_of)
+ copy_attributes_to_variant(template, self)
+
def get_timeline_data(doctype, name):
'''returns timeline data based on stock ledger entry'''
out = {}
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index be0b4c2..58c16e1 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -95,16 +95,19 @@
}
if (this.frm.doc.docstatus===0) {
- cur_frm.add_custom_button(__('Sales Order'),
+ this.frm.add_custom_button(__('Sales Order'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.selling.doctype.sales_order.sales_order.make_material_request",
source_doctype: "Sales Order",
+ target: me.frm,
+ setters: {
+ company: me.frm.doc.company
+ },
get_query_filters: {
docstatus: 1,
status: ["!=", "Closed"],
per_delivered: ["<", 99.99],
- company: cur_frm.doc.company
}
})
}, __("Get items from"));
diff --git a/erpnext/stock/doctype/price_list/price_list.js b/erpnext/stock/doctype/price_list/price_list.js
index 23ac6fd..c362b5a 100644
--- a/erpnext/stock/doctype/price_list/price_list.js
+++ b/erpnext/stock/doctype/price_list/price_list.js
@@ -1,13 +1,14 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-$.extend(cur_frm.cscript, {
- refresh: function() {
- cur_frm.add_custom_button(__("Add / Edit Prices"), function() {
+frappe.ui.form.on("Price List", {
+ refresh: function(frm) {
+ let me = this;
+ frm.add_custom_button(__("Add / Edit Prices"), function() {
frappe.route_options = {
- "price_list": cur_frm.doc.name
+ "price_list": frm.doc.name
};
frappe.set_route("Report", "Item Price");
}, "fa fa-money");
}
-});
+});
\ No newline at end of file
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 383de01..5c97e7c 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -43,6 +43,7 @@
},
refresh: function() {
+ var me = this;
this._super();
if(this.frm.doc.docstatus===1) {
this.show_stock_ledger();
@@ -53,17 +54,20 @@
if(!this.frm.doc.is_return && this.frm.doc.status!="Closed") {
if(this.frm.doc.docstatus==0) {
- cur_frm.add_custom_button(__('Purchase Order'),
+ this.frm.add_custom_button(__('Purchase Order'),
function() {
erpnext.utils.map_current_doc({
method: "erpnext.buying.doctype.purchase_order.purchase_order.make_purchase_receipt",
source_doctype: "Purchase Order",
+ target: me.frm,
+ setters: {
+ supplier: me.frm.doc.supplier || undefined,
+ },
get_query_filters: {
- supplier: cur_frm.doc.supplier || undefined,
docstatus: 1,
status: ["!=", "Closed"],
per_received: ["<", 99.99],
- company: cur_frm.doc.company
+ company: me.frm.doc.company
}
})
}, __("Get items from"));
diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py
index b94061c..944f978 100644
--- a/erpnext/utilities/__init__.py
+++ b/erpnext/utilities/__init__.py
@@ -2,6 +2,7 @@
import frappe
from erpnext.utilities.activation import get_level
+from frappe.utils import cstr
def update_doctypes():
for d in frappe.db.sql("""select df.parent, df.fieldname
@@ -26,7 +27,7 @@
company = company[0][0] if company else None
if company:
- domain = frappe.db.get_value('Company', company, 'domain')
+ domain = frappe.db.get_value('Company', cstr(company), 'domain')
return {
'company': company,
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 9a25b76..7657188 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -18,6 +18,10 @@
frappe.db.get_value("Notification Control", None, dt + "_message"))
def validate_posting_time(self):
+ # set Edit Posting Date and Time to 1 while data import
+ if frappe.flags.in_import:
+ self.set_posting_time = 1
+
if not getattr(self, 'set_posting_time', None):
now = now_datetime()
self.posting_date = now.strftime('%Y-%m-%d')