diff --git a/erpnext/__version__.py b/erpnext/__version__.py
index e8de3f40853..25937f019d7 100644
--- a/erpnext/__version__.py
+++ b/erpnext/__version__.py
@@ -1 +1 @@
-__version__ = '4.12.0'
+__version__ = '4.13.0'
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 7195db8a94d..3874ac21467 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt, cstr, cint, getdate, add_days, formatdate
+from frappe.utils import flt, cstr, cint, getdate
from frappe import msgprint, throw, _
from frappe.model.document import Document
@@ -176,15 +176,7 @@ class Account(Document):
frappe.throw(_("Due Date cannot be before Posting Date"))
elif credit_days is not None and diff > credit_days:
- is_credit_controller = frappe.db.get_value("Accounts Settings", None,
- "credit_controller") in frappe.user.get_roles()
-
- if is_credit_controller:
- msgprint(_("Note: Due Date exceeds the allowed credit days by {0} day(s)").format(
- diff - credit_days))
- else:
- max_due_date = formatdate(add_days(posting_date, credit_days))
- frappe.throw(_("Due Date cannot be after {0}").format(max_due_date))
+ msgprint(_("Note: Due Date exceeds the allowed credit days by {0} day(s)").format(diff - credit_days))
def validate_trash(self):
"""checks gl entries and if child exists"""
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 7e374002f2a..266aae4aedb 100755
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -800,7 +800,8 @@
"fieldtype": "Date",
"label": "From Date",
"no_copy": 1,
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -810,7 +811,8 @@
"fieldtype": "Date",
"label": "To Date",
"no_copy": 1,
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -878,7 +880,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2014-10-08 14:23:20.234176",
+ "modified": "2014-11-27 17:28:20.133701",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.js b/erpnext/accounts/doctype/sales_invoice/pos.js
index 8c6e3cdb827..d9ef6d85626 100644
--- a/erpnext/accounts/doctype/sales_invoice/pos.js
+++ b/erpnext/accounts/doctype/sales_invoice/pos.js
@@ -233,6 +233,11 @@ erpnext.POS = Class.extend({
},
make_item_list: function() {
var me = this;
+ if(!this.price_list) {
+ msgprint(__("Price List not found or disabled"));
+ return;
+ }
+
me.item_timeout = null;
frappe.call({
method: 'erpnext.accounts.doctype.sales_invoice.pos.get_items',
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 3dc81d13416..a2ed86da15f 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -13,17 +13,17 @@ class AccountsReceivableReport(object):
self.age_as_on = getdate(nowdate()) \
if self.filters.report_date > getdate(nowdate()) \
else self.filters.report_date
-
+
def run(self):
customer_naming_by = frappe.db.get_value("Selling Settings", None, "cust_master_name")
return self.get_columns(customer_naming_by), self.get_data(customer_naming_by)
-
+
def get_columns(self, customer_naming_by):
columns = [
_("Posting Date") + ":Date:80", _("Account") + ":Link/Account:150",
_("Voucher Type") + "::110", _("Voucher No") + ":Dynamic Link/Voucher Type:120",
- _("Due Date") + ":Date:80",
- _("Invoiced Amount") + ":Currency:100", _("Payment Received") + ":Currency:100",
+ _("Due Date") + ":Date:80",
+ _("Invoiced Amount") + ":Currency:100", _("Payment Received") + ":Currency:100",
_("Outstanding Amount") + ":Currency:100", _("Age") + ":Int:50", "0-30:Currency:100",
"30-60:Currency:100", "60-90:Currency:100", _("90-Above") + ":Currency:100",
_("Customer") + ":Link/Customer:200"
@@ -69,27 +69,27 @@ class AccountsReceivableReport(object):
# returns a distinct list
return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries()
if getdate(e.posting_date) > report_date]))
-
+
def get_entries_till(self, report_date):
# returns a generator
- return (e for e in self.get_gl_entries()
+ return (e for e in self.get_gl_entries()
if getdate(e.posting_date) <= report_date)
-
+
def is_receivable(self, gle, future_vouchers):
return (
# advance
- (not gle.against_voucher) or
+ (not gle.against_voucher) or
# against sales order
(gle.against_voucher_type == "Sales Order") or
-
+
# sales invoice
- (gle.against_voucher==gle.voucher_no and gle.debit > 0) or
-
+ (gle.against_voucher==gle.voucher_no and gle.debit > 0) or
+
# entries adjusted with future vouchers
((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
)
-
+
def get_outstanding_amount(self, gle, report_date):
payment_received = 0.0
for e in self.get_gl_entries_for(gle.account, gle.voucher_type, gle.voucher_no):
@@ -97,7 +97,7 @@ class AccountsReceivableReport(object):
payment_received += (flt(e.credit) - flt(e.debit))
return flt(gle.debit) - flt(gle.credit) - payment_received
-
+
def get_customer(self, account):
return self.get_account_map().get(account, {}).get("customer") or ""
@@ -106,25 +106,25 @@ class AccountsReceivableReport(object):
def get_territory(self, account):
return self.get_account_map().get(account, {}).get("territory") or ""
-
+
def get_account_map(self):
if not hasattr(self, "account_map"):
- self.account_map = dict(((r.name, r) for r in frappe.db.sql("""select
+ self.account_map = dict(((r.name, r) for r in frappe.db.sql("""select
acc.name, cust.name as customer, cust.customer_name, cust.territory
- from `tabAccount` acc left join `tabCustomer` cust
+ from `tabAccount` acc left join `tabCustomer` cust
on cust.name=acc.master_name where acc.master_type="Customer" """, as_dict=True)))
-
+
return self.account_map
-
+
def get_due_date(self, gle):
if not hasattr(self, "invoice_due_date_map"):
# TODO can be restricted to posting date
self.invoice_due_date_map = dict(frappe.db.sql("""select name, due_date
from `tabSales Invoice` where docstatus=1"""))
-
+
return gle.voucher_type == "Sales Invoice" \
and self.invoice_due_date_map.get(gle.voucher_no) or ""
-
+
def get_gl_entries(self):
if not hasattr(self, "gl_entries"):
conditions, values = self.prepare_conditions()
@@ -132,15 +132,15 @@ class AccountsReceivableReport(object):
where docstatus < 2 {0} order by posting_date, account""".format(conditions),
values, as_dict=True)
return self.gl_entries
-
+
def prepare_conditions(self):
conditions = [""]
values = {}
-
+
if self.filters.company:
conditions.append("company=%(company)s")
values["company"] = self.filters.company
-
+
if self.filters.account:
conditions.append("account=%(account)s")
values["account"] = self.filters.account
@@ -149,11 +149,11 @@ class AccountsReceivableReport(object):
if not account_map:
frappe.throw(_("No Customer Accounts found."))
else:
- accounts_list = ['"{0}"'.format(ac) for ac in account_map]
+ accounts_list = ['"{0}"'.format(ac.replace('"', '\"')) for ac in account_map]
conditions.append("account in ({0})".format(", ".join(accounts_list)))
-
+
return " and ".join(conditions), values
-
+
def get_gl_entries_for(self, account, against_voucher_type, against_voucher):
if not hasattr(self, "gl_entries_map"):
self.gl_entries_map = {}
@@ -163,7 +163,7 @@ class AccountsReceivableReport(object):
.setdefault(gle.against_voucher_type, {})\
.setdefault(gle.against_voucher, [])\
.append(gle)
-
+
return self.gl_entries_map.get(account, {})\
.get(against_voucher_type, {})\
.get(against_voucher, [])
@@ -176,15 +176,15 @@ def get_ageing_data(age_as_on, entry_date, outstanding_amount):
outstanding_range = [0.0, 0.0, 0.0, 0.0]
if not (age_as_on and entry_date):
return [0] + outstanding_range
-
+
age = (getdate(age_as_on) - getdate(entry_date)).days or 0
index = None
for i, days in enumerate([30, 60, 90]):
if age <= days:
index = i
break
-
+
if index is None: index = 3
outstanding_range[index] = outstanding_amount
-
+
return [age] + outstanding_range
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index f072b65a461..a57f5441ee5 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -685,7 +685,8 @@
"label": "Recurring Type",
"no_copy": 1,
"options": "Monthly\nQuarterly\nHalf-yearly\nYearly",
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -695,7 +696,8 @@
"fieldtype": "Date",
"label": "From Date",
"no_copy": 1,
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -705,7 +707,8 @@
"fieldtype": "Date",
"label": "To Date",
"no_copy": 1,
- "permlevel": 0
+ "permlevel": 0,
+ "print_hide": 1
},
{
"allow_on_submit": 1,
@@ -772,7 +775,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2014-10-08 14:23:29.718779",
+ "modified": "2014-11-27 17:27:38.839440",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index af0a96ef67c..49845f68683 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -437,7 +437,7 @@ class AccountsController(TransactionBase):
for order, jv_list in order_jv_map.items():
for jv in jv_list:
if not advance_jv_against_si or jv not in advance_jv_against_si:
- frappe.throw(_("Journal Voucher {0} is linked against Order {1}, hence it must be fetched as advance in Invoice as well.")
+ frappe.msgprint(_("Journal Voucher {0} is linked against Order {1}, check if it should be pulled as advance in this invoice.")
.format(jv, order))
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 15f99a9ffc8..e128019099a 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -4,7 +4,7 @@ app_publisher = "Web Notes Technologies Pvt. Ltd. and Contributors"
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
app_icon = "icon-th"
app_color = "#e74c3c"
-app_version = "4.12.0"
+app_version = "4.13.0"
error_report_email = "support@erpnext.com"
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index ecaac4ac371..9ba988e2599 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -118,3 +118,18 @@ cur_frm.cscript.calculate_total_days = function(doc, dt, dn) {
}
cur_frm.fields_dict.employee.get_query = erpnext.queries.employee;
+
+frappe.ui.form.on("Leave Application", "leave_approver", function(frm) {
+ frappe.call({
+ "method": "frappe.client.get",
+ args: {
+ doctype: "User",
+ name: frm.doc.leave_approver
+ },
+ callback: function (data) {
+ frappe.model.set_value(frm.doctype, frm.docname, "leave_approver_name",
+ data.message.first_name
+ + (data.message.last_name ? (" " + data.message.last_name) : ""))
+ }
+ })
+})
diff --git a/erpnext/hr/doctype/leave_application/leave_application.json b/erpnext/hr/doctype/leave_application/leave_application.json
index 9e2ad53c795..8beed8b0285 100644
--- a/erpnext/hr/doctype/leave_application/leave_application.json
+++ b/erpnext/hr/doctype/leave_application/leave_application.json
@@ -24,6 +24,13 @@
"options": "User",
"permlevel": 0
},
+ {
+ "fieldname": "leave_approver_name",
+ "fieldtype": "Read Only",
+ "label": "Leave Approver Name",
+ "permlevel": 0,
+ "precision": ""
+ },
{
"fieldname": "leave_type",
"fieldtype": "Link",
@@ -184,7 +191,7 @@
"idx": 1,
"is_submittable": 1,
"max_attachments": 3,
- "modified": "2014-09-09 05:35:31.531651",
+ "modified": "2014-12-09 16:33:29.626849",
"modified_by": "Administrator",
"module": "HR",
"name": "Leave Application",
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 63eb7961c43..e6742bb71f3 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -203,15 +203,15 @@ class LeaveApplication(Document):
def get_holidays(leave_app):
tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2, `tabEmployee` e1
where e1.name = %s and h1.parent = h2.name and e1.holiday_list = h2.name
- and h1.holiday_date between %s and %s""", (leave_app.employee, leave_app.from_date, leave_app.to_date))
+ and h1.holiday_date between %s and %s""", (leave_app.employee, leave_app.from_date,
+ leave_app.to_date))
# below line is needed. If an employee hasn't been assigned with any holiday list then above will return 0 rows.
- tot_hol=tot_hol and flt(tot_hol[0][0]) or 0
if not tot_hol:
tot_hol = frappe.db.sql("""select count(*) from `tabHoliday` h1, `tabHoliday List` h2
where h1.parent = h2.name and h1.holiday_date between %s and %s
and ifnull(h2.is_default,0) = 1 and h2.fiscal_year = %s""",
(leave_app.from_date, leave_app.to_date, leave_app.fiscal_year))
- return tot_hol and flt(tot_hol[0][0]) or 0
+ return tot_hol and tot_hol[0][0] or 0
@frappe.whitelist()
def get_total_leave_days(leave_app):
diff --git a/erpnext/projects/doctype/time_log/test_time_log.py b/erpnext/projects/doctype/time_log/test_time_log.py
index 4a312adb41b..d0cf6a0328e 100644
--- a/erpnext/projects/doctype/time_log/test_time_log.py
+++ b/erpnext/projects/doctype/time_log/test_time_log.py
@@ -16,6 +16,15 @@ class TestTimeLog(unittest.TestCase):
self.assertRaises(OverlapError, ts.insert)
frappe.db.sql("delete from `tabTime Log`")
+
+ def test_negative_hours(self):
+ frappe.db.sql("delete from `tabTime Log`")
+ test_time_log = frappe.new_doc("Time Log")
+ test_time_log.activity_type = "Communication"
+ test_time_log.from_time = "2013-01-01 11:00:00.000000"
+ test_time_log.to_time = "2013-01-01 10:00:00.000000"
+ self.assertRaises(frappe.ValidationError, test_time_log.save)
+ frappe.db.sql("delete from `tabTime Log`")
test_records = frappe.get_test_records('Time Log')
test_ignore = ["Time Log Batch", "Sales Invoice"]
diff --git a/erpnext/projects/doctype/time_log/time_log.py b/erpnext/projects/doctype/time_log/time_log.py
index eb8afc7729b..7912ff65f9e 100644
--- a/erpnext/projects/doctype/time_log/time_log.py
+++ b/erpnext/projects/doctype/time_log/time_log.py
@@ -19,10 +19,12 @@ class TimeLog(Document):
self.set_status()
self.validate_overlap()
self.calculate_total_hours()
-
+
def calculate_total_hours(self):
from frappe.utils import time_diff_in_hours
self.hours = time_diff_in_hours(self.to_time, self.from_time)
+ if self.hours < 0:
+ frappe.throw(_("'From Time' cannot be later than 'To Time'"))
def set_status(self):
self.status = {
diff --git a/erpnext/public/js/templates/contact_list.html b/erpnext/public/js/templates/contact_list.html
index c4c058c117b..94af7ef4f2e 100644
--- a/erpnext/public/js/templates/contact_list.html
+++ b/erpnext/public/js/templates/contact_list.html
@@ -14,8 +14,11 @@
{% if(contact_list[i].phone) { %}
{%= __("Phone") %}: {%= contact_list[i].phone %}
{% } %}
+ {% if(contact_list[i].mobile_no) { %}
+ {%= __("Mobile No.") %}: {%= contact_list[i].mobile_no %}
+ {% } %}
{% if(contact_list[i].email_id) { %}
- {%= __("Email Id") %}: {%= contact_list[i].email_id %}
+ {%= __("Email ID") %}: {%= contact_list[i].email_id %}
{% } %}
Uses Jinja Templating and all the fields of Address (including Custom Fields if any) will be available
{{ address_line1 }}<br>{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}{{ city }}<br>{% if state %}{{ state }}<br>{% endif -%}{% if pincode %} PIN: {{ pincode }}<br>{% endif -%}{{ country }}<br>{% if phone %}Phone: {{ phone }}<br>{% endif -%}{% if fax %}Fax: {{ fax }}<br>{% endif -%}{% if email_id %}Email: {{ email_id }}<br>{% endif -%}","