Merge branch 'master' into develop
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index c4f275a..757daa0 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -4,7 +4,7 @@
import frappe
import unittest, copy
-from frappe.utils import nowdate, add_days, flt, nowdate
+from frappe.utils import nowdate, add_days, flt
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
@@ -162,11 +162,50 @@
self.assertEquals(si.base_grand_total, 1628)
self.assertEquals(si.grand_total, 32.56)
+ def test_sales_invoice_with_discount_and_inclusive_tax(self):
+ si = create_sales_invoice(qty=100, rate=50, do_not_save=True)
+ si.append("taxes", {
+ "charge_type": "On Net Total",
+ "account_head": "_Test Account Service Tax - _TC",
+ "cost_center": "_Test Cost Center - _TC",
+ "description": "Service Tax",
+ "rate": 14,
+ 'included_in_print_rate': 1
+ })
+ si.insert()
+
+ # with inclusive tax
+ self.assertEquals(si.net_total, 4385.96)
+ self.assertEquals(si.grand_total, 5000)
+
+ si.reload()
+
+ # additional discount
+ si.discount_amount = 100
+ si.apply_discount_on = 'Net Total'
+
+ si.save()
+
+ # with inclusive tax and additional discount
+ self.assertEquals(si.net_total, 4285.96)
+ self.assertEquals(si.grand_total, 4885.99)
+
+ si.reload()
+
+ # additional discount on grand total
+ si.discount_amount = 100
+ si.apply_discount_on = 'Grand Total'
+
+ si.save()
+
+ # with inclusive tax and additional discount
+ self.assertEquals(si.net_total, 4298.24)
+ self.assertEquals(si.grand_total, 4900.00)
+
def test_sales_invoice_discount_amount(self):
si = frappe.copy_doc(test_records[3])
si.discount_amount = 104.95
si.append("taxes", {
- "doctype": "Sales Taxes and Charges",
"charge_type": "On Previous Row Amount",
"account_head": "_Test Account Service Tax - _TC",
"cost_center": "_Test Cost Center - _TC",
@@ -961,7 +1000,7 @@
pe.submit()
self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Active')
-
+
def test_outstanding_amount_after_advance_jv_cancelation(self):
from erpnext.accounts.doctype.journal_entry.test_journal_entry \
import test_records as jv_test_records
@@ -986,15 +1025,15 @@
#check outstanding after advance allocation
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total - si.total_advance, si.precision("outstanding_amount")))
-
+
#added to avoid Document has been modified exception
jv = frappe.get_doc("Journal Entry", jv.name)
jv.cancel()
-
+
si.load_from_db()
#check outstanding after advance cancellation
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total + si.total_advance, si.precision("outstanding_amount")))
-
+
def test_outstanding_amount_after_advance_payment_entry_cancelation(self):
pe = frappe.get_doc({
"doctype": "Payment Entry",
@@ -1015,7 +1054,7 @@
})
pe.insert()
pe.submit()
-
+
si = frappe.copy_doc(test_records[0])
si.is_pos = 0
si.append("advances", {
@@ -1028,16 +1067,16 @@
})
si.insert()
si.submit()
-
+
si.load_from_db()
#check outstanding after advance allocation
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total - si.total_advance, si.precision("outstanding_amount")))
-
+
#added to avoid Document has been modified exception
pe = frappe.get_doc("Payment Entry", pe.name)
pe.cancel()
-
+
si.load_from_db()
#check outstanding after advance cancellation
self.assertEqual(flt(si.outstanding_amount), flt(si.grand_total + si.total_advance, si.precision("outstanding_amount")))
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index a4078bd..bd9d8ed 100644
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -297,6 +297,8 @@
this.print_template = r.message.print_template;
this.pos_profile_data = r.message.pos_profile;
this.default_customer = r.message.default_customer || null;
+ this.print_settings = locals[":Print Settings"]["Print Settings"];
+ this.letter_head = (this.pos_profile_data.length > 0) ? frappe.boot.letter_heads[this.pos_profile_data[letter_head]] : {};
},
save_previous_entry : function(){
@@ -327,9 +329,9 @@
frappe.meta.sync(data)
})
- this.print_template_data = frappe.render_template("print_template",
- {content: this.print_template, title:"POS",
- base_url: frappe.urllib.get_base_url(), print_css: frappe.boot.print_css})
+ this.print_template_data = frappe.render_template("print_template", {content: this.print_template,
+ title:"POS", base_url: frappe.urllib.get_base_url(), print_css: frappe.boot.print_css,
+ print_settings: this.print_settings, header: this.letter_head.header, footer: this.letter_head.footer})
},
setup: function(){
@@ -408,33 +410,37 @@
this.frm.doc.customer = this.default_customer;
}
- this.party_field.$input.autocomplete({
- autoFocus: true,
- source: function (request, response) {
- me.customer_data = me.get_customers(request.term)
- response($.map(me.customer_data, function(data){
+ this.party_field.awesomeplete = new Awesomplete(this.party_field.$input.get(0), {
+ minChars: 0,
+ maxItems: 99,
+ autoFirst: true,
+ list: [],
+ });
+
+ this.party_field.$input
+ .on('input', function(e) {
+ var customer_data = me.get_customers(e.target.value) || [];
+ me.party_field.awesomeplete.list = customer_data.map(function(data){
return {label: data.name, value: data.name,
customer_group: data.customer_group, territory: data.territory}
- }))
- },
- change: function(event, ui){
- if(ui.item){
- me.frm.doc.customer = ui.item.label;
- me.frm.doc.customer_name = ui.item.customer_name;
- me.frm.doc.customer_group = ui.item.customer_group;
- me.frm.doc.territory = ui.item.territory;
- }else{
+ });
+ })
+ .on('awesomplete-select', function(e) {
+ var item = me.party_field.awesomeplete.get_item(e.originalEvent.text.value);
+ console.log(item);
+ if(item) {
+ me.frm.doc.customer = item.label;
+ me.frm.doc.customer_name = item.customer_name;
+ me.frm.doc.customer_group = item.customer_group;
+ me.frm.doc.territory = item.territory;
+ } else {
me.frm.doc.customer = me.party_field.$input.val();
}
me.refresh();
- }
- }).on("focus", function(){
- setTimeout(function() {
- if(!me.party_field.$input.val()) {
- me.party_field.$input.autocomplete( "search", " " );
- }
- }, 500);
- });
+ })
+ .on('focus', function(e) {
+ $(e.target).val('').trigger('input');
+ });
},
get_customers: function(key){
@@ -568,7 +574,7 @@
me.update_qty(item_code, qty)
})
},
-
+
update_qty: function(item_code, qty) {
var me = this;
this.items = this.get_items(item_code);
@@ -1010,13 +1016,13 @@
frappe.throw(__("Select items to save the invoice"))
}
},
-
+
validate_mode_of_payments: function(){
if (this.frm.doc.payments.length === 0){
frappe.throw(__("Payment Mode is not configured. Please check, whether account has been set on Mode of Payments or on POS Profile."))
}
},
-
+
validate_serial_no: function(){
var me = this;
var item_code = serial_no = '';
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 0fca7dc..dc79d1f 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -80,13 +80,6 @@
"fieldname":"group_by_account",
"label": __("Group by Account"),
"fieldtype": "Check",
- },
- {
- "fieldname":"letter_head",
- "label": __("Letter Head"),
- "fieldtype": "Link",
- "options": "Letter Head",
- "default": frappe.defaults.get_default("letter_head"),
}
]
}
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py
index ba09d3f..9582523 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation_dashboard.py
@@ -6,7 +6,6 @@
'fieldname': 'request_for_quotation',
'transactions': [
{
- 'label': _('Related'),
'items': ['Supplier Quotation']
},
]
diff --git a/erpnext/config/schools.py b/erpnext/config/schools.py
index 1d33d4d..366810d 100644
--- a/erpnext/config/schools.py
+++ b/erpnext/config/schools.py
@@ -6,13 +6,16 @@
{
"label": _("Student"),
"items": [
-
{
"type": "doctype",
"name": "Student"
},
{
"type": "doctype",
+ "name": "Guardian"
+ },
+ {
+ "type": "doctype",
"name": "Student Log"
},
{
diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py
index 3ca424d..14e7999 100644
--- a/erpnext/config/stock.py
+++ b/erpnext/config/stock.py
@@ -264,6 +264,12 @@
{
"type": "report",
"is_query_report": True,
+ "name": "Batch Item Expiry Status",
+ "doctype": "Stock Ledger Entry"
+ },
+ {
+ "type": "report",
+ "is_query_report": True,
"name": "Item Prices",
"doctype": "Price List"
},
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 2369143..e9cef88 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -366,8 +366,9 @@
# discount amount rounding loss adjustment if no taxes
if (not taxes or self.doc.apply_discount_on == "Net Total") \
and i == len(self.doc.get("items")) - 1:
- discount_amount_loss = flt(self.doc.total - net_total - self.doc.discount_amount,
+ discount_amount_loss = flt(self.doc.net_total - net_total - self.doc.discount_amount,
self.doc.precision("net_total"))
+
item.net_amount = flt(item.net_amount + discount_amount_loss,
item.precision("net_amount"))
@@ -452,7 +453,7 @@
elif self.doc.doctype == "Purchase Invoice":
self.doc.outstanding_amount = flt(total_amount_to_pay, self.doc.precision("outstanding_amount"))
-
+
def calculate_paid_amount(self):
paid_amount = base_paid_amount = 0.0
for payment in self.doc.get('payments'):
@@ -467,7 +468,7 @@
self.doc.change_amount = 0.0
self.doc.base_change_amount = 0.0
if self.doc.paid_amount > self.doc.grand_total:
- self.doc.change_amount = flt(self.doc.paid_amount - self.doc.grand_total +
+ self.doc.change_amount = flt(self.doc.paid_amount - self.doc.grand_total +
self.doc.write_off_amount, self.doc.precision("change_amount"))
self.doc.base_change_amount = flt(self.doc.base_paid_amount - self.doc.base_grand_total +
@@ -483,7 +484,7 @@
def calculate_margin(self, item):
total_margin = 0.0
if item.price_list_rate:
- if item.pricing_rule and not self.doc.ignore_pricing_rule:
+ if item.pricing_rule and not self.doc.ignore_pricing_rule:
pricing_rule = frappe.get_doc('Pricing Rule', item.pricing_rule)
item.margin_type = pricing_rule.margin_type
item.margin_rate_or_amount = pricing_rule.margin_rate_or_amount
@@ -492,4 +493,4 @@
margin_value = item.margin_rate_or_amount if item.margin_type == 'Amount' else flt(item.price_list_rate) * flt(item.margin_rate_or_amount) / 100
total_margin = flt(item.price_list_rate) + flt(margin_value)
- return total_margin
+ return total_margin
diff --git a/erpnext/crm/doctype/lead/lead_dashboard.py b/erpnext/crm/doctype/lead/lead_dashboard.py
new file mode 100644
index 0000000..b87fc0e
--- /dev/null
+++ b/erpnext/crm/doctype/lead/lead_dashboard.py
@@ -0,0 +1,11 @@
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'lead',
+ 'transactions': [
+ {
+ 'items': ['Opportunity', 'Quotation']
+ },
+ ]
+ }
\ No newline at end of file
diff --git a/erpnext/crm/doctype/opportunity/opportunity_dashboard.py b/erpnext/crm/doctype/opportunity/opportunity_dashboard.py
index 40ff6d0..1939c2e 100644
--- a/erpnext/crm/doctype/opportunity/opportunity_dashboard.py
+++ b/erpnext/crm/doctype/opportunity/opportunity_dashboard.py
@@ -8,7 +8,6 @@
},
'transactions': [
{
- 'label': _('Related'),
'items': ['Quotation', 'Supplier Quotation']
},
]
diff --git a/erpnext/docs/user/manual/en/selling/articles/drop-shipping.md b/erpnext/docs/user/manual/en/selling/articles/drop-shipping.md
index 6d58e2c..2d12ff4 100644
--- a/erpnext/docs/user/manual/en/selling/articles/drop-shipping.md
+++ b/erpnext/docs/user/manual/en/selling/articles/drop-shipping.md
@@ -13,7 +13,7 @@
<img class="screenshot" alt="Setup Item Master" src="{{docs_base_url}}/assets/img/selling/setup-drop-ship-on-item-master.png">
#### Setup on Sales Order
-If Drop Shipping has set on Item master, it will automatically set **Supplier delivers to Customer** and **Supplier** on Salse Order Item.
+If Drop Shipping has set on Item master, it will automatically set **Supplier delivers to Customer** and **Supplier** on Sales Order Item.
You can setup Drop Shipping, on Sales Order Item. Under **Drop Ship** section, set **Supplier delivers to Customer** and select **Supplier** agaist which Purchase Order will get created.
diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js
index fe83f40..c24a6bc 100755
--- a/erpnext/hr/doctype/employee/employee.js
+++ b/erpnext/hr/doctype/employee/employee.js
@@ -48,8 +48,8 @@
});
frappe.ui.form.on('Employee',{
- prefered_contact_email:function(frm){
- frm.events.update_contact(frm)
+ prefered_contact_email:function(frm){
+ frm.events.update_contact(frm)
},
personal_email:function(frm){
frm.events.update_contact(frm)
@@ -74,5 +74,19 @@
}
});
},
+ create_user: function(frm) {
+ if (!frm.doc.prefered_email)
+ {
+ frappe.throw(__("Please enter Preferred Contact Email"))
+ }
+ frappe.call({
+ method: "erpnext.hr.doctype.employee.employee.create_user",
+ args: { employee: cur_frm.doc.name },
+ callback: function(r)
+ {
+ frm.set_value("user_id", r.message)
+ }
+ });
+ }
});
cur_frm.cscript = new erpnext.hr.EmployeeController({frm: cur_frm});
diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json
index 5ded5a0..62ca61c 100644
--- a/erpnext/hr/doctype/employee/employee.json
+++ b/erpnext/hr/doctype/employee/employee.json
@@ -217,6 +217,35 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "eval:(!doc.user_id)",
+ "fieldname": "create_user",
+ "fieldtype": "Button",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Create User",
+ "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": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "image",
"fieldtype": "Attach Image",
"hidden": 1,
@@ -2244,7 +2273,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-11-07 05:15:16.925799",
+ "modified": "2016-12-19 17:24:22.941738",
"modified_by": "Administrator",
"module": "HR",
"name": "Employee",
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 58d1262..881853d 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -6,7 +6,7 @@
from frappe.utils import getdate, validate_email_add, today, add_years
from frappe.model.naming import make_autoname
-from frappe import throw, _
+from frappe import throw, _, scrub
import frappe.permissions
from frappe.model.document import Document
from erpnext.utilities.transaction_base import delete_events
@@ -39,6 +39,7 @@
self.validate_status()
self.validate_employee_leave_approver()
self.validate_reports_to()
+ self.validate_prefered_email()
if self.user_id:
self.validate_for_enabled_user_id()
@@ -153,6 +154,11 @@
def on_trash(self):
delete_events(self.doctype, self.name)
+ def validate_prefered_email(self):
+ if not self.get(scrub(self.prefered_contact_email)):
+ frappe.msgprint(_("Please enter " + self.prefered_contact_email))
+
+
def get_timeline_data(doctype, name):
'''Return timeline for attendance'''
return dict(frappe.db.sql('''select unix_timestamp(att_date), count(*)
@@ -250,3 +256,34 @@
sales_person = frappe.db.get_value("Sales Person", {"Employee": employee})
if sales_person:
frappe.db.set_value("Sales Person", sales_person, "enabled", 0)
+
+@frappe.whitelist()
+def create_user(employee, user = None):
+ emp = frappe.get_doc("Employee", employee)
+
+ employee_name = emp.employee_name.split(" ")
+ middle_name = last_name = ""
+
+ if len(employee_name) >= 3:
+ last_name = " ".join(employee_name[2:])
+ middle_name = employee_name[1]
+ elif len(employee_name) == 2:
+ last_name = employee_name[1]
+
+ first_name = employee_name[0]
+
+ user = frappe.new_doc("User")
+ user.update({
+ "name": emp.employee_name,
+ "email": emp.prefered_email,
+ "enabled": 1,
+ "first_name": first_name,
+ "middle_name": middle_name,
+ "last_name": last_name,
+ "gender": emp.gender,
+ "birth_date": emp.date_of_birth,
+ "phone": emp.cell_number,
+ "bio": emp.bio
+ })
+ user.insert()
+ return user.name
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.json b/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.json
index 2225496..43f79c9 100644
--- a/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.json
+++ b/erpnext/manufacturing/doctype/production_plan_sales_order/production_plan_sales_order.json
@@ -50,7 +50,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
- "label": "Salse Order Date",
+ "label": "Sales Order Date",
"length": 0,
"no_copy": 0,
"oldfieldname": "document_date",
diff --git a/erpnext/patches/v7_0/set_portal_settings.py b/erpnext/patches/v7_0/set_portal_settings.py
index d9b6400..f7ee205 100644
--- a/erpnext/patches/v7_0/set_portal_settings.py
+++ b/erpnext/patches/v7_0/set_portal_settings.py
@@ -7,13 +7,14 @@
from erpnext.setup.setup_wizard import domainify
def execute():
+ frappe.reload_doctype('Role')
for dt in ("assessment", "announcement", "course", "fees"):
frappe.reload_doc("schools", "doctype", dt)
frappe.reload_doc('website', 'doctype', 'portal_menu_item')
frappe.get_doc('Portal Settings').sync_menu()
-
+
if 'schools' in frappe.get_installed_apps():
domainify.setup_domain('Education')
else:
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index c3dbcd4..bd907f6 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -359,7 +359,8 @@
conditions = get_conditions(filters)
return frappe.db.sql("""select `tabTimesheet Detail`.name as name,
`tabTimesheet Detail`.docstatus as status, `tabTimesheet Detail`.parent as parent,
- from_time as start_date, hours, activity_type, project, to_time as end_date
+ from_time as start_date, hours, activity_type, project, to_time as end_date,
+ CONCAT(`tabTimesheet Detail`.parent, ' (', ROUND(hours,2),' hrs)') as title
from `tabTimesheet Detail`, `tabTimesheet`
where `tabTimesheet Detail`.parent = `tabTimesheet`.name
and `tabTimesheet`.docstatus < 2
diff --git a/erpnext/projects/doctype/timesheet/timesheet_calendar.js b/erpnext/projects/doctype/timesheet/timesheet_calendar.js
index b22cd09..0af1a6c 100644
--- a/erpnext/projects/doctype/timesheet/timesheet_calendar.js
+++ b/erpnext/projects/doctype/timesheet/timesheet_calendar.js
@@ -6,7 +6,8 @@
"id": "name",
"title": "name",
"allDay": "allDay",
- "child_name": "name"
+ "child_name": "name",
+ "title": "title"
},
style_map: {
"0": "info",
diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css
index 535f83a..ca3b4b5 100644
--- a/erpnext/public/css/erpnext.css
+++ b/erpnext/public/css/erpnext.css
@@ -61,6 +61,8 @@
}
.item-list-area {
padding: 15px 0px;
+ overflow-y: scroll;
+ height: calc(100vh - 162px);
}
.pos-toolbar,
.pos-bill-toolbar {
diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less
index 2d74b5f..e2ccddd 100644
--- a/erpnext/public/less/erpnext.less
+++ b/erpnext/public/less/erpnext.less
@@ -76,6 +76,8 @@
.item-list-area {
padding: 15px 0px;
+ overflow-y: scroll;
+ height: ~"calc(100vh - 162px)";
}
.pos-toolbar, .pos-bill-toolbar {
diff --git a/erpnext/schools/doctype/guardian/guardian.json b/erpnext/schools/doctype/guardian/guardian.json
index 120a884..8368f4a 100644
--- a/erpnext/schools/doctype/guardian/guardian.json
+++ b/erpnext/schools/doctype/guardian/guardian.json
@@ -1,6 +1,6 @@
{
"allow_copy": 0,
- "allow_import": 0,
+ "allow_import": 1,
"allow_rename": 0,
"autoname": "GARD.####",
"beta": 0,
@@ -10,6 +10,7 @@
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
+ "engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
@@ -23,6 +24,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Guardian Name",
"length": 0,
"no_copy": 0,
@@ -31,6 +33,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,
@@ -48,7 +51,8 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Email Address",
"length": 0,
"no_copy": 0,
@@ -57,6 +61,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,
@@ -74,7 +79,8 @@
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
- "in_list_view": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Mobile Number",
"length": 0,
"no_copy": 0,
@@ -83,6 +89,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,
@@ -101,6 +108,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Alternate Number",
"length": 0,
"no_copy": 0,
@@ -109,6 +117,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,
@@ -127,6 +136,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -134,6 +144,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,
@@ -152,6 +163,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Date of Birth",
"length": 0,
"no_copy": 0,
@@ -160,6 +172,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,
@@ -178,6 +191,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Education",
"length": 0,
"no_copy": 0,
@@ -186,6 +200,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,
@@ -204,6 +219,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Occupation",
"length": 0,
"no_copy": 0,
@@ -212,6 +228,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,
@@ -230,6 +247,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Designation",
"length": 0,
"no_copy": 0,
@@ -238,6 +256,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,
@@ -256,6 +275,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Image",
"length": 0,
"no_copy": 0,
@@ -264,6 +284,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,
@@ -282,6 +303,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -289,6 +311,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,
@@ -307,6 +330,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Work Address",
"length": 0,
"no_copy": 0,
@@ -315,6 +339,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,
@@ -333,6 +358,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -340,6 +366,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,
@@ -358,6 +385,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Interests",
"length": 0,
"no_copy": 0,
@@ -367,6 +395,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,
@@ -385,7 +414,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-09-01 14:33:26.541873",
+ "modified": "2016-12-28 16:14:58.836437",
"modified_by": "Administrator",
"module": "Schools",
"name": "Guardian",
@@ -402,6 +431,7 @@
"export": 1,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
diff --git a/erpnext/schools/doctype/student/student_dashboard.py b/erpnext/schools/doctype/student/student_dashboard.py
index 55faffb..8b5fb41 100644
--- a/erpnext/schools/doctype/student/student_dashboard.py
+++ b/erpnext/schools/doctype/student/student_dashboard.py
@@ -7,10 +7,10 @@
'fieldname': 'student',
'transactions': [
{
- 'items': ['Student Log', 'Student Group', 'Student Attendance']
+ 'items': ['Student Log', 'Student Batch', 'Student Group', 'Program Enrollment']
},
{
- 'items': ['Program Enrollment', 'Fees', 'Assessment']
+ 'items': ['Fees', 'Assessment', 'Student Attendance', 'Student Leave Application']
}
]
}
\ No newline at end of file
diff --git a/erpnext/schools/doctype/student_leave_application/student_leave_application.json b/erpnext/schools/doctype/student_leave_application/student_leave_application.json
index f183afc..ad6d498 100644
--- a/erpnext/schools/doctype/student_leave_application/student_leave_application.json
+++ b/erpnext/schools/doctype/student_leave_application/student_leave_application.json
@@ -103,7 +103,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "date",
+ "fieldname": "from_date",
"fieldtype": "Date",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -111,7 +111,7 @@
"in_filter": 0,
"in_list_view": 1,
"in_standard_filter": 1,
- "label": "Date",
+ "label": "From Date",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -131,6 +131,63 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "To Date",
+ "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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "Will show the student as Present in Student Monthly Attendance Report",
+ "fieldname": "mark_as_present",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Mark as Present",
+ "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": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "section_break_5",
"fieldtype": "Section Break",
"hidden": 0,
@@ -220,7 +277,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-12-15 14:51:28.774955",
+ "modified": "2016-12-21 18:58:00.256114",
"modified_by": "Administrator",
"module": "Schools",
"name": "Student Leave Application",
diff --git a/erpnext/schools/report/absent_student_report/absent_student_report.py b/erpnext/schools/report/absent_student_report/absent_student_report.py
index 82a20aa..32026c9 100644
--- a/erpnext/schools/report/absent_student_report/absent_student_report.py
+++ b/erpnext/schools/report/absent_student_report/absent_student_report.py
@@ -55,6 +55,6 @@
def get_leave_applications(date):
leave_applicants = []
for student in frappe.db.sql("""select student from `tabStudent Leave Application`
- where docstatus = 1 and date = %s""", date):
+ where docstatus = 1 and from_date <= %s and to_date >= %s""", (date, date)):
leave_applicants.append(student[0])
return leave_applicants
\ No newline at end of file
diff --git a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js
index 32c0551..8d914cb 100644
--- a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js
+++ b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js
@@ -3,40 +3,40 @@
frappe.query_reports["Student Monthly Attendance Sheet"] = {
- "filters": [
- {
- "fieldname":"month",
- "label": __("Month"),
- "fieldtype": "Select",
- "options": "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec",
- "default": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
- "Dec"][frappe.datetime.str_to_obj(frappe.datetime.get_today()).getMonth()],
- },
- {
- "fieldname":"year",
- "label": __("Year"),
- "fieldtype": "Select",
- "reqd": 1
- },
- {
- "fieldname":"student_batch",
- "label": __("Student Batch"),
- "fieldtype": "Link",
- "options": "Student Batch",
- "reqd": 1
- }
- ],
+ "filters": [{
+ "fieldname": "month",
+ "label": __("Month"),
+ "fieldtype": "Select",
+ "options": "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec",
+ "default": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
+ "Dec"
+ ][frappe.datetime.str_to_obj(frappe.datetime.get_today()).getMonth()],
+ },
+ {
+ "fieldname": "year",
+ "label": __("Year"),
+ "fieldtype": "Select",
+ "reqd": 1
+ },
+ {
+ "fieldname": "student_batch",
+ "label": __("Student Batch"),
+ "fieldtype": "Link",
+ "options": "Student Batch",
+ "reqd": 1
+ }
+ ],
- "onload": function() {
- return frappe.call({
- method: "erpnext.schools.report.student_monthly_attendance_sheet.student_monthly_attendance_sheet.get_attendance_years",
- callback: function(r) {
- var year_filter = frappe.query_report_filters_by_name.year;
- year_filter.df.options = r.message;
- year_filter.df.default = r.message.split("\n")[0];
- year_filter.refresh();
- year_filter.set_input(year_filter.df.default);
- }
- });
- }
-}
+ "onload": function() {
+ return frappe.call({
+ method: "erpnext.schools.report.student_monthly_attendance_sheet.student_monthly_attendance_sheet.get_attendance_years",
+ callback: function(r) {
+ var year_filter = frappe.query_report_filters_by_name.year;
+ year_filter.df.options = r.message;
+ year_filter.df.default = r.message.split("\n")[0];
+ year_filter.refresh();
+ year_filter.set_input(year_filter.df.default);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
index 2f8ba52..cd2c82c 100644
--- a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
+++ b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import cstr, cint, getdate
+from frappe.utils import cstr, cint, getdate, get_first_day, get_last_day, date_diff, add_days
from frappe import msgprint, _
from calendar import monthrange
from erpnext.schools.api import get_student_batch_students
@@ -11,72 +11,93 @@
def execute(filters=None):
if not filters: filters = {}
- conditions, filters = get_conditions(filters)
- columns = get_columns(filters)
- att_map = get_attendance_list(conditions, filters)
+ from_date = get_first_day(filters["month"] + '-' + filters["year"])
+ to_date = get_last_day(filters["month"] + '-' + filters["year"])
+ total_days_in_month = date_diff(to_date, from_date) +1
+ columns = get_columns(total_days_in_month)
students = get_student_batch_students(filters.get("student_batch"))
+ students_list = get_students_list(students)
+ att_map = get_attendance_list(from_date, to_date, filters.get("student_batch"), students_list)
data = []
for stud in students:
row = [stud.student, stud.student_name]
-
+ date = from_date
total_p = total_a = 0.0
- for day in range(filters["total_days_in_month"]):
+ for day in range(total_days_in_month):
status="None"
if att_map.get(stud.student):
- status = att_map.get(stud.student).get(day + 1, "None")
+ status = att_map.get(stud.student).get(date, "None")
status_map = {"Present": "P", "Absent": "A", "None": ""}
row.append(status_map[status])
-
if status == "Present":
total_p += 1
elif status == "Absent":
total_a += 1
-
+ date = add_days(date, 1)
row += [total_p, total_a]
data.append(row)
-
return columns, data
-def get_columns(filters):
+def get_columns(days_in_month):
columns = [ _("Student") + ":Link/Student:90", _("Student Name") + "::150"]
-
- for day in range(filters["total_days_in_month"]):
+ for day in range(days_in_month):
columns.append(cstr(day+1) +"::20")
-
columns += [_("Total Present") + ":Int:95", _("Total Absent") + ":Int:90"]
return columns
-def get_attendance_list(conditions, filters):
- attendance_list = frappe.db.sql("""select student, day(date) as day_of_month,
- status from `tabStudent Attendance` where docstatus = 1 %s order by student, date""" %
- conditions, filters, as_dict=1)
+def get_students_list(students):
+ student_list = []
+ for stud in students:
+ student_list.append(stud.student)
+ return student_list
+def get_attendance_list(from_date, to_date, student_batch, students_list):
+ attendance_list = frappe.db.sql("""select student, date, status
+ from `tabStudent Attendance` where docstatus = 1 and student_batch = %s
+ and date between %s and %s
+ order by student, date""",
+ (student_batch, from_date, to_date), as_dict=1)
att_map = {}
+ students_with_leave_application = get_students_with_leave_application(from_date, to_date, students_list)
for d in attendance_list:
- att_map.setdefault(d.student, frappe._dict()).setdefault(d.day_of_month, "")
- att_map[d.student][d.day_of_month] = d.status
-
+ att_map.setdefault(d.student, frappe._dict()).setdefault(d.date, "")
+ if students_with_leave_application and d.student in students_with_leave_application.get(d.date,[]):
+ att_map[d.student][d.date] = "Present"
+ else:
+ att_map[d.student][d.date] = d.status
return att_map
-def get_conditions(filters):
- if not (filters.get("month") and filters.get("year")):
- msgprint(_("Please select month and year"), raise_exception=1)
+def get_students_with_leave_application(from_date, to_date, students_list):
+ leave_applications = frappe.db.sql("""
+ select student, from_date, to_date
+ from `tabStudent Leave Application`
+ where
+ mark_as_present and docstatus = 1
+ and student in %(students)s
+ and (
+ from_date between %(from_date)s and %(to_date)s
+ or to_date between %(from_date)s and %(to_date)s
+ or (%(from_date)s between from_date and to_date and %(to_date)s between from_date and to_date)
+ )
+ """, {
+ "students": students_list,
+ "from_date": from_date,
+ "to_date": to_date
+ }, as_dict=True)
+ students_with_leaves= {}
+ for application in leave_applications:
+ for date in daterange(application.from_date, application.to_date):
+ students_with_leaves.setdefault(date, []).append(application.student)
- filters["month"] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
- "Dec"].index(filters.month) + 1
+ return students_with_leaves
- filters["total_days_in_month"] = monthrange(cint(filters.year), filters.month)[1]
-
- conditions = " and month(date) = %(month)s and year(date) = %(year)s"
-
- if filters.get("student_batch"): conditions += " and student_batch = %(student_batch)s"
-
- return conditions, filters
+def daterange(d1, d2):
+ import datetime
+ return (d1 + datetime.timedelta(days=i) for i in range((d2 - d1).days + 1))
@frappe.whitelist()
def get_attendance_years():
year_list = frappe.db.sql_list("""select distinct YEAR(date) from `tabStudent Attendance` ORDER BY YEAR(date) DESC""")
if not year_list:
year_list = [getdate().year]
-
return "\n".join(str(year) for year in year_list)
diff --git a/erpnext/selling/doctype/quotation/quotation_dashboard.py b/erpnext/selling/doctype/quotation/quotation_dashboard.py
index e572a92..f1c41e5 100644
--- a/erpnext/selling/doctype/quotation/quotation_dashboard.py
+++ b/erpnext/selling/doctype/quotation/quotation_dashboard.py
@@ -5,7 +5,6 @@
'fieldname': 'prevdoc_docname',
'transactions': [
{
- 'label': _('Related'),
'items': ['Sales Order']
},
]
diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py
index 97ef329..6e71769 100644
--- a/erpnext/startup/boot.py
+++ b/erpnext/startup/boot.py
@@ -13,8 +13,6 @@
bootinfo.website_settings = frappe.get_doc('Website Settings')
if frappe.session['user']!='Guest':
- bootinfo.letter_heads = get_letter_heads()
-
update_page_info(bootinfo)
load_country_and_currency(bootinfo)
@@ -42,12 +40,6 @@
number_format, smallest_currency_fraction_value, symbol from tabCurrency
where enabled=1""", as_dict=1, update={"doctype":":Currency"})
-def get_letter_heads():
- import frappe
- ret = frappe.db.sql("""select name, content from `tabLetter Head`
- where disabled=0""")
- return dict(ret)
-
def update_page_info(bootinfo):
bootinfo.page_info.update({
"Chart of Accounts": {
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 1f793d1..8844528 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -88,13 +88,13 @@
image: function(frm) {
refresh_field("image_view");
},
-
+
is_fixed_asset: function(frm) {
if (frm.doc.is_fixed_asset) {
frm.set_value("is_stock_item", 0);
}
},
-
+
page_name: frappe.utils.warn_page_name_change,
item_code: function(frm) {
@@ -191,15 +191,15 @@
frm.fields_dict.reorder_levels.grid.get_field("warehouse").get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
-
+
var filters = {
"is_group": 0
}
-
+
if (d.parent_warehouse) {
filters.extend({"parent_warehouse": d.warehouse_group})
}
-
+
return {
filters: filters
}
@@ -313,39 +313,38 @@
$(field.input_area).addClass("ui-front");
- field.$input.autocomplete({
- minLength: 0,
+ var input = field.$input.get(0);
+ input.awesomplete = new Awesomplete(input, {
minChars: 0,
- autoFocus: true,
- source: function(request, response) {
+ maxItems: 99,
+ autoFirst: true,
+ list: [],
+ });
+ input.field = field;
+
+ field.$input
+ .on('input', function(e) {
+ var term = e.target.value;
frappe.call({
method:"frappe.client.get_list",
args:{
doctype:"Item Attribute Value",
filters: [
["parent","=", i],
- ["attribute_value", "like", request.term + "%"]
+ ["attribute_value", "like", term + "%"]
],
fields: ["attribute_value"]
},
callback: function(r) {
if (r.message) {
- response($.map(r.message, function(d) { return d.attribute_value; }));
+ e.target.awesomplete.list = r.message.map(function(d) { return d.attribute_value; });
}
}
});
- },
- select: function(event, ui) {
- field.$input.val(ui.item.value);
- field.$input.trigger("change");
- },
- }).on("focus", function(){
- setTimeout(function() {
- if(!field.$input.val()) {
- field.$input.autocomplete("search", "");
- }
- }, 500);
- });
+ })
+ .on('focus', function(e) {
+ $(e.target).val('').trigger('input');
+ })
});
},
toggle_attributes: function(frm) {
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index a31aed4..ee42ae5 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -1055,6 +1055,67 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
+ "columns": 0,
+ "depends_on": "",
+ "fieldname": "unit_of_measure_conversion",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Units of Measure",
+ "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": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "",
+ "description": "Will also apply for variants",
+ "fieldname": "uoms",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "UOMs",
+ "length": 0,
+ "no_copy": 1,
+ "oldfieldname": "uom_conversion_details",
+ "oldfieldtype": "Table",
+ "options": "UOM Conversion Detail",
+ "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": 1,
"collapsible_depends_on": "attributes",
"columns": 0,
"depends_on": "",
@@ -1362,67 +1423,6 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
- "fieldname": "unit_of_measure_conversion",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Unit of Measure Conversion",
- "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": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "",
- "description": "Will also apply for variants",
- "fieldname": "uoms",
- "fieldtype": "Table",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "UOMs",
- "length": 0,
- "no_copy": 1,
- "oldfieldname": "uom_conversion_details",
- "oldfieldtype": "Table",
- "options": "UOM Conversion Detail",
- "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,
- "depends_on": "",
"fieldname": "last_purchase_rate",
"fieldtype": "Float",
"hidden": 0,
diff --git a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
index e679054..61c19f0 100644
--- a/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
+++ b/erpnext/stock/doctype/landed_cost_item/landed_cost_item.json
@@ -9,11 +9,13 @@
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
+ "engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "item_code",
"fieldtype": "Link",
"hidden": 0,
@@ -21,6 +23,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Item Code",
"length": 0,
"no_copy": 0,
@@ -29,6 +32,7 @@
"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,
@@ -40,6 +44,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -47,6 +52,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
@@ -57,6 +63,7 @@
"print_hide_if_no_value": 0,
"print_width": "300px",
"read_only": 1,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
@@ -68,6 +75,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "receipt_document_type",
"fieldtype": "Select",
"hidden": 0,
@@ -75,6 +83,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Receipt Document Type",
"length": 0,
"no_copy": 1,
@@ -84,6 +93,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,
@@ -94,6 +104,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "receipt_document",
"fieldtype": "Dynamic Link",
"hidden": 0,
@@ -101,6 +112,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Receipt Document",
"length": 0,
"no_copy": 1,
@@ -110,6 +122,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,
@@ -120,6 +133,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "col_break2",
"fieldtype": "Column Break",
"hidden": 0,
@@ -127,12 +141,14 @@
"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,
@@ -143,6 +159,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "qty",
"fieldtype": "Float",
"hidden": 0,
@@ -150,6 +167,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Qty",
"length": 0,
"no_copy": 0,
@@ -157,6 +175,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,
@@ -167,6 +186,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "rate",
"fieldtype": "Currency",
"hidden": 0,
@@ -174,6 +194,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Rate",
"length": 0,
"no_copy": 0,
@@ -182,6 +203,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,
@@ -192,6 +214,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -199,6 +222,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
@@ -209,6 +233,7 @@
"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,
@@ -219,6 +244,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "applicable_charges",
"fieldtype": "Currency",
"hidden": 0,
@@ -226,6 +252,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Applicable Charges",
"length": 0,
"no_copy": 0,
@@ -233,7 +260,8 @@
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
- "read_only": 1,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
@@ -244,6 +272,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "purchase_receipt_item",
"fieldtype": "Data",
"hidden": 1,
@@ -251,6 +280,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Purchase Receipt Item",
"length": 0,
"no_copy": 1,
@@ -258,6 +288,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,
@@ -275,7 +306,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2016-07-11 03:28:01.757912",
+ "modified": "2016-12-20 04:50:19.785273",
"modified_by": "Administrator",
"module": "Stock",
"name": "Landed Cost Item",
diff --git a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
index b1f5a8c..dbc6a88 100644
--- a/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
+++ b/erpnext/stock/doctype/landed_cost_taxes_and_charges/landed_cost_taxes_and_charges.json
@@ -9,11 +9,13 @@
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
+ "engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
@@ -21,6 +23,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Description",
"length": 0,
"no_copy": 0,
@@ -28,6 +31,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 +42,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "col_break3",
"fieldtype": "Column Break",
"hidden": 0,
@@ -45,12 +50,14 @@
"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,
@@ -62,6 +69,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
@@ -69,6 +77,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
@@ -77,6 +86,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,
@@ -94,7 +104,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2016-07-11 03:28:01.958276",
+ "modified": "2016-12-20 05:44:54.700163",
"modified_by": "Administrator",
"module": "Stock",
"name": "Landed Cost Taxes and Charges",
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
index 525853b..b97378f 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.js
@@ -32,7 +32,7 @@
},
- refresh: function() {
+ refresh: function(frm) {
var help_content = [
'<br><br>',
'<table class="table table-bordered" style="background-color: #f9f9f9;">',
@@ -70,12 +70,15 @@
} else {
return this.frm.call({
doc: me.frm.doc,
- method: "get_items_from_purchase_receipts"
+ method: "get_items_from_purchase_receipts",
+ callback: function(r, rt) {
+ me.set_applicable_charges_for_item();
+ }
});
}
},
- amount: function() {
+ amount: function(frm) {
this.set_total_taxes_and_charges();
this.set_applicable_charges_for_item();
},
@@ -90,17 +93,23 @@
set_applicable_charges_for_item: function() {
var me = this;
+
if(this.frm.doc.taxes.length) {
+
var total_item_cost = 0.0;
+ var based_on = this.frm.doc.distribute_charges_based_on.toLowerCase();
$.each(this.frm.doc.items || [], function(i, d) {
- total_item_cost += flt(d.amount)
+ total_item_cost += flt(d[based_on])
});
$.each(this.frm.doc.items || [], function(i, item) {
- item.applicable_charges = flt(item.amount) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
+ item.applicable_charges = flt(item[based_on]) * flt(me.frm.doc.total_taxes_and_charges) / flt(total_item_cost)
});
refresh_field("items");
}
+ },
+ distribute_charges_based_on: function (frm) {
+ this.set_applicable_charges_for_item();
}
});
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
index 227541f..db6e402 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json
@@ -10,6 +10,7 @@
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 0,
+ "engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
@@ -101,6 +102,34 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "purchase_receipt_items",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Purchase Receipt Items",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "get_items_from_purchase_receipts",
"fieldtype": "Button",
"hidden": 0,
@@ -156,6 +185,35 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "sec_break1",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Additional Charges",
+ "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,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "taxes",
"fieldtype": "Table",
"hidden": 0,
@@ -184,7 +242,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "sec_break1",
+ "fieldname": "section_break_9",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -194,7 +252,6 @@
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
- "options": "Simple",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -240,34 +297,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "amended_from",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Amended From",
- "length": 0,
- "no_copy": 1,
- "options": "Landed Cost Voucher",
- "permlevel": 0,
- "print_hide": 1,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "col_break1",
"fieldtype": "Column Break",
"hidden": 0,
@@ -295,7 +324,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "default": "Amount",
+ "default": "",
"fieldname": "distribute_charges_based_on",
"fieldtype": "Select",
"hidden": 0,
@@ -325,6 +354,34 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Amended From",
+ "length": 0,
+ "no_copy": 1,
+ "options": "Landed Cost Voucher",
+ "permlevel": 0,
+ "print_hide": 1,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "sec_break2",
"fieldtype": "Section Break",
"hidden": 0,
@@ -378,7 +435,7 @@
],
"hide_heading": 0,
"hide_toolbar": 0,
- "icon": "fa fa-usd",
+ "icon": "icon-usd",
"idx": 0,
"image_view": 0,
"in_create": 0,
@@ -387,7 +444,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-11-07 05:09:46.981120",
+ "modified": "2016-12-21 01:40:13.959409",
"modified_by": "Administrator",
"module": "Stock",
"name": "Landed Cost Voucher",
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index cdf7263..aacf02c 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -29,9 +29,6 @@
item.receipt_document = pr.receipt_document
item.purchase_receipt_item = d.name
- if self.get("taxes"):
- self.set_applicable_charges_for_item()
-
def validate(self):
self.check_mandatory()
self.validate_purchase_receipts()
@@ -39,15 +36,13 @@
if not self.get("items"):
self.get_items_from_purchase_receipts()
else:
- self.set_applicable_charges_for_item()
+ self.validate_applicable_charges_for_item()
def check_mandatory(self):
if not self.get("purchase_receipts"):
frappe.throw(_("Please enter Receipt Document"))
- if not self.get("taxes"):
- frappe.throw(_("Please enter Taxes and Charges"))
-
+
def validate_purchase_receipts(self):
receipt_documents = []
@@ -67,15 +62,18 @@
def set_total_taxes_and_charges(self):
self.total_taxes_and_charges = sum([flt(d.amount) for d in self.get("taxes")])
- def set_applicable_charges_for_item(self):
+ def validate_applicable_charges_for_item(self):
based_on = self.distribute_charges_based_on.lower()
+
total = sum([flt(d.get(based_on)) for d in self.get("items")])
-
+
if not total:
- frappe.throw(_("Total {0} for all items is zero, may you should change 'Distribute Charges Based On'").format(based_on))
+ frappe.throw(_("Total {0} for all items is zero, may be you should change 'Distribute Charges Based On'").format(based_on))
+
+ if self.total_taxes_and_charges != sum([flt(d.applicable_charges) for d in self.get("items")]):
+ frappe.throw(_("Total Applicable Charges in Purchase Receipt Items table must be same as Total Taxes and Charges"))
- for item in self.get("items"):
- item.applicable_charges = flt(item.get(based_on)) * flt(self.total_taxes_and_charges) / flt(total)
+
def on_submit(self):
self.update_landed_cost()
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index c58607f..409770e 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -5,6 +5,7 @@
from __future__ import unicode_literals
import unittest
import frappe
+from frappe.utils import flt
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \
import set_perpetual_inventory, get_gl_entries, test_records as pr_test_records
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
@@ -23,7 +24,7 @@
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
- self.submit_landed_cost_voucher("Purchase Receipt", pr.name)
+ submit_landed_cost_voucher("Purchase Receipt", pr.name)
pr_lc_value = frappe.db.get_value("Purchase Receipt Item", {"parent": pr.name}, "landed_cost_voucher_amount")
self.assertEquals(pr_lc_value, 25.0)
@@ -75,7 +76,7 @@
},
fieldname=["qty_after_transaction", "stock_value"], as_dict=1)
- self.submit_landed_cost_voucher("Purchase Invoice", pi.name)
+ submit_landed_cost_voucher("Purchase Invoice", pi.name)
pi_lc_value = frappe.db.get_value("Purchase Invoice Item", {"parent": pi.name},
"landed_cost_voucher_amount")
@@ -121,7 +122,7 @@
serial_no_rate = frappe.db.get_value("Serial No", "SN001", "purchase_rate")
- self.submit_landed_cost_voucher("Purchase Receipt", pr.name)
+ submit_landed_cost_voucher("Purchase Receipt", pr.name)
serial_no = frappe.db.get_value("Serial No", "SN001",
["warehouse", "purchase_rate"], as_dict=1)
@@ -131,27 +132,37 @@
set_perpetual_inventory(0)
- def submit_landed_cost_voucher(self, receipt_document_type, receipt_document):
- ref_doc = frappe.get_doc(receipt_document_type, receipt_document)
-
- lcv = frappe.new_doc("Landed Cost Voucher")
- lcv.company = "_Test Company"
- lcv.set("purchase_receipts", [{
- "receipt_document_type": receipt_document_type,
- "receipt_document": receipt_document,
- "supplier": ref_doc.supplier,
- "posting_date": ref_doc.posting_date,
- "grand_total": ref_doc.base_grand_total
- }])
-
- lcv.set("taxes", [{
- "description": "Insurance Charges",
- "account": "_Test Account Insurance Charges - _TC",
- "amount": 50
- }])
+def submit_landed_cost_voucher(receipt_document_type, receipt_document):
+ ref_doc = frappe.get_doc(receipt_document_type, receipt_document)
+
+ lcv = frappe.new_doc("Landed Cost Voucher")
+ lcv.company = "_Test Company"
+ lcv.distribute_charges_based_on = 'Amount'
+
+ lcv.set("purchase_receipts", [{
+ "receipt_document_type": receipt_document_type,
+ "receipt_document": receipt_document,
+ "supplier": ref_doc.supplier,
+ "posting_date": ref_doc.posting_date,
+ "grand_total": ref_doc.base_grand_total
+ }])
+
+ lcv.set("taxes", [{
+ "description": "Insurance Charges",
+ "account": "_Test Account Insurance Charges - _TC",
+ "amount": 50
+ }])
- lcv.insert()
- lcv.submit()
-
+ lcv.insert()
+
+ distribute_landed_cost_on_items(lcv)
+
+ lcv.submit()
+
+def distribute_landed_cost_on_items(lcv):
+ based_on = lcv.distribute_charges_based_on.lower()
+ total = sum([flt(d.get(based_on)) for d in lcv.get("items")])
+ for item in lcv.get("items"):
+ item.applicable_charges = flt(item.get(based_on)) * flt(lcv.total_taxes_and_charges) / flt(total)
test_records = frappe.get_test_records('Landed Cost Voucher')
diff --git a/erpnext/stock/doctype/material_request/material_request_list.js b/erpnext/stock/doctype/material_request/material_request_list.js
index eb14930..b6ceeac 100644
--- a/erpnext/stock/doctype/material_request/material_request_list.js
+++ b/erpnext/stock/doctype/material_request/material_request_list.js
@@ -3,10 +3,10 @@
get_indicator: function(doc) {
if(doc.status=="Stopped") {
return [__("Stopped"), "red", "status,=,Stopped"];
- } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 0.00) {
+ } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 0) {
return [__("Pending"), "orange", "per_ordered,=,0"];
- } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) < 100) {
- return [__("Partially Ordered"), "orange", "per_ordered,<,100"];
+ } else if(doc.docstatus==1 && flt(doc.per_ordered, 2) < 100) {
+ return [__("Partially ordred"), "yellow", "per_ordered,<,100"];
} else if(doc.docstatus==1 && flt(doc.per_ordered, 2) == 100) {
if (doc.material_request_type == "Purchase") {
return [__("Ordered"), "green", "per_ordered,=,100"];
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index a5a6ced..b410802 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -431,22 +431,16 @@
uom: function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(d.uom && d.item_code){
- arg = {
- 'item_code':d.item_code,
- 'uom':d.uom,
- 'qty':d.qty
- };
return frappe.call({
- doc: cur_frm.doc,
- method: "get_uom_details",
- args: arg,
+ method: "erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details",
+ args: {
+ item_code: d.item_code,
+ uom: d.uom,
+ qty: d.qty
+ },
callback: function(r) {
if(r.message) {
- var d = locals[cdt][cdn];
- $.each(r.message, function(k, v) {
- d[k] = v;
- });
- refresh_field("items");
+ frappe.model.set_value(cdt, cdn, r.message);
}
}
});
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index c5a03e6..1199593 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -233,7 +233,7 @@
for d in self.get('items'):
transferred_serial_no = frappe.db.get_value("Stock Entry Detail",{"parent": previous_se,
"item_code": d.item_code}, "serial_no")
-
+
if transferred_serial_no:
d.serial_no = transferred_serial_no
@@ -496,7 +496,7 @@
# update uom
if args.get("uom") and for_update:
- ret.update(self.get_uom_details(args))
+ ret.update(get_uom_details(args.get('item_code'), args.get('uom'), args.get('qty')))
if not ret["expense_account"]:
ret["expense_account"] = frappe.db.get_value("Company", self.company, "stock_adjustment_account")
@@ -509,23 +509,6 @@
return ret
- def get_uom_details(self, args):
- """Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`
-
- :param args: dict with `item_code`, `uom` and `qty`"""
- conversion_factor = get_conversion_factor(args.get("item_code"), args.get("uom")).get("conversion_factor")
-
- if not conversion_factor:
- frappe.msgprint(_("UOM coversion factor required for UOM: {0} in Item: {1}")
- .format(args.get("uom"), args.get("item_code")))
- ret = {'uom' : ''}
- else:
- ret = {
- 'conversion_factor' : flt(conversion_factor),
- 'transfer_qty' : flt(args.get("qty")) * flt(conversion_factor)
- }
- return ret
-
def get_items(self):
self.set('items', [])
self.validate_production_order()
@@ -559,7 +542,7 @@
item["from_warehouse"] = self.pro_doc.wip_warehouse
item["to_warehouse"] = self.to_warehouse if self.purpose=="Subcontract" else ""
-
+
self.add_to_stock_entry_detail(item_dict)
scrap_item_dict = self.get_bom_scrap_material(self.fg_completed_qty)
@@ -567,7 +550,7 @@
if self.pro_doc and self.pro_doc.scrap_warehouse:
item["to_warehouse"] = self.pro_doc.scrap_warehouse
self.add_to_stock_entry_detail(scrap_item_dict, bom_no=self.bom_no)
-
+
# fetch the serial_no of the first stock entry for the second stock entry
if self.production_order and self.purpose == "Manufacture":
self.set_serial_nos(self.production_order)
@@ -632,10 +615,10 @@
for item in item_dict.values():
item.from_warehouse = self.from_warehouse or item.default_warehouse
return item_dict
-
+
def get_bom_scrap_material(self, qty):
from erpnext.manufacturing.doctype.bom.bom import get_bom_items_as_dict
-
+
# item dict = { item_code: {qty, description, stock_uom} }
item_dict = get_bom_items_as_dict(self.bom_no, self.company, qty=qty,
fetch_exploded = 0, fetch_scrap_items = 1)
@@ -643,7 +626,7 @@
for item in item_dict.values():
item.from_warehouse = ""
return item_dict
-
+
def get_transfered_raw_materials(self):
transferred_materials = frappe.db.sql("""
select
@@ -850,6 +833,24 @@
return operating_cost_per_unit
@frappe.whitelist()
+def get_uom_details(item_code, uom, qty):
+ """Returns dict `{"conversion_factor": [value], "transfer_qty": qty * [value]}`
+
+ :param args: dict with `item_code`, `uom` and `qty`"""
+ conversion_factor = get_conversion_factor(item_code, uom).get("conversion_factor")
+
+ if not conversion_factor:
+ frappe.msgprint(_("UOM coversion factor required for UOM: {0} in Item: {1}")
+ .format(uom, item_code))
+ ret = {'uom' : ''}
+ else:
+ ret = {
+ 'conversion_factor' : flt(conversion_factor),
+ 'transfer_qty' : flt(qty) * flt(conversion_factor)
+ }
+ return ret
+
+@frappe.whitelist()
def get_warehouse_details(args):
if isinstance(args, basestring):
args = json.loads(args)
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index 6501682..4801d40 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -8,11 +8,13 @@
"description": "Settings",
"docstatus": 0,
"doctype": "DocType",
+ "editable_grid": 0,
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"default": "Item Code",
"fieldname": "item_naming_by",
"fieldtype": "Select",
@@ -21,6 +23,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Item Naming By",
"length": 0,
"no_copy": 0,
@@ -29,6 +32,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,
@@ -39,6 +43,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"description": "",
"fieldname": "item_group",
"fieldtype": "Link",
@@ -47,6 +52,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Default Item Group",
"length": 0,
"no_copy": 0,
@@ -55,6 +61,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,
@@ -65,6 +72,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "stock_uom",
"fieldtype": "Link",
"hidden": 0,
@@ -72,6 +80,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
+ "in_standard_filter": 0,
"label": "Default Stock UOM",
"length": 0,
"no_copy": 0,
@@ -80,6 +89,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,6 +100,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "default_warehouse",
"fieldtype": "Link",
"hidden": 0,
@@ -97,6 +108,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Default Warehouse",
"length": 0,
"no_copy": 0,
@@ -106,6 +118,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,
@@ -116,6 +129,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -123,12 +137,14 @@
"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,
@@ -139,6 +155,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "valuation_method",
"fieldtype": "Select",
"hidden": 0,
@@ -146,6 +163,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Default Valuation Method",
"length": 0,
"no_copy": 0,
@@ -154,6 +172,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,
@@ -164,6 +183,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"description": "Percentage you are allowed to receive or deliver more against the quantity ordered. For example: If you have ordered 100 units. and your Allowance is 10% then you are allowed to receive 110 units.",
"fieldname": "tolerance",
"fieldtype": "Float",
@@ -172,13 +192,15 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
- "label": "Allowance Percent",
+ "in_standard_filter": 0,
+ "label": "Limit Percent",
"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,
@@ -189,6 +211,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"default": "1",
"fieldname": "show_barcode_field",
"fieldtype": "Check",
@@ -197,6 +220,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Show Barcode Field",
"length": 0,
"no_copy": 0,
@@ -205,6 +229,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,
@@ -215,6 +240,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "section_break_7",
"fieldtype": "Section Break",
"hidden": 0,
@@ -222,6 +248,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -229,6 +256,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,
@@ -239,6 +267,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "auto_insert_price_list_rate_if_missing",
"fieldtype": "Check",
"hidden": 0,
@@ -246,6 +275,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Auto insert Price List rate if missing",
"length": 0,
"no_copy": 0,
@@ -254,6 +284,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,
@@ -264,6 +295,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "allow_negative_stock",
"fieldtype": "Check",
"hidden": 0,
@@ -271,6 +303,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Allow Negative Stock",
"length": 0,
"no_copy": 0,
@@ -278,6 +311,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,
@@ -288,6 +322,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "column_break_10",
"fieldtype": "Column Break",
"hidden": 0,
@@ -295,6 +330,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -302,6 +338,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,
@@ -312,6 +349,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"default": "1",
"fieldname": "automatically_set_serial_nos_based_on_fifo",
"fieldtype": "Check",
@@ -320,6 +358,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Automatically Set Serial Nos based on FIFO",
"length": 0,
"no_copy": 0,
@@ -328,6 +367,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,
@@ -338,6 +378,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "auto_material_request",
"fieldtype": "Section Break",
"hidden": 0,
@@ -345,6 +386,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Auto Material Request",
"length": 0,
"no_copy": 0,
@@ -352,6 +394,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,
@@ -362,6 +405,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "auto_indent",
"fieldtype": "Check",
"hidden": 0,
@@ -369,6 +413,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Raise Material Request when stock reaches re-order level",
"length": 0,
"no_copy": 0,
@@ -376,6 +421,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,
@@ -386,6 +432,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "reorder_email_notify",
"fieldtype": "Check",
"hidden": 0,
@@ -393,6 +440,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Notify by Email on creation of automatic Material Request",
"length": 0,
"no_copy": 0,
@@ -400,6 +448,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,
@@ -410,6 +459,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "freeze_stock_entries",
"fieldtype": "Section Break",
"hidden": 0,
@@ -417,6 +467,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Freeze Stock Entries",
"length": 0,
"no_copy": 0,
@@ -424,6 +475,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,
@@ -434,6 +486,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "stock_frozen_upto",
"fieldtype": "Date",
"hidden": 0,
@@ -441,6 +494,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Stock Frozen Upto",
"length": 0,
"no_copy": 0,
@@ -448,6 +502,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,
@@ -458,6 +513,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "stock_frozen_upto_days",
"fieldtype": "Int",
"hidden": 0,
@@ -465,6 +521,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Freeze Stocks Older Than [Days]",
"length": 0,
"no_copy": 0,
@@ -472,6 +529,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,
@@ -482,6 +540,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
+ "columns": 0,
"fieldname": "stock_auth_role",
"fieldtype": "Link",
"hidden": 0,
@@ -489,6 +548,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
+ "in_standard_filter": 0,
"label": "Role Allowed to edit frozen stock",
"length": 0,
"no_copy": 0,
@@ -497,6 +557,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,
@@ -506,15 +567,16 @@
],
"hide_heading": 0,
"hide_toolbar": 0,
- "icon": "fa fa-cog",
+ "icon": "icon-cog",
"idx": 1,
+ "image_view": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2016-05-12 12:28:29.374452",
+ "modified": "2016-12-16 02:18:58.187847",
"modified_by": "Administrator",
"module": "Stock",
"name": "Stock Settings",
@@ -530,6 +592,7 @@
"export": 0,
"if_owner": 0,
"import": 0,
+ "is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
diff --git a/erpnext/stock/report/batch_item_expiry_status/__init__.py b/erpnext/stock/report/batch_item_expiry_status/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/report/batch_item_expiry_status/__init__.py
diff --git a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.js b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.js
new file mode 100644
index 0000000..eeeb9ad
--- /dev/null
+++ b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.js
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.query_reports["Batch Item Expiry Status"] = {
+ "filters": [
+ {
+ "fieldname":"from_date",
+ "label": __("From Date"),
+ "fieldtype": "Date",
+ "width": "80",
+ "default": sys_defaults.year_start_date,
+ },
+ {
+ "fieldname":"to_date",
+ "label": __("To Date"),
+ "fieldtype": "Date",
+ "width": "80",
+ "default": frappe.datetime.get_today()
+ }
+ ]
+}
diff --git a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.json b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.json
new file mode 100644
index 0000000..d5d23ba
--- /dev/null
+++ b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.json
@@ -0,0 +1,18 @@
+{
+ "add_total_row": 0,
+ "apply_user_permissions": 1,
+ "creation": "2016-12-21 11:29:01.884436",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2016-12-21 11:29:01.884436",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Batch Item Expiry Status",
+ "owner": "Administrator",
+ "ref_doctype": "Stock Ledger Entry",
+ "report_name": "Batch Item Expiry Status",
+ "report_type": "Script Report"
+}
\ No newline at end of file
diff --git a/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
new file mode 100644
index 0000000..7354eee
--- /dev/null
+++ b/erpnext/stock/report/batch_item_expiry_status/batch_item_expiry_status.py
@@ -0,0 +1,94 @@
+# 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 flt, cint, getdate
+
+def execute(filters=None):
+ if not filters: filters = {}
+
+ float_precision = cint(frappe.db.get_default("float_precision")) or 3
+
+ columns = get_columns(filters)
+ item_map = get_item_details(filters)
+ iwb_map = get_item_warehouse_batch_map(filters, float_precision)
+
+ data = []
+ for item in sorted(iwb_map):
+ for wh in sorted(iwb_map[item]):
+ for batch in sorted(iwb_map[item][wh]):
+ qty_dict = iwb_map[item][wh][batch]
+
+ data.append([item, item_map[item]["item_name"], item_map[item]["description"], wh, batch,
+ frappe.db.get_value('Batch', batch, 'expiry_date'), qty_dict.expiry_status
+ ])
+
+
+ return columns, data
+
+def get_columns(filters):
+ """return columns based on filters"""
+
+ columns = [_("Item") + ":Link/Item:100"] + [_("Item Name") + "::150"] + [_("Description") + "::150"] + \
+ [_("Warehouse") + ":Link/Warehouse:100"] + [_("Batch") + ":Link/Batch:100"] + [_("Expires On") + ":Date:90"] + \
+ [_("Expiry (In Days)") + ":Int:120"]
+
+ return columns
+
+def get_conditions(filters):
+ conditions = ""
+ if not filters.get("from_date"):
+ frappe.throw(_("'From Date' is required"))
+
+ if filters.get("to_date"):
+ conditions += " and posting_date <= '%s'" % filters["to_date"]
+ else:
+ frappe.throw(_("'To Date' is required"))
+
+ return conditions
+
+def get_stock_ledger_entries(filters):
+ conditions = get_conditions(filters)
+ return frappe.db.sql("""select item_code, batch_no, warehouse,
+ posting_date, actual_qty
+ from `tabStock Ledger Entry`
+ where docstatus < 2 and ifnull(batch_no, '') != '' %s order by item_code, warehouse""" %
+ conditions, as_dict=1)
+
+def get_item_warehouse_batch_map(filters, float_precision):
+ sle = get_stock_ledger_entries(filters)
+ iwb_map = {}
+
+ from_date = getdate(filters["from_date"])
+ to_date = getdate(filters["to_date"])
+
+ for d in sle:
+ iwb_map.setdefault(d.item_code, {}).setdefault(d.warehouse, {})\
+ .setdefault(d.batch_no, frappe._dict({
+ "expires_on": None, "expiry_status": None}))
+
+ qty_dict = iwb_map[d.item_code][d.warehouse][d.batch_no]
+
+ expiry_date_unicode = frappe.db.get_value('Batch', d.batch_no, 'expiry_date')
+ qty_dict.expires_on = expiry_date_unicode
+
+ exp_date = frappe.utils.data.getdate(expiry_date_unicode)
+ qty_dict.expires_on = exp_date
+
+ expires_in_days = (exp_date - frappe.utils.datetime.date.today()).days
+
+ if expires_in_days > 0:
+ qty_dict.expiry_status = expires_in_days
+ else:
+ qty_dict.expiry_status = 0
+
+ return iwb_map
+
+def get_item_details(filters):
+ item_map = {}
+ for d in frappe.db.sql("select name, item_name, description from tabItem", as_dict=1):
+ item_map.setdefault(d.name, d)
+
+ return item_map
diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html
index 19dc204..f027644 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -6,7 +6,7 @@
<ul class="breadcrumb">
<li>
<span class="fa fa-angle-left"></span>
- <a href="/me">My Account</a>
+ <a href="/me">{{ _("My Account") }}</a>
</li>
</ul>
</div>