Merge pull request #3143 from frappe/fix-travis
Update .travis.yml
diff --git a/erpnext/accounts/doctype/account/account.js b/erpnext/accounts/doctype/account/account.js
index 71acd62..a2eb714 100644
--- a/erpnext/accounts/doctype/account/account.js
+++ b/erpnext/accounts/doctype/account/account.js
@@ -12,12 +12,12 @@
cur_frm.toggle_display('account_name', doc.__islocal);
// hide fields if group
- cur_frm.toggle_display(['account_type', 'tax_rate'], doc.group_or_ledger=='Ledger')
+ cur_frm.toggle_display(['account_type', 'tax_rate'], cint(doc.is_group)==0)
// disable fields
- cur_frm.toggle_enable(['account_name', 'group_or_ledger', 'company'], false);
+ cur_frm.toggle_enable(['account_name', 'is_group', 'company'], false);
- if(doc.group_or_ledger=='Ledger') {
+ if(cint(doc.is_group)==0) {
cur_frm.toggle_display('freeze_account', doc.__onload && doc.__onload.can_freeze_account);
}
@@ -40,7 +40,7 @@
cur_frm.add_fetch('parent_account', 'root_type', 'root_type');
cur_frm.cscript.account_type = function(doc, cdt, cdn) {
- if(doc.group_or_ledger=='Ledger') {
+ if(doc.is_group==0) {
cur_frm.toggle_display(['tax_rate'], doc.account_type == 'Tax');
cur_frm.toggle_display('warehouse', doc.account_type=='Warehouse');
}
@@ -50,10 +50,10 @@
cur_frm.add_custom_button(__('Chart of Accounts'),
function() { frappe.set_route("Accounts Browser", "Account"); }, 'icon-sitemap')
- if (cstr(doc.group_or_ledger) == 'Group') {
- cur_frm.add_custom_button(__('Convert to Ledger'),
+ if (doc.is_group == 1) {
+ cur_frm.add_custom_button(__('Convert to non-Group'),
function() { cur_frm.cscript.convert_to_ledger(); }, 'icon-retweet', 'btn-default');
- } else if (cstr(doc.group_or_ledger) == 'Ledger') {
+ } else if (cint(doc.is_group) == 0) {
cur_frm.add_custom_button(__('View Ledger'), function() {
frappe.route_options = {
"account": doc.name,
@@ -88,7 +88,7 @@
cur_frm.fields_dict['parent_account'].get_query = function(doc) {
return {
filters: {
- "group_or_ledger": "Group",
+ "is_group": 1,
"company": doc.company
}
}
diff --git a/erpnext/accounts/doctype/account/account.json b/erpnext/accounts/doctype/account/account.json
index 4862962..77eaf65 100644
--- a/erpnext/accounts/doctype/account/account.json
+++ b/erpnext/accounts/doctype/account/account.json
@@ -38,18 +38,12 @@
"search_index": 1
},
{
- "default": "Ledger",
- "fieldname": "group_or_ledger",
- "fieldtype": "Select",
- "in_filter": 1,
- "in_list_view": 1,
- "label": "Group or Ledger",
- "oldfieldname": "group_or_ledger",
- "oldfieldtype": "Select",
- "options": "\nLedger\nGroup",
+ "default": "0",
+ "fieldname": "is_group",
+ "fieldtype": "Check",
+ "label": "Is Group",
"permlevel": 0,
- "read_only": 1,
- "reqd": 1,
+ "precision": "",
"search_index": 1
},
{
@@ -107,7 +101,7 @@
"label": "Account Type",
"oldfieldname": "account_type",
"oldfieldtype": "Select",
- "options": "\nBank\nCash\nTax\nChargeable\nWarehouse\nReceivable\nPayable\nEquity\nFixed Asset\nCost of Goods Sold\nExpense Account\nIncome Account\nStock Received But Not Billed\nExpenses Included In Valuation\nStock Adjustment\nStock",
+ "options": "\nBank\nCash\nTax\nChargeable\nWarehouse\nReceivable\nPayable\nEquity\nFixed Asset\nCost of Goods Sold\nExpense Account\nIncome Account\nStock Received But Not Billed\nExpenses Included In Valuation\nStock Adjustment\nStock\nTemporary",
"permlevel": 0,
"search_index": 0
},
@@ -177,7 +171,7 @@
"icon": "icon-money",
"idx": 1,
"in_create": 0,
- "modified": "2015-02-20 05:09:22.108350",
+ "modified": "2015-04-27 20:07:37.147184",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",
@@ -261,5 +255,5 @@
"write": 1
}
],
- "search_fields": "group_or_ledger"
+ "search_fields": "is_group"
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 23fa656..683734b 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -13,7 +13,7 @@
def onload(self):
frozen_accounts_modifier = frappe.db.get_value("Accounts Settings", "Accounts Settings",
"frozen_accounts_modifier")
- if not frozen_accounts_modifier or frozen_accounts_modifier in frappe.user.get_roles():
+ if not frozen_accounts_modifier or frozen_accounts_modifier in frappe.get_roles():
self.get("__onload").can_freeze_account = True
def autoname(self):
@@ -32,12 +32,12 @@
"""Fetch Parent Details and validate parent account"""
if self.parent_account:
par = frappe.db.get_value("Account", self.parent_account,
- ["name", "group_or_ledger", "report_type", "root_type", "company"], as_dict=1)
+ ["name", "is_group", "report_type", "root_type", "company"], as_dict=1)
if not par:
throw(_("Account {0}: Parent account {1} does not exist").format(self.name, self.parent_account))
elif par.name == self.name:
throw(_("Account {0}: You can not assign itself as parent account").format(self.name))
- elif par.group_or_ledger != 'Group':
+ elif not par.is_group:
throw(_("Account {0}: Parent account {1} can not be a ledger").format(self.name, self.parent_account))
elif par.company != self.company:
throw(_("Account {0}: Parent account {1} does not belong to company: {2}")
@@ -59,7 +59,7 @@
if old_value and old_value != self.freeze_account:
frozen_accounts_modifier = frappe.db.get_value('Accounts Settings', None, 'frozen_accounts_modifier')
if not frozen_accounts_modifier or \
- frozen_accounts_modifier not in frappe.user.get_roles():
+ frozen_accounts_modifier not in frappe.get_roles():
throw(_("You are not authorized to set Frozen value"))
def validate_balance_must_be_debit_or_credit(self):
@@ -78,7 +78,7 @@
elif self.check_gle_exists():
throw(_("Account with existing transaction cannot be converted to ledger"))
else:
- self.group_or_ledger = 'Ledger'
+ self.is_group = 0
self.save()
return 1
@@ -88,7 +88,7 @@
elif self.account_type:
throw(_("Cannot covert to Group because Account Type is selected."))
else:
- self.group_or_ledger = 'Group'
+ self.is_group = 1
self.save()
return 1
@@ -160,10 +160,10 @@
throw(_("Account {0} does not exist").format(new))
val = list(frappe.db.get_value("Account", new_account,
- ["group_or_ledger", "root_type", "company"]))
+ ["is_group", "root_type", "company"]))
- if val != [self.group_or_ledger, self.root_type, self.company]:
- throw(_("""Merging is only possible if following properties are same in both records. Group or Ledger, Root Type, Company"""))
+ if val != [self.is_group, self.root_type, self.company]:
+ throw(_("""Merging is only possible if following properties are same in both records. Is Group, Root Type, Company"""))
return new_account
@@ -177,7 +177,7 @@
def get_parent_account(doctype, txt, searchfield, start, page_len, filters):
return frappe.db.sql("""select name from tabAccount
- where group_or_ledger = 'Group' and docstatus != 2 and company = %s
+ where is_group = 1 and docstatus != 2 and company = %s
and %s like %s order by name limit %s, %s""" %
("%s", searchfield, "%s", "%s", "%s"),
(filters["company"], "%%%s%%" % txt, start, page_len), as_list=1)
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
index a27d739..7729d22 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/chart_of_accounts.py
@@ -13,18 +13,18 @@
accounts = []
def _import_accounts(children, parent, root_type, root_account=False):
- for account_name, children in children.items():
+ for account_name, child in children.items():
if root_account:
- root_type = children.get("root_type")
+ root_type = child.get("root_type")
- if account_name not in ["account_type", "root_type", "group_or_ledger"]:
+ if account_name not in ["account_type", "root_type", "is_group"]:
account_name_in_db = unidecode(account_name.strip().lower())
if account_name_in_db in accounts:
count = accounts.count(account_name_in_db)
account_name = account_name + " " + cstr(count)
- group_or_ledger = identify_group_or_ledger(children)
+ is_group = identify_is_group(child)
report_type = "Balance Sheet" if root_type in ["Asset", "Liability", "Equity"] \
else "Profit and Loss"
@@ -33,10 +33,10 @@
"account_name": account_name,
"company": company,
"parent_account": parent,
- "group_or_ledger": group_or_ledger,
+ "is_group": is_group,
"root_type": root_type,
"report_type": report_type,
- "account_type": children.get("account_type")
+ "account_type": child.get("account_type")
})
if root_account:
@@ -46,19 +46,19 @@
accounts.append(account_name_in_db)
- _import_accounts(children, account.name, root_type)
+ _import_accounts(child, account.name, root_type)
_import_accounts(chart, None, None, root_account=True)
-def identify_group_or_ledger(children):
- if children.get("group_or_ledger"):
- group_or_ledger = children.get("group_or_ledger")
- elif len(set(children.keys()) - set(["account_type", "root_type", "group_or_ledger"])):
- group_or_ledger = "Group"
+def identify_is_group(child):
+ if child.get("is_group"):
+ is_group = child.get("is_group")
+ elif len(set(child.keys()) - set(["account_type", "root_type", "is_group"])):
+ is_group = 1
else:
- group_or_ledger = "Ledger"
+ is_group = 0
- return group_or_ledger
+ return is_group
def get_chart(chart_name):
chart = {}
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/ae_uae_chart_template_standard.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/ae_uae_chart_template_standard.json
index 58c4548..1ba0931 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/ae_uae_chart_template_standard.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/ae_uae_chart_template_standard.json
@@ -85,7 +85,7 @@
},
"Stock in Hand": {
"account_type": "Stock",
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
"Perliminary and Preoperating Expenses": {
@@ -326,7 +326,7 @@
},
"Duties and Taxes": {
"account_type": "Tax",
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Accruals & Provisions": {
"Accruals": {
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
index 84e734a..254e2b7 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json
@@ -12,7 +12,7 @@
},
"Bank Accounts": {
"account_type": "Bank",
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Cash In Hand": {
"Cash": {
@@ -21,17 +21,17 @@
"account_type": "Cash"
},
"Loans and Advances (Assets)": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Securities and Deposits": {
"Earnest Money": {}
},
"Stock Assets": {
"account_type": "Stock",
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Tax Assets": {
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
"Fixed Assets": {
@@ -52,10 +52,12 @@
}
},
"Investments": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
- "Temporary Accounts (Assets)": {
- "Temporary Assets": {}
+ "Temporary Accounts": {
+ "Temporary Opening": {
+ "account_type": "Temporary"
+ }
},
"root_type": "Asset"
},
@@ -146,7 +148,7 @@
},
"Indirect Income": {
"account_type": "Income Account",
- "group_or_ledger": "Group"
+ "is_group": 1
},
"root_type": "Income"
},
@@ -168,7 +170,7 @@
},
"Duties and Taxes": {
"account_type": "Tax",
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Loans (Liabilities)": {
"Secured Loans": {},
@@ -176,10 +178,7 @@
"Bank Overdraft Account": {}
}
},
- "Temporary Accounts (Liabilities)": {
- "Temporary Liabilities": {}
- },
"root_type": "Liability"
}
}
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/ni_ni_chart_template.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/ni_ni_chart_template.json
index 6db540a..eafc309 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/ni_ni_chart_template.json
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/ni_ni_chart_template.json
@@ -32,7 +32,7 @@
}
},
"Otros Equivalentes a Efectivo": {
- "group_or_ledger": "Group",
+ "is_group": 1,
"account_type": "Cash"
}
},
@@ -61,7 +61,7 @@
"Estimacion para Cuentas Incobrables": {}
},
"Inventarios": {
- "group_or_ledger": "Group",
+ "is_group": 1,
"account_type": "Stock"
},
"Impuestos Acreditables": {
@@ -90,7 +90,7 @@
"Retenciones Definitivas Sobre Rentas o Ganancias de Capital": {}
},
"Otras Cuentas por Cobrar": {
- "group_or_ledger": "Group",
+ "is_group": 1,
"account_type": "Receivable"
}
},
@@ -110,11 +110,11 @@
},
"Inversiones Permanentes": {
"Inversiones Permanentes": {
- "group_or_ledger": "Group",
+ "is_group": 1,
"account_type": "Fixed Asset"
},
"Negocios Conjuntos": {
- "group_or_ledger": "Group",
+ "is_group": 1,
"account_type": "Fixed Asset"
}
},
@@ -124,25 +124,25 @@
},
"Activos Intangibles": {
"Patentes": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Marcas Registradas": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Derechos de Autor": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Concesiones": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Licencias": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Gastos de investigacion": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Amortizacion de Activos Intangibles": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Deterioro de Valor de Activos Intangibles": {}
},
@@ -150,29 +150,29 @@
"Gastos de Consitucion": {},
"Gastos Pre Operativos": {},
"Mejoras en Bienes Arrendados": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Amortizacion de Activos Amortizables": {},
"Deterioro de Valaor de Activos Amortizables": {}
},
"Cuentas por Cobrar a Largo Plazo": {
"Creditos a Largo Plazo": {
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
"Inversiones a Largo Plazo": {
"Depositos Bancarios a Plazo": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Intereses percibidos por adelantado": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Titulos y Acciones": {
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
"Activo por Impuestos Diferidos": {
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
"root_type": "Asset"
@@ -199,21 +199,21 @@
"Anticipos de Clientes": {},
"Pasivos Financieros a Corto Plazo": {
"Prestamos por Pagar a Corto Plazo": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Sobregiros Bancarios": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Otras Deudas Bancarias": {
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
"Gastos por Pagar": {
"Servicios Basicos": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Prestaciones Sociales": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Salarios por Pagar": {}
},
@@ -287,28 +287,28 @@
}
},
"Otras Cuentas por Pagar": {
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
"Pasivo No Corriente": {
"Prestamos a Largo Plazo": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Cuentas por Pagar a Largo Plaso": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Otras Cuentas por Pagar a Largo Plazo": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Otros Pasivos Financieros a Largo Plaso": {
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
"Obligaciones por Arrendamiento Financiero a Largo Plazo": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Pasivo por Impuestos Diferidos": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"root_type": "Liability"
},
@@ -324,7 +324,7 @@
}
},
"Donaciones": {
- "group_or_ledger": "Group"
+ "is_group": 1
},
"Ganancias Acumuladas": {
"Reservas": {
diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
index 7236631..dd3c067 100644
--- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
+++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/standard_chart_of_accounts.py
@@ -15,7 +15,7 @@
},
_("Bank Accounts"): {
"account_type": "Bank",
- "group_or_ledger": "Group"
+ "is_group": 1
},
_("Cash In Hand"): {
_("Cash"): {
@@ -24,17 +24,17 @@
"account_type": "Cash"
},
_("Loans and Advances (Assets)"): {
- "group_or_ledger": "Group"
+ "is_group": 1
},
_("Securities and Deposits"): {
_("Earnest Money"): {}
},
_("Stock Assets"): {
"account_type": "Stock",
- "group_or_ledger": "Group"
+ "is_group": 1
},
_("Tax Assets"): {
- "group_or_ledger": "Group"
+ "is_group": 1
}
},
_("Fixed Assets"): {
@@ -55,10 +55,12 @@
}
},
_("Investments"): {
- "group_or_ledger": "Group"
+ "is_group": 1
},
- _("Temporary Accounts (Assets)"): {
- _("Temporary Assets"): {}
+ _("Temporary Accounts"): {
+ _("Temporary Opening"): {
+ "account_type": "Temporary"
+ }
},
"root_type": "Asset"
},
@@ -149,7 +151,7 @@
},
_("Indirect Income"): {
"account_type": "Income Account",
- "group_or_ledger": "Group"
+ "is_group": 1
},
"root_type": "Income"
},
@@ -167,7 +169,7 @@
},
_("Duties and Taxes"): {
"account_type": "Tax",
- "group_or_ledger": "Group"
+ "is_group": 1
},
_("Loans (Liabilities)"): {
_("Secured Loans"): {},
@@ -175,9 +177,6 @@
_("Bank Overdraft Account"): {},
},
},
- _("Temporary Accounts (Liabilities)"): {
- _("Temporary Liabilities"): {}
- },
"root_type": "Liability"
},
_("Equity"): {
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index 985b884..2a3feda 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -8,37 +8,37 @@
from frappe.test_runner import make_test_objects
accounts = [
- # [account_name, parent_account, group_or_ledger]
- ["_Test Account Bank Account", "Bank Accounts", "Ledger", "Bank"],
+ # [account_name, parent_account, is_group]
+ ["_Test Account Bank Account", "Bank Accounts", 0, "Bank"],
- ["_Test Account Stock Expenses", "Direct Expenses", "Group", None],
- ["_Test Account Shipping Charges", "_Test Account Stock Expenses", "Ledger", "Chargeable"],
- ["_Test Account Customs Duty", "_Test Account Stock Expenses", "Ledger", "Tax"],
- ["_Test Account Insurance Charges", "_Test Account Stock Expenses", "Ledger", "Chargeable"],
- ["_Test Account Stock Adjustment", "_Test Account Stock Expenses", "Ledger", "Stock Adjustment"],
+ ["_Test Account Stock Expenses", "Direct Expenses", 1, None],
+ ["_Test Account Shipping Charges", "_Test Account Stock Expenses", 0, "Chargeable"],
+ ["_Test Account Customs Duty", "_Test Account Stock Expenses", 0, "Tax"],
+ ["_Test Account Insurance Charges", "_Test Account Stock Expenses", 0, "Chargeable"],
+ ["_Test Account Stock Adjustment", "_Test Account Stock Expenses", 0, "Stock Adjustment"],
- ["_Test Account Tax Assets", "Current Assets", "Group", None],
- ["_Test Account VAT", "_Test Account Tax Assets", "Ledger", "Tax"],
- ["_Test Account Service Tax", "_Test Account Tax Assets", "Ledger", "Tax"],
+ ["_Test Account Tax Assets", "Current Assets", 1, None],
+ ["_Test Account VAT", "_Test Account Tax Assets", 0, "Tax"],
+ ["_Test Account Service Tax", "_Test Account Tax Assets", 0, "Tax"],
- ["_Test Account Reserves and Surplus", "Current Liabilities", "Ledger", None],
+ ["_Test Account Reserves and Surplus", "Current Liabilities", 0, None],
- ["_Test Account Cost for Goods Sold", "Expenses", "Ledger", None],
- ["_Test Account Excise Duty", "_Test Account Tax Assets", "Ledger", "Tax"],
- ["_Test Account Education Cess", "_Test Account Tax Assets", "Ledger", "Tax"],
- ["_Test Account S&H Education Cess", "_Test Account Tax Assets", "Ledger", "Tax"],
- ["_Test Account CST", "Direct Expenses", "Ledger", "Tax"],
- ["_Test Account Discount", "Direct Expenses", "Ledger", None],
- ["_Test Write Off", "Indirect Expenses", "Ledger", None],
+ ["_Test Account Cost for Goods Sold", "Expenses", 0, None],
+ ["_Test Account Excise Duty", "_Test Account Tax Assets", 0, "Tax"],
+ ["_Test Account Education Cess", "_Test Account Tax Assets", 0, "Tax"],
+ ["_Test Account S&H Education Cess", "_Test Account Tax Assets", 0, "Tax"],
+ ["_Test Account CST", "Direct Expenses", 0, "Tax"],
+ ["_Test Account Discount", "Direct Expenses", 0, None],
+ ["_Test Write Off", "Indirect Expenses", 0, None],
# related to Account Inventory Integration
- ["_Test Account Stock In Hand", "Current Assets", "Ledger", None],
- ["_Test Account Fixed Assets", "Current Assets", "Ledger", None],
+ ["_Test Account Stock In Hand", "Current Assets", 0, None],
+ ["_Test Account Fixed Assets", "Current Assets", 0, None],
# Receivable / Payable Account
- ["_Test Receivable", "Current Assets", "Ledger", "Receivable"],
- ["_Test Payable", "Current Liabilities", "Ledger", "Payable"],
+ ["_Test Receivable", "Current Assets", 0, "Receivable"],
+ ["_Test Payable", "Current Liabilities", 0, "Payable"],
]
for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]:
@@ -47,8 +47,8 @@
"account_name": account_name,
"parent_account": parent_account + " - " + abbr,
"company": company,
- "group_or_ledger": group_or_ledger,
+ "is_group": is_group,
"account_type": account_type
- } for account_name, parent_account, group_or_ledger, account_type in accounts])
+ } for account_name, parent_account, is_group, account_type in accounts])
return test_objects
diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js
index 96f9007..c39550b 100644
--- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js
+++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.js
@@ -26,7 +26,7 @@
return {
"filters": {
"account_type": "Bank",
- "group_or_ledger": "Ledger"
+ "is_group": 0
}
};
});
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js
index 1b4451f..6946bcb 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.js
+++ b/erpnext/accounts/doctype/cost_center/cost_center.js
@@ -18,7 +18,7 @@
filters:[
['Account', 'company', '=', me.frm.doc.company],
['Account', 'report_type', '=', 'Profit and Loss'],
- ['Account', 'group_or_ledger', '=', 'Ledger'],
+ ['Account', 'is_group', '=', '0'],
]
}
});
@@ -27,7 +27,7 @@
this.frm.set_query("parent_cost_center", function() {
return {
filters:[
- ['Cost Center', 'group_or_ledger', '=', 'Group'],
+ ['Cost Center', 'is_group', '=', '1'],
['Cost Center', 'company', '=', me.frm.doc.company],
]
}
@@ -40,15 +40,15 @@
cur_frm.cscript.refresh = function(doc, cdt, cdn) {
var intro_txt = '';
cur_frm.toggle_display('cost_center_name', doc.__islocal);
- cur_frm.toggle_enable(['group_or_ledger', 'company'], doc.__islocal);
+ cur_frm.toggle_enable(['is_group', 'company'], doc.__islocal);
- if(!doc.__islocal && doc.group_or_ledger=='Group') {
+ if(!doc.__islocal && doc.is_group==1) {
intro_txt += __('Note: This Cost Center is a Group. Cannot make accounting entries against groups.');
}
cur_frm.cscript.hide_unhide_group_ledger(doc);
- cur_frm.toggle_display('sb1', doc.group_or_ledger=='Ledger')
+ cur_frm.toggle_display('sb1', doc.is_group==0)
cur_frm.set_intro(intro_txt);
cur_frm.add_custom_button(__('Chart of Cost Centers'),
@@ -62,11 +62,11 @@
}
cur_frm.cscript.hide_unhide_group_ledger = function(doc) {
- if (cstr(doc.group_or_ledger) == 'Group') {
- cur_frm.add_custom_button(__('Convert to Ledger'),
+ if (doc.is_group == 1) {
+ cur_frm.add_custom_button(__('Convert to non-Group'),
function() { cur_frm.cscript.convert_to_ledger(); }, 'icon-retweet',
"btn-default")
- } else if (cstr(doc.group_or_ledger) == 'Ledger') {
+ } else if (doc.is_group == 0) {
cur_frm.add_custom_button(__('Convert to Group'),
function() { cur_frm.cscript.convert_to_group(); }, 'icon-retweet',
"btn-default")
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.json b/erpnext/accounts/doctype/cost_center/cost_center.json
index b37fa96..409f59c 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.json
+++ b/erpnext/accounts/doctype/cost_center/cost_center.json
@@ -58,18 +58,12 @@
"width": "50%"
},
{
- "fieldname": "group_or_ledger",
- "fieldtype": "Select",
- "hidden": 0,
- "label": "Group or Ledger",
- "no_copy": 1,
- "oldfieldname": "group_or_ledger",
- "oldfieldtype": "Select",
- "options": "\nGroup\nLedger",
+ "default": "0",
+ "fieldname": "is_group",
+ "fieldtype": "Check",
+ "label": "Is Group",
"permlevel": 0,
- "print_hide": 1,
- "report_hide": 1,
- "reqd": 1
+ "precision": ""
},
{
"description": "Define Budget for this Cost Center. To set budget action, see <a href=\"#!List/Company\">Company Master</a>",
@@ -145,7 +139,7 @@
"icon": "icon-money",
"idx": 1,
"in_create": 0,
- "modified": "2015-02-20 05:07:59.251051",
+ "modified": "2015-04-23 02:54:26.934607",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Cost Center",
@@ -198,5 +192,5 @@
"role": "Material User"
}
],
- "search_fields": "parent_cost_center"
+ "search_fields": "parent_cost_center, is_group"
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py
index b6cc503..f26c80b 100644
--- a/erpnext/accounts/doctype/cost_center/cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/cost_center.py
@@ -16,9 +16,6 @@
frappe.db.get_value("Company", self.company, "abbr")
def validate_mandatory(self):
- if not self.group_or_ledger:
- msgprint(_("Please select Group or Ledger value"), raise_exception=1)
-
if self.cost_center_name != self.company and not self.parent_cost_center:
msgprint(_("Please enter parent cost center"), raise_exception=1)
elif self.cost_center_name == self.company and self.parent_cost_center:
@@ -30,7 +27,7 @@
elif self.check_gle_exists():
msgprint(_("Cost Center with existing transactions can not be converted to ledger"), raise_exception=1)
else:
- self.group_or_ledger = 'Ledger'
+ self.is_group = 0
self.save()
return 1
@@ -38,7 +35,7 @@
if self.check_gle_exists():
msgprint(_("Cost Center with existing transactions can not be converted to group"), raise_exception=1)
else:
- self.group_or_ledger = 'Group'
+ self.is_group = 1
self.save()
return 1
@@ -52,7 +49,7 @@
def validate_budget_details(self):
check_acc_list = []
for d in self.get('budgets'):
- if self.group_or_ledger=="Group":
+ if self.is_group==1:
msgprint(_("Budget cannot be set for Group Cost Centers"), raise_exception=1)
if [d.account, d.fiscal_year] in check_acc_list:
@@ -70,7 +67,7 @@
new_cost_center = get_name_with_abbr(newdn, self.company)
# Validate properties before merging
- super(CostCenter, self).before_rename(olddn, new_cost_center, merge, "group_or_ledger")
+ super(CostCenter, self).before_rename(olddn, new_cost_center, merge, "is_group")
return new_cost_center
diff --git a/erpnext/accounts/doctype/cost_center/test_records.json b/erpnext/accounts/doctype/cost_center/test_records.json
index 7486214..129f0db 100644
--- a/erpnext/accounts/doctype/cost_center/test_records.json
+++ b/erpnext/accounts/doctype/cost_center/test_records.json
@@ -13,21 +13,21 @@
"cost_center_name": "_Test Cost Center",
"distribution_id": "_Test Distribution",
"doctype": "Cost Center",
- "group_or_ledger": "Ledger",
+ "is_group": 0,
"parent_cost_center": "_Test Company - _TC"
},
{
"company": "_Test Company",
"cost_center_name": "_Test Cost Center 2",
"doctype": "Cost Center",
- "group_or_ledger": "Ledger",
+ "is_group": 0,
"parent_cost_center": "_Test Company - _TC"
},
{
"company": "_Test Company",
"cost_center_name": "_Test Write Off Cost Center",
"doctype": "Cost Center",
- "group_or_ledger": "Ledger",
+ "is_group": 0,
"parent_cost_center": "_Test Company - _TC"
}
]
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json
index ffb3f9b..54c7dd6 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.json
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json
@@ -25,17 +25,6 @@
"permlevel": 0
},
{
- "fieldname": "aging_date",
- "fieldtype": "Date",
- "in_filter": 1,
- "in_list_view": 1,
- "label": "Aging Date",
- "oldfieldname": "aging_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "search_index": 0
- },
- {
"fieldname": "account",
"fieldtype": "Link",
"in_filter": 1,
@@ -203,7 +192,7 @@
"icon": "icon-list",
"idx": 1,
"in_create": 1,
- "modified": "2014-09-11 18:35:22.822064",
+ "modified": "2015-04-27 20:32:48.246818",
"modified_by": "Administrator",
"module": "Accounts",
"name": "GL Entry",
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 54acc9e..ae4dae0 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -63,10 +63,10 @@
def validate_account_details(self, adv_adj):
"""Account must be ledger, active and not freezed"""
- ret = frappe.db.sql("""select group_or_ledger, docstatus, company
+ ret = frappe.db.sql("""select is_group, docstatus, company
from tabAccount where name=%s""", self.account, as_dict=1)[0]
- if ret.group_or_ledger=='Group':
+ if ret.is_group==1:
frappe.throw(_("Account {0} cannot be a Group").format(self.account))
if ret.docstatus==2:
@@ -110,7 +110,7 @@
if acc_frozen_upto:
frozen_accounts_modifier = frappe.db.get_value( 'Accounts Settings', None,'frozen_accounts_modifier')
if getdate(posting_date) <= getdate(acc_frozen_upto) \
- and not frozen_accounts_modifier in frappe.user.get_roles():
+ and not frozen_accounts_modifier in frappe.get_roles():
frappe.throw(_("You are not authorized to add or update entries before {0}").format(formatdate(acc_frozen_upto)))
def update_outstanding_amt(account, party_type, party, against_voucher_type, against_voucher, on_cancel=False):
@@ -155,5 +155,5 @@
if not frozen_accounts_modifier:
frappe.throw(_("Account {0} is frozen").format(account))
- elif frozen_accounts_modifier not in frappe.user.get_roles():
+ elif frozen_accounts_modifier not in frappe.get_roles():
frappe.throw(_("Not authorized to edit frozen Account {0}").format(account))
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 2b0003e..5ff9e5f 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -36,7 +36,7 @@
return {
filters: {
company: me.frm.doc.company,
- group_or_ledger: "Ledger"
+ is_group: 0
}
};
});
@@ -136,7 +136,6 @@
cur_frm.script_manager.make(erpnext.accounts.JournalVoucher);
cur_frm.cscript.refresh = function(doc) {
- cur_frm.cscript.is_opening(doc)
erpnext.toggle_naming_series();
cur_frm.cscript.voucher_type(doc);
@@ -163,11 +162,6 @@
erpnext.get_fiscal_year(doc.company, doc.posting_date);
}
-cur_frm.cscript.is_opening = function(doc, cdt, cdn) {
- hide_field('aging_date');
- if (doc.is_opening == 'Yes') unhide_field('aging_date');
-}
-
cur_frm.cscript.update_totals = function(doc) {
var td=0.0; var tc =0.0;
var el = doc.accounts || [];
@@ -231,7 +225,7 @@
var jvdetail = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
$.each(r, function(i, d) {
var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
- row.account = d.cash_bank_account;
+ row.account = d.account;
row.balance = d.balance;
});
refresh_field("accounts");
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index 5ebac38..6eb395d 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -295,18 +295,6 @@
"search_index": 1
},
{
- "description": "",
- "fieldname": "aging_date",
- "fieldtype": "Date",
- "label": "Ageing Date",
- "no_copy": 0,
- "oldfieldname": "aging_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 1,
- "read_only": 0
- },
- {
"default": "Accounts Receivable",
"depends_on": "eval:doc.voucher_type == 'Write Off Entry'",
"fieldname": "write_off_based_on",
@@ -457,7 +445,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2015-03-25 07:11:27.108475",
+ "modified": "2015-04-27 20:32:31.655580",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Journal Entry",
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 0873b9b..6317793 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -32,7 +32,6 @@
self.validate_against_purchase_invoice()
self.set_against_account()
self.create_remarks()
- self.set_aging_date()
self.set_print_format_fields()
self.validate_against_sales_order()
self.validate_against_purchase_order()
@@ -306,18 +305,6 @@
if r:
self.remark = ("\n").join(r) #User Remarks is not mandatory
-
- def set_aging_date(self):
- if self.is_opening != 'Yes':
- self.aging_date = self.posting_date
- else:
- party_list = [d.party for d in self.get("accounts") if d.party_type and d.party]
-
- if len(party_list) and not self.aging_date:
- frappe.throw(_("Aging Date is mandatory for opening entry"))
- else:
- self.aging_date = self.posting_date
-
def set_print_format_fields(self):
for d in self.get('accounts'):
if d.party_type and d.party:
@@ -448,13 +435,12 @@
Pending Amount is {2}".format(d.idx, d.against_expense_claim, pending_amount)))
def validate_credit_debit_note(self):
- count = frappe.db.exists({
- "doctype": "Journal Entry",
- "stock_entry":self.stock_entry,
- "docstatus":1
- })
- if count:
- frappe.throw(_("{0} already made against stock entry {1}".format(self.voucher_type, self.stock_entry)))
+ if self.stock_entry:
+ if frappe.db.get_value("Stock Entry", self.stock_entry, "docstatus") != 1:
+ frappe.throw(_("Stock Entry {0} is not submitted").format(self.stock_entry))
+
+ if frappe.db.exists({"doctype": "Journal Entry", "stock_entry": self.stock_entry, "docstatus":1}):
+ frappe.msgprint(_("Warning: Another {0} # {1} exists against stock entry {2}".format(self.voucher_type, self.name, self.stock_entry)))
def validate_empty_accounts_table(self):
if not self.get('accounts'):
@@ -465,8 +451,8 @@
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
if mode_of_payment:
account = get_bank_cash_account(mode_of_payment, company)
- if account.get("bank_cash_account"):
- account.update({"balance": get_balance_on(account.get("bank_cash_account"))})
+ if account.get("account"):
+ account.update({"balance": get_balance_on(account.get("account"))})
return account
if voucher_type=="Bank Entry":
@@ -480,7 +466,7 @@
if account:
return {
- "cash_bank_account": account,
+ "account": account,
"balance": get_balance_on(account)
}
@@ -537,7 +523,7 @@
d2 = jv.append("accounts")
if bank_account:
- d2.account = bank_account["cash_bank_account"]
+ d2.account = bank_account["account"]
d2.balance = bank_account["balance"]
return jv
@@ -546,7 +532,7 @@
def get_opening_accounts(company):
"""get all balance sheet accounts for opening entry"""
accounts = frappe.db.sql_list("""select name from tabAccount
- where group_or_ledger='Ledger' and report_type='Balance Sheet' and company=%s""", company)
+ where is_group=0 and report_type='Balance Sheet' and company=%s""", company)
return [{"account": a, "balance": get_balance_on(a)} for a in accounts]
diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
index a052375..10807ff 100644
--- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
+++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.js
@@ -5,7 +5,7 @@
return{
filters: [
['Account', 'account_type', 'in', 'Bank, Cash'],
- ['Account', 'group_or_ledger', '=', 'Ledger'],
+ ['Account', 'is_group', '=', 0],
['Account', 'company', '=', doc.company]
]
}
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index 9394bcb..71df6cf 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -22,7 +22,7 @@
return{
filters: {
"company": me.frm.doc.company,
- "group_or_ledger": "Ledger",
+ "is_group": 0,
"account_type": (me.frm.doc.party_type == "Customer" ? "Receivable" : "Payable")
}
};
@@ -37,7 +37,7 @@
return{
filters:[
['Account', 'company', '=', me.frm.doc.company],
- ['Account', 'group_or_ledger', '=', 'Ledger'],
+ ['Account', 'is_group', '=', 0],
['Account', 'account_type', 'in', ['Bank', 'Cash']]
]
};
diff --git a/erpnext/accounts/doctype/payment_tool/payment_tool.js b/erpnext/accounts/doctype/payment_tool/payment_tool.js
index eb44161..cff0bd2 100644
--- a/erpnext/accounts/doctype/payment_tool/payment_tool.js
+++ b/erpnext/accounts/doctype/payment_tool/payment_tool.js
@@ -18,7 +18,7 @@
return {
filters: {
"account_type": ["in", ["Bank", "Cash"]],
- "group_or_ledger": "Ledger",
+ "is_group": 0,
"company": frm.doc.company
}
}
@@ -74,10 +74,9 @@
"mode_of_payment": frm.doc.payment_mode,
"company": frm.doc.company
},
- callback: function(r, rt) {
+ callback: function(r, rt) {
if(r.message) {
- frm.doc.set_value("payment_account", r.message['bank_cash_account']
-);
+ cur_frm.set_value("payment_account", r.message['account']);
}
}
});
diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js
index 2f2fc7c..c087500 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js
@@ -15,7 +15,7 @@
"company": doc.company,
"report_type": "Balance Sheet",
"freeze_account": "No",
- "group_or_ledger": "Ledger"
+ "is_group": 0
}
- }
+ }
}
diff --git a/erpnext/accounts/doctype/pos_setting/pos_setting.js b/erpnext/accounts/doctype/pos_setting/pos_setting.js
index 8004e3e..db5fec1 100755
--- a/erpnext/accounts/doctype/pos_setting/pos_setting.js
+++ b/erpnext/accounts/doctype/pos_setting/pos_setting.js
@@ -22,7 +22,7 @@
return{
filters:{
'report_type': "Balance Sheet",
- 'group_or_ledger': "Ledger",
+ 'is_group': 0,
'company': doc.company
}
}
@@ -33,7 +33,7 @@
cur_frm.fields_dict['income_account'].get_query = function(doc,cdt,cdn) {
return{
filters:{
- 'group_or_ledger': "Ledger",
+ 'is_group': 0,
'company': doc.company,
'account_type': "Income Account"
}
@@ -47,7 +47,7 @@
return{
filters:{
'company': doc.company,
- 'group_or_ledger': "Ledger"
+ 'is_group': 0
}
}
}
@@ -60,7 +60,7 @@
filters: {
"report_type": "Profit and Loss",
"company": doc.company,
- "group_or_ledger": "Ledger"
+ "is_group": 0
}
}
}
@@ -83,7 +83,7 @@
return{
filters:{
'report_type': 'Profit and Loss',
- 'group_or_ledger': 'Ledger',
+ 'is_group': 0,
'company': doc.company
}
}
@@ -94,7 +94,7 @@
cur_frm.fields_dict.write_off_cost_center.get_query = function(doc) {
return{
filters:{
- 'group_or_ledger': 'Ledger',
+ 'is_group': 0,
'company': doc.company
}
}
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 9da83b6..3e16a31 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -67,8 +67,6 @@
}, "icon-download", "btn-default");
}
-
- this.is_opening(doc);
},
supplier: function() {
@@ -116,11 +114,6 @@
cur_frm.script_manager.make(erpnext.accounts.PurchaseInvoice);
-cur_frm.cscript.is_opening = function(doc, dt, dn) {
- hide_field('aging_date');
- if (doc.is_opening == 'Yes') unhide_field('aging_date');
-}
-
cur_frm.cscript.make_bank_entry = function() {
return frappe.call({
method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_payment_entry_from_purchase_invoice",
@@ -161,7 +154,7 @@
filters:{
'account_type': 'Payable',
'root_type': 'Liability',
- 'group_or_ledger': 'Ledger',
+ 'is_group': 0,
'company': doc.company
}
}
@@ -198,7 +191,7 @@
return {
filters: {
'company': doc.company,
- 'group_or_ledger': 'Ledger'
+ 'is_group': 0
}
}
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 6cb1169..edbefba 100755
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -6,21 +6,6 @@
"doctype": "DocType",
"fields": [
{
- "fieldname": "supplier_section",
- "fieldtype": "Section Break",
- "label": "",
- "options": "icon-user",
- "permlevel": 0
- },
- {
- "fieldname": "column_break0",
- "fieldtype": "Column Break",
- "oldfieldtype": "Column Break",
- "permlevel": 0,
- "read_only": 0,
- "width": "50%"
- },
- {
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Series",
@@ -750,18 +735,6 @@
"search_index": 1
},
{
- "description": "Actual Invoice Date",
- "fieldname": "aging_date",
- "fieldtype": "Date",
- "label": "Aging Date",
- "oldfieldname": "aging_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 1,
- "read_only": 0,
- "search_index": 0
- },
- {
"allow_on_submit": 1,
"fieldname": "select_print_heading",
"fieldtype": "Link",
@@ -965,7 +938,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2015-03-23 14:47:57.373436",
+ "modified": "2015-04-30 03:05:13.790265",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 0e7a640..c0ebf68 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -47,7 +47,6 @@
self.check_for_stopped_status()
self.validate_with_previous_doc()
self.validate_uom_is_integer("uom", "qty")
- self.set_aging_date()
self.set_against_expense_account()
self.validate_write_off_account()
self.update_valuation_rate("items")
@@ -141,13 +140,6 @@
}
})
-
- def set_aging_date(self):
- if self.is_opening != 'Yes':
- self.aging_date = self.posting_date
- elif not self.aging_date:
- throw(_("Ageing date is mandatory for opening entry"))
-
def set_against_expense_account(self):
auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
@@ -173,7 +165,7 @@
elif item.expense_account not in against_accounts:
# if no auto_accounting_for_stock or not a stock item
against_accounts.append(item.expense_account)
-
+
self.against_expense_account = ",".join(against_accounts)
def po_required(self):
@@ -247,6 +239,7 @@
self.update_against_document_in_jv()
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
+ self.update_project()
def make_gl_entries(self):
auto_accounting_for_stock = \
@@ -288,7 +281,7 @@
)
# accumulate valuation tax
- if tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
+ if self.is_opening == "No" and tax.category in ("Valuation", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount):
if auto_accounting_for_stock and not tax.cost_center:
frappe.throw(_("Cost Center is required in row {0} in Taxes table for type {1}").format(tax.idx, _(tax.category)))
valuation_tax.setdefault(tax.cost_center, 0)
@@ -310,7 +303,8 @@
})
)
- if auto_accounting_for_stock and item.item_code in stock_items and item.item_tax_amount:
+ if auto_accounting_for_stock and self.is_opening == "No" and \
+ item.item_code in stock_items and item.item_tax_amount:
# Post reverse entry for Stock-Received-But-Not-Billed if it is booked in Purchase Receipt
negative_expense_booked_in_pi = None
if item.purchase_receipt:
@@ -330,7 +324,7 @@
negative_expense_to_be_booked += flt(item.item_tax_amount, self.precision("item_tax_amount", item))
- if negative_expense_to_be_booked and valuation_tax:
+ if self.is_opening == "No" and negative_expense_to_be_booked and valuation_tax:
# credit valuation tax amount in "Expenses Included In Valuation"
# this will balance out valuation amount included in cost of goods sold
@@ -380,9 +374,17 @@
self.update_prevdoc_status()
self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
self.make_gl_entries_on_cancel()
-
- def on_update(self):
- pass
+ self.update_project()
+
+ def update_project(self):
+ project_list = []
+ for d in self.items:
+ if d.project_name and d.project_name not in project_list:
+ project = frappe.get_doc("Project", d.project_name)
+ project.flags.dont_sync_tasks = True
+ project.update_purchase_costing()
+ project.save()
+ project_list.append(d.project_name)
@frappe.whitelist()
def get_expense_account(doctype, txt, searchfield, start, page_len, filters):
@@ -393,10 +395,10 @@
# Hence the first condition is an "OR"
return frappe.db.sql("""select tabAccount.name from `tabAccount`
where (tabAccount.report_type = "Profit and Loss"
- or tabAccount.account_type in ("Expense Account", "Fixed Asset"))
- and tabAccount.group_or_ledger="Ledger"
+ or tabAccount.account_type in ("Expense Account", "Fixed Asset", "Temporary"))
+ and tabAccount.is_group=0
and tabAccount.docstatus!=2
and tabAccount.company = '%(company)s'
and tabAccount.%(key)s LIKE '%(txt)s'
%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
- 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
\ No newline at end of file
+ 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 5ae47d7..7f46b08 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -6,7 +6,6 @@
import unittest
import frappe
import frappe.model
-import json
from frappe.utils import cint
import frappe.defaults
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \
@@ -234,5 +233,47 @@
def test_recurring_invoice(self):
from erpnext.controllers.tests.test_recurring_document import test_recurring_document
test_recurring_document(self, test_records)
+
+ def test_total_purchase_cost_for_project(self):
+ purchase_invoice = frappe.new_doc('Purchase Invoice')
+ purchase_invoice.update({
+ "credit_to": "_Test Payable - _TC",
+ "supplier": "_Test Supplier",
+ "company": "_Test Company",
+ "items": [
+ {
+ "rate": 500,
+ "qty": 1,
+ "project_name": "_Test Project",
+ "item_code": "_Test Item Home Desktop 100",
+ "expense_account": "_Test Account Cost for Goods Sold - _TC",
+ "cost_center": "_Test Cost Center - _TC"
+ },
+ {
+ "rate": 1500,
+ "qty": 1,
+ "project_name": "_Test Project",
+ "item_code": "_Test Item Home Desktop 200",
+ "expense_account": "_Test Account Cost for Goods Sold - _TC",
+ "cost_center": "_Test Cost Center - _TC"
+ }
+ ]
+ })
+ purchase_invoice.save()
+ purchase_invoice.submit()
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 2000)
+
+ purchase_invoice1 = frappe.copy_doc(purchase_invoice)
+ purchase_invoice1.save()
+ purchase_invoice1.submit()
+
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 4000)
+
+ purchase_invoice1.cancel()
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 2000)
+
+ purchase_invoice.cancel()
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), 0)
+
test_records = frappe.get_test_records('Purchase Invoice')
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index ade0d32..96b47c6 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -39,7 +39,6 @@
refresh: function(doc, dt, dn) {
this._super();
- cur_frm.cscript.is_opening(doc, dt, dn);
cur_frm.dashboard.reset();
if(doc.docstatus==1) {
@@ -254,6 +253,12 @@
"mode_of_payment": doc.mode_of_payment,
"company": doc.company
},
+ callback: function(r, rt) {
+ if(r.message) {
+ cur_frm.set_value("cash_bank_account", r.message["account"]);
+ }
+
+ }
});
}
}
@@ -262,11 +267,6 @@
cur_frm.cscript.hide_fields(doc, dt, dn);
}
-cur_frm.cscript.is_opening = function(doc, dt, dn) {
- hide_field('aging_date');
- if (doc.is_opening == 'Yes') unhide_field('aging_date');
-}
-
cur_frm.cscript['Make Delivery Note'] = function() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_delivery_note",
@@ -291,7 +291,7 @@
return{
filters: {
'report_type': 'Balance Sheet',
- 'group_or_ledger': 'Ledger',
+ 'is_group': 0,
'company': doc.company
}
}
@@ -302,7 +302,7 @@
filters: [
["Account", "account_type", "in", ["Cash", "Bank"]],
["Account", "root_type", "=", "Asset"],
- ["Account", "group_or_ledger", "=", "Ledger"],
+ ["Account", "is_group", "=",0],
["Account", "company", "=", doc.company]
]
}
@@ -312,7 +312,7 @@
return{
filters:{
'report_type': 'Profit and Loss',
- 'group_or_ledger': 'Ledger',
+ 'is_group': 0,
'company': doc.company
}
}
@@ -323,7 +323,7 @@
cur_frm.fields_dict.write_off_cost_center.get_query = function(doc) {
return{
filters:{
- 'group_or_ledger': 'Ledger',
+ 'is_group': 0,
'company': doc.company
}
}
@@ -354,7 +354,7 @@
filters: {
'report_type': 'Profit and Loss',
'company': doc.company,
- 'group_or_ledger': 'Ledger'
+ "is_group": 0
}
}
}
@@ -367,7 +367,7 @@
return {
filters: {
'company': doc.company,
- 'group_or_ledger': 'Ledger'
+ "is_group": 0
}
}
}
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 11ae3b5..46c68e9 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -987,17 +987,6 @@
"read_only": 0
},
{
- "description": "Actual Invoice Date",
- "fieldname": "aging_date",
- "fieldtype": "Date",
- "label": "Aging Date",
- "oldfieldname": "aging_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "print_hide": 1,
- "read_only": 0
- },
- {
"fieldname": "fiscal_year",
"fieldtype": "Link",
"in_filter": 1,
@@ -1254,8 +1243,8 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2015-04-02 13:42:22.985078",
- "modified_by": "anand@erpnext.com",
+ "modified": "2015-04-27 20:31:51.966964",
+ "modified_by": "Administrator",
"module": "Accounts",
"name": "Sales Invoice",
"owner": "Administrator",
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 40712c2..9568c90 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -62,7 +62,6 @@
if not self.is_opening:
self.is_opening = 'No'
- self.set_aging_date()
self.set_against_income_account()
self.validate_c_form()
self.validate_time_logs_are_submitted()
@@ -282,13 +281,6 @@
}
})
-
- def set_aging_date(self):
- if self.is_opening != 'Yes':
- self.aging_date = self.posting_date
- elif not self.aging_date:
- throw(_("Ageing Date is mandatory for opening entry"))
-
def set_against_income_account(self):
"""Set against account for debit to account"""
against_acc = []
@@ -449,7 +441,7 @@
def make_gl_entries(self, repost_future_gle=True):
gl_entries = self.get_gl_entries()
-
+
if gl_entries:
from erpnext.accounts.general_ledger import make_gl_entries
@@ -598,12 +590,12 @@
@frappe.whitelist()
def get_bank_cash_account(mode_of_payment, company):
- account = frappe.db.get_value("Mode of Payment Account", {"parent": mode_of_payment, "company": company}, \
- "default_account")
+ account = frappe.db.get_value("Mode of Payment Account",
+ {"parent": mode_of_payment, "company": company}, "default_account")
if not account:
frappe.msgprint(_("Please set default Cash or Bank account in Mode of Payment {0}").format(mode_of_payment))
return {
- "cash_bank_account": account
+ "account": account
}
@@ -616,8 +608,8 @@
# Hence the first condition is an "OR"
return frappe.db.sql("""select tabAccount.name from `tabAccount`
where (tabAccount.report_type = "Profit and Loss"
- or tabAccount.account_type = "Income Account")
- and tabAccount.group_or_ledger="Ledger"
+ or tabAccount.account_type in ("Income Account", "Temporary"))
+ and tabAccount.is_group=0
and tabAccount.docstatus!=2
and tabAccount.company = '%(company)s'
and tabAccount.%(key)s LIKE '%(txt)s'
diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js
index 9c9b037..49b5c25 100644
--- a/erpnext/accounts/page/accounts_browser/accounts_browser.js
+++ b/erpnext/accounts/page/accounts_browser/accounts_browser.js
@@ -24,18 +24,16 @@
'<ol>'+
'<li>'+__('To add child nodes, explore tree and click on the node under which you want to add more nodes.')+'</li>'+
'<li>'+
- __('Accounting Entries can be made against leaf nodes, called')+
- ' <b>' +__('Ledgers')+'</b>. '+ __('Entries against ') +
- '<b>' +__('Groups') + '</b> '+ __('are not allowed.')+
+ __('Accounting Entries can be made against leaf nodes. Entries against Groups are not allowed.')+
'</li>'+
- '<li>'+__('Please do NOT create Account (Ledgers) for Customers and Suppliers. They are created directly from the Customer / Supplier masters.')+'</li>'+
+ '<li>'+__('Please do NOT create Accounts for Customers and Suppliers. They are created directly from the Customer / Supplier masters.')+'</li>'+
'<li>'+
'<b>'+__('To create a Bank Account')+'</b>: '+
- __('Go to the appropriate group (usually Application of Funds > Current Assets > Bank Accounts and create a new Account Ledger (by clicking on Add Child) of type "Bank"')+
+ __('Go to the appropriate group (usually Application of Funds > Current Assets > Bank Accounts and create a new Account (by clicking on Add Child) of type "Bank"')+
'</li>'+
'<li>'+
'<b>'+__('To create a Tax Account') +'</b>: '+
- __('Go to the appropriate group (usually Source of Funds > Current Liabilities > Taxes and Duties and create a new Account Ledger (by clicking on Add Child) of type "Tax" and do mention the Tax rate.')+
+ __('Go to the appropriate group (usually Source of Funds > Current Liabilities > Taxes and Duties and create a new Account (by clicking on Add Child) of type "Tax" and do mention the Tax rate.')+
'</li>'+
'</ol>'+
'<p>'+__('Please setup your chart of accounts before you start Accounting Entries')+'</p></div>').appendTo(main);
@@ -201,13 +199,12 @@
fields: [
{fieldtype:'Data', fieldname:'account_name', label:__('New Account Name'), reqd:true,
description: __("Name of new Account. Note: Please don't create accounts for Customers and Suppliers, they are created automatically from the Customer and Supplier master")},
- {fieldtype:'Select', fieldname:'group_or_ledger', label:__('Group or Ledger'),
- options:'Group\nLedger', "default": "Ledger",
- description: __('Further accounts can be made under Groups, but entries can be made against Ledger')},
+ {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
+ description: __('Further accounts can be made under Groups, but entries can be made against non-Groups')},
{fieldtype:'Select', fieldname:'account_type', label:__('Account Type'),
options: ['', 'Bank', 'Cash', 'Warehouse', 'Receivable', 'Payable',
'Equity', 'Cost of Goods Sold', 'Fixed Asset', 'Expense Account',
- 'Income Account', 'Tax', 'Chargeable'].join('\n'),
+ 'Income Account', 'Tax', 'Chargeable', 'Temporary'].join('\n'),
description: __("Optional. This setting will be used to filter in various transactions.") },
{fieldtype:'Float', fieldname:'tax_rate', label:__('Tax Rate')},
{fieldtype:'Link', fieldname:'warehouse', label:__('Warehouse'), options:"Warehouse"}
@@ -217,12 +214,13 @@
var fd = d.fields_dict;
// account type if ledger
- $(fd.group_or_ledger.input).change(function() {
- if($(this).val()=='Group') {
+ $(fd.is_group.input).change(function() {
+ if($(this).prop("checked")) {
$(fd.account_type.wrapper).toggle(false);
$(fd.tax_rate.wrapper).toggle(false);
$(fd.warehouse.wrapper).toggle(false);
} else {
+ $(fd.account_type.wrapper).toggle(true);
fd.account_type.$input.trigger("change");
}
});
@@ -263,11 +261,11 @@
// show
d.on_page_show = function() {
- $(fd.group_or_ledger.input).change();
+ $(fd.is_group.input).change();
$(fd.account_type.input).change();
}
- $(fd.group_or_ledger.input).val("Ledger").change();
+ $(fd.is_group.input).prop("checked", false).change();
d.show();
},
@@ -278,8 +276,8 @@
title:__('New Cost Center'),
fields: [
{fieldtype:'Data', fieldname:'cost_center_name', label:__('New Cost Center Name'), reqd:true},
- {fieldtype:'Select', fieldname:'group_or_ledger', label:__('Group or Ledger'),
- options:'Group\nLedger', description:__('Further accounts can be made under Groups but entries can be made against Ledger')},
+ {fieldtype:'Check', fieldname:'is_group', label:__('Is Group'),
+ description:__('Further cost centers can be made under Groups but entries can be made against non-Groups')},
{fieldtype:'Button', fieldname:'create_new', label:__('Create New') }
]
});
diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.py b/erpnext/accounts/page/accounts_browser/accounts_browser.py
index de19d3b..bb64e54 100644
--- a/erpnext/accounts/page/accounts_browser/accounts_browser.py
+++ b/erpnext/accounts/page/accounts_browser/accounts_browser.py
@@ -6,6 +6,7 @@
import frappe.defaults
from frappe.utils import flt
from erpnext.accounts.utils import get_balance_on
+from erpnext.accounts.report.financial_statements import sort_root_accounts
@frappe.whitelist()
def get_companies():
@@ -20,17 +21,22 @@
# root
if args['parent'] in ("Accounts", "Cost Centers"):
+ select_cond = ", root_type, report_type" if args["parent"]=="Accounts" else ""
+
acc = frappe.db.sql(""" select
- name as value, if(group_or_ledger='Group', 1, 0) as expandable
+ name as value, is_group as expandable %s
from `tab%s`
where ifnull(parent_%s,'') = ''
and `company` = %s and docstatus<2
- order by name""" % (ctype, ctype.lower().replace(' ','_'), '%s'),
+ order by name""" % (select_cond, ctype, ctype.lower().replace(' ','_'), '%s'),
company, as_dict=1)
+
+ if args["parent"]=="Accounts":
+ sort_root_accounts(acc)
else:
# other
acc = frappe.db.sql("""select
- name as value, if(group_or_ledger='Group', 1, 0) as expandable
+ name as value, is_group as expandable
from `tab%s`
where ifnull(parent_%s,'') = %s
and docstatus<2
diff --git a/erpnext/accounts/page/financial_analytics/financial_analytics.js b/erpnext/accounts/page/financial_analytics/financial_analytics.js
index a9ac72f..ef373aa 100644
--- a/erpnext/accounts/page/financial_analytics/financial_analytics.js
+++ b/erpnext/accounts/page/financial_analytics/financial_analytics.js
@@ -265,7 +265,7 @@
var me= this;
$.each(this.data, function(i, account) {
// update groups
- if((account.group_or_ledger == "Ledger") || (account.rgt - account.lft == 1)) {
+ if((account.is_group == 0) || (account.rgt - account.lft == 1)) {
var parent = me.parent_map[account.name];
while(parent) {
var parent_account = me.item_by_name[parent];
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 7ea0c66..00e595f 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -186,7 +186,7 @@
frappe.throw(_("Due Date cannot be before Posting Date"))
elif credit_days is not None and diff > flt(credit_days):
is_credit_controller = frappe.db.get_value("Accounts Settings", None,
- "credit_controller") in frappe.user.get_roles()
+ "credit_controller") in frappe.get_roles()
if is_credit_controller:
msgprint(_("Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s)")
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 3bde399..52c9760 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -170,14 +170,15 @@
if not hasattr(self, "gl_entries"):
conditions, values = self.prepare_conditions(party_type)
self.gl_entries = frappe.db.sql("""select * from `tabGL Entry`
- where docstatus < 2 {0} order by posting_date, party"""
+ where docstatus < 2 and party_type=%s {0} order by posting_date, party"""
.format(conditions), values, as_dict=True)
return self.gl_entries
def prepare_conditions(self, party_type):
conditions = [""]
- values = []
+ values = [party_type]
+
party_type_field = scrub(party_type)
if self.filters.company:
@@ -185,20 +186,9 @@
values.append(self.filters.company)
if self.filters.get(party_type_field):
- conditions.append("party_type=%s and party=%s")
- values += [party_type, self.filters.get(party_type_field)]
+ conditions.append("party=%s")
+ values.append(self.filters.get(party_type_field))
- if self.filters.account:
- conditions.append("account=%s")
- values.append(self.filters.account)
- else:
- account_map = self.get_account_map()
- if not account_map:
- frappe.throw(_("No Customer Accounts found."))
- else:
- conditions.append("account in ({0})".format(", ".join(["%s"] * len(account_map))))
- values += account_map.keys()
-
return " and ".join(conditions), values
def get_gl_entries_for(self, party, party_type, against_voucher_type, against_voucher):
diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js
index 35a4fe9..37d8130 100644
--- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js
+++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js
@@ -24,13 +24,13 @@
"reqd": 1,
"get_query": function() {
return {
- "query": "erpnext.controllers.queries.get_account_list",
+ "query": "erpnext.controllers.queries.get_account_list",
"filters": [
['Account', 'account_type', 'in', 'Bank, Cash'],
- ['Account', 'group_or_ledger', '=', 'Ledger'],
+ ['Account', 'is_group', '=', 0],
]
}
}
},
]
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
index 0d333da..581531b 100644
--- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
+++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js
@@ -14,7 +14,7 @@
"query": "erpnext.controllers.queries.get_account_list",
"filters": [
['Account', 'account_type', 'in', 'Bank, Cash'],
- ['Account', 'group_or_ledger', '=', 'Ledger'],
+ ['Account', 'is_group', '=', 0],
]
}
}
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index b58f078..07d5e51 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -184,9 +184,14 @@
parent_children_map.setdefault(d.parent_account or None, []).append(d)
filtered_accounts = []
+
def add_to_list(parent, level):
if level < depth:
- for child in (parent_children_map.get(parent) or []):
+ children = parent_children_map.get(parent) or []
+ if parent == None:
+ sort_root_accounts(children)
+
+ for child in children:
child.indent = level
filtered_accounts.append(child)
add_to_list(child.name, level + 1)
@@ -203,6 +208,20 @@
return filtered_accounts, accounts_by_name
+def sort_root_accounts(roots):
+ """Sort root types as Asset, Liability, Equity, Income, Expense"""
+
+ def compare_roots(a, b):
+ if a.report_type != b.report_type and a.report_type == "Balance Sheet":
+ return -1
+ if a.root_type != b.root_type and a.root_type == "Asset":
+ return -1
+ if a.root_type == "Liability" and b.root_type == "Equity":
+ return -1
+ return 1
+
+ roots.sort(compare_roots)
+
def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closing_entries=False):
"""Returns a dict like { "account": [gl entries], ... }"""
additional_conditions = []
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index e70f2ea..a7ee7c0 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -8,7 +8,7 @@
def execute(filters=None):
account_details = {}
- for acc in frappe.db.sql("""select name, group_or_ledger from tabAccount""", as_dict=1):
+ for acc in frappe.db.sql("""select name, is_group from tabAccount""", as_dict=1):
account_details.setdefault(acc.name, acc)
validate_filters(filters, account_details)
@@ -25,7 +25,7 @@
frappe.throw(_("Account {0} does not exists").format(filters.account))
if filters.get("account") and filters.get("group_by_account") \
- and account_details[filters.account].group_or_ledger == "Ledger":
+ and account_details[filters.account].is_group == 0:
frappe.throw(_("Can not filter based on Account, if grouped by Account"))
if filters.get("voucher_no") and filters.get("group_by_voucher"):
@@ -45,10 +45,10 @@
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
def get_columns():
- return [_("Posting Date") + ":Date:90", _("Account") + ":Link/Account:200",
- _("Debit") + ":Float:100", _("Credit") + ":Float:100",
- _("Voucher Type") + "::120", _("Voucher No") + ":Dynamic Link/Voucher Type:160",
- _("Against Account") + "::120", _("Party Type") + "::80", _("Party") + "::150",
+ return [_("Posting Date") + ":Date:90", _("Account") + ":Link/Account:200",
+ _("Debit") + ":Float:100", _("Credit") + ":Float:100",
+ _("Voucher Type") + "::120", _("Voucher No") + ":Dynamic Link/Voucher Type:160",
+ _("Against Account") + "::120", _("Party Type") + "::80", _("Party") + "::150",
_("Cost Center") + ":Link/Cost Center:100", _("Remarks") + "::400"]
def get_result(filters, account_details):
@@ -179,7 +179,7 @@
for d in data:
result.append([d.get("posting_date"), d.get("account"), d.get("debit"),
d.get("credit"), d.get("voucher_type"), d.get("voucher_no"),
- d.get("against"), d.get("party_type"), d.get("party"),
+ d.get("against"), d.get("party_type"), d.get("party"),
d.get("cost_center"), d.get("remarks")])
return result
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.js b/erpnext/accounts/report/gross_profit/gross_profit.js
index b744e29..9035626 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.js
+++ b/erpnext/accounts/report/gross_profit/gross_profit.js
@@ -8,6 +8,7 @@
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
+ "reqd": 1,
"default": frappe.defaults.get_user_default("company")
},
{
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index f062cdb..761d038 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -123,7 +123,8 @@
def prepare_data(accounts, filters, total_row):
show_zero_values = cint(filters.show_zero_values)
data = []
- for i, d in enumerate(accounts):
+ accounts_with_zero_value = []
+ for d in accounts:
has_value = False
row = {
"account_name": d.account_name,
@@ -141,8 +142,13 @@
if row[key]:
has_value = True
- if has_value or show_zero_values:
+ if show_zero_values:
data.append(row)
+ else:
+ if not has_value:
+ accounts_with_zero_value.append(d.name)
+ elif d.parent_account not in accounts_with_zero_value:
+ data.append(row)
data.extend([{},total_row])
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 4b5b5f6..e0f0e3b 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -89,7 +89,7 @@
% year_start_date)
# different filter for group and ledger - improved performance
- if acc.group_or_ledger=="Group":
+ if acc.is_group:
cond.append("""exists (
select * from `tabAccount` ac where ac.name = gle.account
and ac.lft >= %s and ac.rgt <= %s
@@ -348,8 +348,8 @@
def get_currency_precision(currency=None):
if not currency:
currency = frappe.db.get_value("Company",
- frappe.db.get_default("company"), "default_currency")
- currency_format = frappe.db.get_value("Currency", currency, "number_format")
+ frappe.db.get_default("company"), "default_currency", cache=True)
+ currency_format = frappe.db.get_value("Currency", currency, "number_format", cache=True)
from frappe.utils import get_number_format_info
return get_number_format_info(currency_format)[2]
diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.py b/erpnext/buying/doctype/purchase_common/purchase_common.py
index 8cedddf..21791f7 100644
--- a/erpnext/buying/doctype/purchase_common/purchase_common.py
+++ b/erpnext/buying/doctype/purchase_common/purchase_common.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt
+from frappe.utils import flt, cstr
from frappe import _
from erpnext.stock.doctype.item.item import get_last_purchase_details
@@ -39,7 +39,7 @@
(flt(last_purchase_rate), d.item_code))
def validate_for_items(self, obj):
- check_list, chk_dupl_itm=[],[]
+ items = []
for d in obj.get("items"):
# validation for valid qty
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
@@ -70,31 +70,11 @@
if not (obj.doctype=="Material Request" and getattr(obj, "material_request_type", None)=="Material Transfer"):
if item[0][1] != 'Yes' and item[0][2] != 'Yes':
frappe.throw(_("{0} must be a Purchased or Sub-Contracted Item in row {1}").format(d.item_code, d.idx))
-
- # list criteria that should not repeat if item is stock item
- e = [getattr(d, "schedule_date", None), d.item_code, d.description, d.warehouse, d.uom,
- d.meta.get_field('prevdoc_docname') and d.prevdoc_docname or d.meta.get_field('sales_order_no') and d.sales_order_no or '',
- d.meta.get_field('prevdoc_detail_docname') and d.prevdoc_detail_docname or '',
- d.meta.get_field('batch_no') and d.batch_no or '']
-
- # if is not stock item
- f = [getattr(d, "schedule_date", None), d.item_code, d.description]
-
- ch = frappe.db.sql("""select is_stock_item from `tabItem` where name = %s""", d.item_code)
-
- if ch and ch[0][0] == 'Yes':
- # check for same items
- if e in check_list:
- frappe.throw(_("Item {0} has been entered multiple times with same description or date or warehouse").format(d.item_code))
- else:
- check_list.append(e)
-
- elif ch and ch[0][0] == 'No':
- # check for same items
- if f in chk_dupl_itm:
- frappe.throw(_("Item {0} has been entered multiple times with same description or date").format(d.item_code))
- else:
- chk_dupl_itm.append(f)
+
+ items.append(cstr(d.item_code))
+ if items and len(items) != len(set(items)):
+ frappe.msgprint(_("Warning: Same item has been entered multiple times."))
+
def check_for_stopped_status(self, doctype, docname):
stopped = frappe.db.sql("""select name from `tab%s` where name = %s and
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index cd652fe..b985a06 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -508,6 +508,7 @@
"fieldname": "advance_paid",
"fieldtype": "Currency",
"label": "Advance Paid",
+ "no_copy": 1,
"permlevel": 0,
"print_hide": 1,
"read_only": 1
@@ -872,7 +873,7 @@
"icon": "icon-file-text",
"idx": 1,
"is_submittable": 1,
- "modified": "2015-03-23 14:47:26.072237",
+ "modified": "2015-04-28 15:27:28.755816",
"modified_by": "Administrator",
"module": "Buying",
"name": "Purchase Order",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 91c50b1..96a3d97 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -68,7 +68,10 @@
})
def validate_minimum_order_qty(self):
- itemwise_min_order_qty = frappe._dict(frappe.db.sql("select name, min_order_qty from tabItem"))
+ items = list(set([d.item_code for d in self.get("items")]))
+
+ itemwise_min_order_qty = frappe._dict(frappe.db.sql("""select name, min_order_qty
+ from tabItem where name in ({0})""".format(", ".join(["%s"] * len(items))), items))
itemwise_qty = frappe._dict()
for d in self.get("items"):
@@ -77,7 +80,8 @@
for item_code, qty in itemwise_qty.items():
if flt(qty) < flt(itemwise_min_order_qty.get(item_code)):
- frappe.throw(_("Item #{0}: Ordered qty can not less than item's minimum order qty (defined in item master).").format(item_code))
+ frappe.throw(_("Item {0}: Ordered qty {1} cannot be less than minimum order qty {2} (defined in Item).").format(item_code,
+ qty, itemwise_min_order_qty.get(item_code)))
def get_schedule_dates(self):
for d in self.get('items'):
@@ -217,15 +221,15 @@
def on_update(self):
pass
-
+
def before_recurring(self):
super(PurchaseOrder, self).before_recurring()
-
+
for field in ("per_received", "per_billed"):
self.set(field, None)
for d in self.get("items"):
- for field in ("received_qty", "billed_amt", "prevdoc_doctype", "prevdoc_docname",
+ for field in ("received_qty", "billed_amt", "prevdoc_doctype", "prevdoc_docname",
"prevdoc_detail_docname", "supplier_quotation", "supplier_quotation_item"):
d.set(field, None)
diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js
index a8ccf32..064fac1 100644
--- a/erpnext/buying/doctype/supplier/supplier.js
+++ b/erpnext/buying/doctype/supplier/supplier.js
@@ -65,7 +65,7 @@
filters: {
'account_type': 'Payable',
'company': d.company,
- 'group_or_ledger': 'Ledger'
+ "is_group": 0
}
}
}
diff --git a/erpnext/config/projects.py b/erpnext/config/projects.py
index d591c9e..07149e3 100644
--- a/erpnext/config/projects.py
+++ b/erpnext/config/projects.py
@@ -32,6 +32,11 @@
"name": "Activity Type",
"description": _("Types of activities for Time Sheets"),
},
+ {
+ "type": "doctype",
+ "name": "Activity Cost",
+ "description": _("Cost of various activities"),
+ },
]
},
{
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c622478..8a0c669 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -39,9 +39,8 @@
def before_recurring(self):
self.fiscal_year = None
- for fieldname in ("due_date", "aging_date"):
- if self.meta.get_field(fieldname):
- self.set(fieldname, None)
+ if self.meta.get_field("due_date"):
+ self.due_date = None
def set_missing_values(self, for_validate=False):
for fieldname in ["posting_date", "transaction_date"]:
@@ -178,7 +177,6 @@
'posting_date': self.posting_date,
'voucher_type': self.doctype,
'voucher_no': self.name,
- 'aging_date': self.get("aging_date") or self.posting_date,
'remarks': self.get("remarks"),
'fiscal_year': self.fiscal_year,
'debit': 0,
@@ -358,7 +356,7 @@
def validate_conversion_rate(currency, conversion_rate, conversion_rate_label, company):
"""common validation for currency and price list currency"""
- company_currency = frappe.db.get_value("Company", company, "default_currency")
+ company_currency = frappe.db.get_value("Company", company, "default_currency", cache=True)
if not conversion_rate:
throw(_("{0} is mandatory. Maybe Currency Exchange record is not created for {1} to {2}.").format(
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 2af8738..898dd23 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -138,7 +138,7 @@
tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount
where tabAccount.docstatus!=2
and account_type in (%s)
- and group_or_ledger = 'Ledger'
+ and is_group = 0
and company = %s
and `%s` LIKE %s
limit %s, %s""" %
@@ -147,7 +147,7 @@
start, page_len]))
if not tax_accounts:
tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount
- where tabAccount.docstatus!=2 and group_or_ledger = 'Ledger'
+ where tabAccount.docstatus!=2 and is_group = 0
and company = %s and `%s` LIKE %s limit %s, %s"""
% ("%s", searchfield, "%s", "%s", "%s"),
(filters.get("company"), "%%%s%%" % txt, start, page_len))
@@ -281,8 +281,8 @@
elif isinstance(filters, list):
filter_list.extend(filters)
- if "group_or_ledger" not in [d[1] for d in filter_list]:
- filter_list.append(["Account", "group_or_ledger", "=", "Ledger"])
+ if "is_group" not in [d[1] for d in filter_list]:
+ filter_list.append(["Account", "is_group", "=", "0"])
if searchfield and txt:
filter_list.append([doctype, searchfield, "like", "%%%s%%" % txt])
diff --git a/erpnext/controllers/trends.py b/erpnext/controllers/trends.py
index 3d5e690..16387a5 100644
--- a/erpnext/controllers/trends.py
+++ b/erpnext/controllers/trends.py
@@ -31,7 +31,10 @@
for f in ["Fiscal Year", "Based On", "Period", "Company"]:
if not filters.get(f.lower().replace(" ", "_")):
frappe.throw(_("{0} is mandatory").format(f))
-
+
+ if not frappe.db.exists("Fiscal Year", filters.get("fiscal_year")):
+ frappe.throw(_("Fiscal Year: {0} does not exists").format(filters.get("fiscal_year")))
+
if filters.get("based_on") == filters.get("group_by"):
frappe.throw(_("'Based On' and 'Group By' can not be same"))
diff --git a/erpnext/controllers/website_list_for_contact.py b/erpnext/controllers/website_list_for_contact.py
index 3c9ae46..9282be2 100644
--- a/erpnext/controllers/website_list_for_contact.py
+++ b/erpnext/controllers/website_list_for_contact.py
@@ -22,7 +22,7 @@
from frappe.templates.pages.list import get_list
user = frappe.session.user
- if user != "Guest" and is_website_user(user):
+ if user != "Guest" and is_website_user():
# find party for this contact
customers, suppliers = get_customers_suppliers(doctype, user)
if customers:
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 0fb8d48..b523416 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -11,14 +11,12 @@
from erpnext.controllers.selling_controller import SellingController
from erpnext.utilities.address_and_contact import load_address_and_contact
+sender_field = "email_id"
+
class Lead(SellingController):
def get_feed(self):
return '{0}: {1}'.format(_(self.status), self.lead_name)
- def set_sender(self, sender):
- """Will be called by **Communication** when a Lead is created from an incoming email."""
- self.email_id = sender
-
def onload(self):
customer = frappe.db.get_value("Customer", {"lead_name": self.name})
self.get("__onload").is_customer = customer
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index abf5fef..08d413f 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -2,32 +2,17 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import frappe
+import frappe, json
from frappe.utils import cstr, cint
from frappe import msgprint, _
from frappe.model.mapper import get_mapped_doc
from erpnext.utilities.transaction_base import TransactionBase
+subject_field = "title"
+sender_field = "contact_email"
+
class Opportunity(TransactionBase):
- def set_sender(self, email_id):
- """Set lead against new opportunity"""
- lead_name = frappe.db.get_value("Lead", {"email_id": email_id})
- if not lead_name:
- lead = frappe.get_doc({
- "doctype": "Lead",
- "email_id": email_id,
- "lead_name": email_id
- })
- lead.insert(ignore_permissions=True)
- lead_name = lead.name
-
- self.enquiry_from = "Lead"
- self.lead = lead_name
-
- def set_subject(self, subject):
- self.title = subject
-
def after_insert(self):
if self.lead:
frappe.get_doc("Lead", self.lead).set_status(update=True)
@@ -40,6 +25,8 @@
(not cint(self.get("__islocal"))) else None,
})
+ self.make_new_lead_if_required()
+
if not self.enquiry_from:
frappe.throw(_("Opportunity From field is mandatory"))
@@ -55,6 +42,22 @@
from erpnext.accounts.utils import validate_fiscal_year
validate_fiscal_year(self.transaction_date, self.fiscal_year, _("Opportunity Date"), self)
+ def make_new_lead_if_required(self):
+ """Set lead against new opportunity"""
+ if not self.lead or self.customer:
+ lead_name = frappe.db.get_value("Lead", {"email_id": self.contact_email})
+ if not lead_name:
+ lead = frappe.get_doc({
+ "doctype": "Lead",
+ "email_id": self.contact_email,
+ "lead_name": self.contact_email
+ })
+ lead.insert(ignore_permissions=True)
+ lead_name = lead.name
+
+ self.enquiry_from = "Lead"
+ self.lead = lead_name
+
def declare_enquiry_lost(self,arg):
if not self.has_quotation():
frappe.db.set(self, 'status', 'Lost')
@@ -200,3 +203,11 @@
}, target_doc, set_missing_values)
return doclist
+
+@frappe.whitelist()
+def set_multiple_status(names, status):
+ names = json.loads(names)
+ for name in names:
+ opp = frappe.get_doc("Opportunity", name)
+ opp.status = status
+ opp.save()
diff --git a/erpnext/crm/doctype/opportunity/opportunity_list.js b/erpnext/crm/doctype/opportunity/opportunity_list.js
index 6c6c897..55a5463 100644
--- a/erpnext/crm/doctype/opportunity/opportunity_list.js
+++ b/erpnext/crm/doctype/opportunity/opportunity_list.js
@@ -6,5 +6,16 @@
indicator[1] = "green";
}
return indicator;
+ },
+ onload: function(listview) {
+ var method = "erpnext.crm.doctype.opportunity.opportunity.set_multiple_status";
+
+ listview.page.add_menu_item(__("Set as Open"), function() {
+ listview.call_for_selected_items(method, {"status": "Open"});
+ });
+
+ listview.page.add_menu_item(__("Set as Closed"), function() {
+ listview.call_for_selected_items(method, {"status": "Closed"});
+ });
}
};
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index 5e857f8..72a2686 100644
--- 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
from frappe.model.naming import make_autoname
-from frappe import throw, _, msgprint
+from frappe import throw, _
import frappe.permissions
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
@@ -139,8 +139,8 @@
def validate_employee_leave_approver(self):
for l in self.get("leave_approvers")[:]:
if "Leave Approver" not in frappe.get_roles(l.leave_approver):
- self.get("leave_approvers").remove(l)
- msgprint(_("{0} is not a valid Leave Approver. Removing row #{1}.").format(l.leave_approver, l.idx))
+ frappe.get_doc("User", l.leave_approver).add_roles("Leave Approver")
+
def validate_reports_to(self):
if self.reports_to == self.name:
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 8076bf7..d279074 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -133,12 +133,14 @@
cur_frm.cscript.calculate_total_amount = function(doc,cdt,cdn){
cur_frm.cscript.calculate_total(doc,cdt,cdn);
}
+
cur_frm.cscript.claim_amount = function(doc,cdt,cdn){
cur_frm.cscript.calculate_total(doc,cdt,cdn);
var child = locals[cdt][cdn];
refresh_field("sanctioned_amount", child.name, child.parentfield);
}
+
cur_frm.cscript.sanctioned_amount = function(doc,cdt,cdn){
cur_frm.cscript.calculate_total(doc,cdt,cdn);
}
@@ -148,3 +150,30 @@
cur_frm.email_doc(frappe.boot.notification_settings.expense_claim_message);
}
}
+
+erpnext.expense_claim = {
+ set_title :function(frm) {
+ if (!frm.doc.task) {
+ frm.set_value("title", frm.doc.employee_name);
+ }
+ else {
+ frm.set_value("title", frm.doc.employee_name + " for "+ frm.doc.task);
+ }
+ }
+}
+
+frappe.ui.form.on("Expense Claim", "employee_name", function(frm) {
+ erpnext.expense_claim.set_title(frm);
+});
+
+frappe.ui.form.on("Expense Claim", "task", function(frm) {
+ erpnext.expense_claim.set_title(frm);
+});
+
+cur_frm.fields_dict['task'].get_query = function(doc) {
+ return {
+ filters:{
+ 'project': doc.project
+ }
+ }
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json
index ef3d617..e9e29a8 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.json
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.json
@@ -93,7 +93,8 @@
"oldfieldname": "expense_voucher_details",
"oldfieldtype": "Table",
"options": "Expense Claim Detail",
- "permlevel": 0
+ "permlevel": 0,
+ "reqd": 1
},
{
"fieldname": "sb1",
@@ -102,6 +103,7 @@
"permlevel": 0
},
{
+ "default": "Today",
"fieldname": "posting_date",
"fieldtype": "Date",
"in_filter": 1,
@@ -192,6 +194,21 @@
"precision": ""
},
{
+ "fieldname": "task",
+ "fieldtype": "Link",
+ "label": "Task",
+ "options": "Task",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "label": "Title",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "email_id",
"fieldtype": "Data",
"hidden": 1,
@@ -220,7 +237,7 @@
"icon": "icon-money",
"idx": 1,
"is_submittable": 1,
- "modified": "2015-03-26 04:41:50.473196",
+ "modified": "2015-05-02 07:42:25.202983",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim",
@@ -241,25 +258,6 @@
},
{
"amend": 1,
- "apply_user_permissions": 0,
- "cancel": 1,
- "create": 1,
- "delete": 1,
- "email": 0,
- "export": 0,
- "import": 0,
- "permlevel": 0,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "HR Manager",
- "set_user_permissions": 0,
- "share": 1,
- "submit": 1,
- "write": 1
- },
- {
- "amend": 1,
"apply_user_permissions": 1,
"cancel": 1,
"create": 1,
@@ -272,6 +270,7 @@
"role": "Expense Approver",
"share": 1,
"submit": 1,
+ "user_permission_doctypes": "[\"Company\",\"Expense Claim\",\"Fiscal Year\",\"Project\",\"Task\",\"User\"]",
"write": 1
},
{
@@ -288,11 +287,12 @@
"role": "HR User",
"share": 1,
"submit": 1,
+ "user_permission_doctypes": "[\"Company\",\"Expense Claim\",\"Fiscal Year\",\"Project\",\"Task\",\"User\"]",
"write": 1
}
],
"search_fields": "approval_status,employee,employee_name",
"sort_field": "modified",
"sort_order": "DESC",
- "title_field": "employee_name"
+ "title_field": "title"
}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index 76606e5..6687399 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import get_fullname
+from frappe.utils import get_fullname, flt
from frappe.model.document import Document
from erpnext.hr.utils import set_employee_name
from erpnext.accounts.utils import validate_fiscal_year
@@ -18,19 +18,44 @@
def validate(self):
validate_fiscal_year(self.posting_date, self.fiscal_year, _("Posting Date"), self)
- self.validate_exp_details()
+ self.validate_sanctioned_amount()
self.validate_expense_approver()
+ self.validate_task()
+ self.calculate_total_amount()
set_employee_name(self)
def on_submit(self):
if self.approval_status=="Draft":
frappe.throw(_("""Approval Status must be 'Approved' or 'Rejected'"""))
-
- def validate_exp_details(self):
- if not self.get('expenses'):
- frappe.throw(_("Please add expense voucher details"))
+ if self.task:
+ self.update_task()
+
+ def on_cancel(self):
+ if self.task:
+ self.update_task()
+
+ def calculate_total_amount(self):
+ self.total_claimed_amount = 0
+ self.total_sanctioned_amount = 0
+ for d in self.get('expenses'):
+ self.total_claimed_amount += flt(d.claim_amount)
+ self.total_sanctioned_amount += flt(d.sanctioned_amount)
def validate_expense_approver(self):
if self.exp_approver and "Expense Approver" not in frappe.get_roles(self.exp_approver):
frappe.throw(_("{0} ({1}) must have role 'Expense Approver'")\
.format(get_fullname(self.exp_approver), self.exp_approver), InvalidExpenseApproverError)
+
+ def update_task(self):
+ task = frappe.get_doc("Task", self.task)
+ task.update_total_expense_claim()
+ task.save()
+
+ def validate_task(self):
+ if self.project and not self.task:
+ frappe.throw(_("Task is mandatory if Expense Claim is against a Project"))
+
+ def validate_sanctioned_amount(self):
+ for d in self.get('expenses'):
+ if flt(d.sanctioned_amount) > flt(d.claim_amount):
+ frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index f1c657a..a9091fb 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -8,4 +8,47 @@
test_records = frappe.get_test_records('Expense Claim')
class TestExpenseClaim(unittest.TestCase):
- pass
+ def test_total_expense_claim_for_project(self):
+ frappe.db.sql("""delete from `tabTask` where project = "_Test Project 1" """)
+ frappe.db.sql("""delete from `tabProject` where name = "_Test Project 1" """)
+
+ frappe.get_doc({
+ "project_name": "_Test Project 1",
+ "doctype": "Project",
+ "tasks" :
+ [{ "title": "_Test Project Task 1", "status": "Open" }]
+ }).save()
+
+ task_name = frappe.db.get_value("Task",{"project": "_Test Project 1"})
+ expense_claim = frappe.get_doc({
+ "doctype": "Expense Claim",
+ "employee": "_T-Employee-0001",
+ "approval_status": "Approved",
+ "project": "_Test Project 1",
+ "task": task_name,
+ "expenses":
+ [{ "expense_type": "Food", "claim_amount": 300, "sanctioned_amount": 200 }]
+ })
+ expense_claim.submit()
+
+ self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
+
+ expense_claim2 = frappe.get_doc({
+ "doctype": "Expense Claim",
+ "employee": "_T-Employee-0001",
+ "approval_status": "Approved",
+ "project": "_Test Project 1",
+ "task": task_name,
+ "expenses":
+ [{ "expense_type": "Food", "claim_amount": 600, "sanctioned_amount": 500 }]
+ })
+ expense_claim2.submit()
+
+ self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 700)
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 700)
+
+ expense_claim2.cancel()
+
+ self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
diff --git a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
index d975189..c6123ee 100644
--- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
+++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
@@ -16,6 +16,12 @@
"width": "150px"
},
{
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "expense_type",
"fieldtype": "Link",
"in_list_view": 1,
@@ -29,6 +35,12 @@
"width": "150px"
},
{
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "description",
"fieldtype": "Small Text",
"in_list_view": 1,
@@ -40,6 +52,12 @@
"width": "300px"
},
{
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "claim_amount",
"fieldtype": "Currency",
"in_list_view": 1,
@@ -53,6 +71,12 @@
"width": "150px"
},
{
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"allow_on_submit": 0,
"fieldname": "sanctioned_amount",
"fieldtype": "Currency",
@@ -69,7 +93,7 @@
],
"idx": 1,
"istable": 1,
- "modified": "2014-05-09 02:16:38.529082",
+ "modified": "2015-04-08 06:18:47.539134",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim Detail",
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py
index 90b0ec9..b0482cd 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.py
@@ -9,12 +9,14 @@
from frappe import _
from frappe.utils import comma_and
+sender_field = "email_id"
+
class JobApplicant(Document):
def onload(self):
offer_letter = frappe.get_all("Offer Letter", filters={"job_applicant": self.name})
if offer_letter:
- self.__onload.offer_letter = offer_letter[0].name
-
+ self.get("__onload").offer_letter = offer_letter[0].name
+
def autoname(self):
keys = filter(None, (self.applicant_name, self.email_id))
if not keys:
@@ -31,6 +33,3 @@
if names:
frappe.throw(_("Email id must be unique, already exists for {0}").format(comma_and(names)), frappe.DuplicateEntryError)
-
- def set_sender(self, sender):
- self.email_id = sender
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index 2b4bbbd..7e72064 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -3,6 +3,10 @@
cur_frm.add_fetch('employee','employee_name','employee_name');
+frappe.ui.form.on("Leave Application", "leave_approver", function(frm) {
+ frm.set_value("leave_approver_name", frappe.user.full_name(frm.doc.leave_approver));
+});
+
cur_frm.cscript.onload = function(doc, dt, dn) {
if(!doc.posting_date)
set_multiple(dt,dn,{posting_date:get_today()});
@@ -13,7 +17,10 @@
cur_frm.set_query("leave_approver", function() {
return {
- filters: [["UserRole", "role", "=", "Leave Approver"]]
+ query: "erpnext.hr.doctype.leave_application.leave_application.get_approvers",
+ filters: {
+ employee: cur_frm.doc.employee
+ }
};
});
@@ -106,18 +113,3 @@
}
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 cb15d42..cd32b9c 100644
--- a/erpnext/hr/doctype/leave_application/leave_application.json
+++ b/erpnext/hr/doctype/leave_application/leave_application.json
@@ -17,17 +17,8 @@
"permlevel": 1
},
{
- "description": "Leave can be approved by users with Role, \"Leave Approver\"",
- "fieldname": "leave_approver",
- "fieldtype": "Link",
- "label": "Leave Approver",
- "options": "User",
- "permlevel": 0
- },
- {
- "fieldname": "leave_approver_name",
- "fieldtype": "Read Only",
- "label": "Leave Approver Name",
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break",
"permlevel": 0,
"precision": ""
},
@@ -44,6 +35,20 @@
"search_index": 1
},
{
+ "fieldname": "leave_balance",
+ "fieldtype": "Float",
+ "label": "Leave Balance Before Application",
+ "no_copy": 1,
+ "permlevel": 0,
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "from_date",
"fieldtype": "Date",
"in_list_view": 1,
@@ -68,6 +73,15 @@
"permlevel": 0
},
{
+ "fieldname": "total_leave_days",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Total Leave Days",
+ "no_copy": 1,
+ "permlevel": 0,
+ "read_only": 1
+ },
+ {
"fieldname": "column_break1",
"fieldtype": "Column Break",
"permlevel": 0,
@@ -81,6 +95,12 @@
"permlevel": 0
},
{
+ "fieldname": "section_break_7",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "employee",
"fieldtype": "Link",
"in_filter": 1,
@@ -101,38 +121,33 @@
"search_index": 0
},
{
- "fieldname": "leave_balance",
- "fieldtype": "Float",
- "label": "Leave Balance Before Application",
- "no_copy": 1,
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break",
"permlevel": 0,
- "read_only": 1
+ "precision": ""
},
{
- "fieldname": "total_leave_days",
- "fieldtype": "Float",
- "in_list_view": 1,
- "label": "Total Leave Days",
- "no_copy": 1,
+ "description": "",
+ "fieldname": "leave_approver",
+ "fieldtype": "Link",
+ "label": "Leave Approver",
+ "options": "User",
+ "permlevel": 0
+ },
+ {
+ "fieldname": "leave_approver_name",
+ "fieldtype": "Read Only",
+ "label": "Leave Approver Name",
"permlevel": 0,
- "read_only": 1
+ "precision": ""
},
{
"fieldname": "sb10",
"fieldtype": "Section Break",
- "label": "More Info",
+ "label": "",
"permlevel": 0
},
{
- "allow_on_submit": 1,
- "default": "1",
- "fieldname": "follow_via_email",
- "fieldtype": "Check",
- "label": "Follow via Email",
- "permlevel": 0,
- "print_hide": 1
- },
- {
"default": "Today",
"fieldname": "posting_date",
"fieldtype": "Date",
@@ -153,6 +168,15 @@
"search_index": 0
},
{
+ "allow_on_submit": 1,
+ "default": "1",
+ "fieldname": "follow_via_email",
+ "fieldtype": "Check",
+ "label": "Follow via Email",
+ "permlevel": 0,
+ "print_hide": 1
+ },
+ {
"fieldname": "column_break_17",
"fieldtype": "Column Break",
"permlevel": 0
@@ -192,7 +216,7 @@
"idx": 1,
"is_submittable": 1,
"max_attachments": 3,
- "modified": "2015-02-05 05:11:40.611487",
+ "modified": "2015-04-30 02:19:39.330689",
"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 d3bf358..c75c2bd 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -204,6 +204,17 @@
post(**{"txt": args.message, "contact": args.message_to, "subject": args.subject,
"notify": cint(self.follow_via_email)})
+@frappe.whitelist()
+def get_approvers(doctype, txt, searchfield, start, page_len, filters):
+ if not filters.get("employee"):
+ frappe.throw(_("Please select Employee Record first."))
+
+ return frappe.db.sql("""select user.name, user.first_name, user.last_name from
+ tabUser user, `tabEmployee Leave Approver` approver where
+ approver.parent = %s
+ and user.name like %s
+ and approver.leave_approver=user.name""", (filters.get("employee"), "%" + txt + "%"))
+
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
diff --git a/erpnext/hr/doctype/leave_application/leave_application_list.js b/erpnext/hr/doctype/leave_application/leave_application_list.js
index e0558a7..f82dfb2 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_list.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_list.js
@@ -1,6 +1,6 @@
frappe.listview_settings['Leave Application'] = {
add_fields: ["status", "leave_type", "employee", "employee_name", "total_leave_days", "from_date"],
- filters:[["status","!=", "Rejected"], ["to_date", ">=", frappe.datetime.get_today()]],
+ filters:[["status","!=", "Rejected"]],
get_indicator: function(doc) {
return [__(doc.status), frappe.utils.guess_colour(doc.status),
"status,=," + doc.status];
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 14932d2..4c87dc7 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -388,6 +388,7 @@
and bom_item.docstatus < 2
and bom_item.parent = %(bom)s
and item.name = bom_item.item_code
+ and ifnull(item.is_stock_item, 'No') = 'Yes'
{conditions}
group by item_code, stock_uom"""
diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
index 2dc6ce8..0c25e8f 100644
--- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
+++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json
@@ -42,7 +42,7 @@
},
{
"fieldname": "hour_rate",
- "fieldtype": "Currency",
+ "fieldtype": "Float",
"in_list_view": 0,
"label": "Hour Rate",
"oldfieldname": "hour_rate",
@@ -77,7 +77,7 @@
],
"idx": 1,
"istable": 1,
- "modified": "2015-04-21 07:11:38.730014",
+ "modified": "2015-04-22 03:24:47.809532",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",
diff --git a/erpnext/manufacturing/doctype/production_order_operation/production_order_operation.json b/erpnext/manufacturing/doctype/production_order_operation/production_order_operation.json
index 2034ae5..8313485 100644
--- a/erpnext/manufacturing/doctype/production_order_operation/production_order_operation.json
+++ b/erpnext/manufacturing/doctype/production_order_operation/production_order_operation.json
@@ -194,7 +194,7 @@
{
"allow_on_submit": 0,
"fieldname": "hour_rate",
- "fieldtype": "Currency",
+ "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
@@ -293,7 +293,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2015-04-21 07:10:43.341203",
+ "modified": "2015-04-22 03:25:18.542350",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Order Operation",
diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
index 968c115..1298790 100644
--- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
+++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py
@@ -248,8 +248,10 @@
ifnull(sum(ifnull(fb.qty, 0)/ifnull(bom.quantity, 1)), 0) as qty,
fb.description, fb.stock_uom, it.min_order_qty
from `tabBOM Explosion Item` fb, `tabBOM` bom, `tabItem` it
- where bom.name = fb.parent and it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
+ where bom.name = fb.parent and it.name = fb.item_code
+ and ifnull(it.is_pro_applicable, 'No') = 'No'
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
+ and ifnull(it.is_stock_item, 'No') = 'Yes'
and fb.docstatus<2 and bom.name=%s
group by item_code, stock_uom""", bom, as_dict=1):
bom_wise_item_details.setdefault(d.item_code, d)
@@ -262,6 +264,7 @@
from `tabBOM Item` bom_item, `tabBOM` bom, tabItem item
where bom.name = bom_item.parent and bom.name = %s and bom_item.docstatus < 2
and bom_item.item_code = item.name
+ and ifnull(item.is_stock_item, 'No') = 'Yes'
group by item_code""", bom, as_dict=1):
bom_wise_item_details.setdefault(d.item_code, d)
@@ -320,8 +323,9 @@
# shortage
requested_qty = total_qty - flt(item_projected_qty.get(item))
# consider minimum order qty
- requested_qty = requested_qty > flt(so_item_qty[0][3]) and \
- requested_qty or flt(so_item_qty[0][3])
+
+ if requested_qty < flt(so_item_qty[0][3]):
+ requested_qty = flt(so_item_qty[0][3])
# distribute requested qty SO wise
for item_details in so_item_qty:
diff --git a/erpnext/manufacturing/report/completed_production_orders/completed_production_orders.json b/erpnext/manufacturing/report/completed_production_orders/completed_production_orders.json
index 0ad6cc4..3c16810 100644
--- a/erpnext/manufacturing/report/completed_production_orders/completed_production_orders.json
+++ b/erpnext/manufacturing/report/completed_production_orders/completed_production_orders.json
@@ -5,12 +5,12 @@
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
- "modified": "2015-03-30 05:42:42.742398",
+ "modified": "2015-04-24 21:04:02.944586",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Completed Production Orders",
"owner": "Administrator",
- "query": "SELECT\n `tabProduction Order`.name as \"Production Order:Link/Production Order:200\",\n `tabProduction Order`.creation as \"Date:Date:120\",\n `tabProduction Order`.production_item as \"Item:Link/Item:150\",\n `tabProduction Order`.qty as \"To Produce:Int:100\",\n `tabProduction Order`.produced_qty as \"Produced:Int:100\",\n `tabProduction Order`.company as \"Company:Link/Company:\",\nFROM\n `tabProduction Order`\nWHERE\n `tabProduction Order`.docstatus=1\n AND ifnull(`tabProduction Order`.produced_qty,0) = `tabProduction Order`.qty",
+ "query": "SELECT\n `tabProduction Order`.name as \"Production Order:Link/Production Order:200\",\n `tabProduction Order`.creation as \"Date:Date:120\",\n `tabProduction Order`.production_item as \"Item:Link/Item:150\",\n `tabProduction Order`.qty as \"To Produce:Int:100\",\n `tabProduction Order`.produced_qty as \"Produced:Int:100\",\n `tabProduction Order`.company as \"Company:Link/Company:\"\nFROM\n `tabProduction Order`\nWHERE\n `tabProduction Order`.docstatus=1\n AND ifnull(`tabProduction Order`.produced_qty,0) = `tabProduction Order`.qty",
"ref_doctype": "Production Order",
"report_name": "Completed Production Orders",
"report_type": "Query Report"
diff --git a/erpnext/manufacturing/report/open_production_orders/open_production_orders.json b/erpnext/manufacturing/report/open_production_orders/open_production_orders.json
index bb32326..860f81d 100644
--- a/erpnext/manufacturing/report/open_production_orders/open_production_orders.json
+++ b/erpnext/manufacturing/report/open_production_orders/open_production_orders.json
@@ -5,12 +5,12 @@
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
- "modified": "2015-03-30 05:43:59.976254",
+ "modified": "2015-04-23 03:26:35.711681",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Open Production Orders",
"owner": "Administrator",
- "query": "SELECT\n `tabProduction Order`.name as \"Production Order:Link/Production Order:200\",\n `tabProduction Order`.creation as \"Date:Date:120\",\n `tabProduction Order`.production_item as \"Item:Link/Item:150\",\n `tabProduction Order`.qty as \"To Produce:Int:100\",\n `tabProduction Order`.produced_qty as \"Produced:Int:100\",\n `tabProduction Order`.company as \"Company:Link/Company:\",\nFROM\n `tabProduction Order`\nWHERE\n `tabProduction Order`.docstatus=1\n AND ifnull(`tabProduction Order`.produced_qty,0) < `tabProduction Order`.qty\n AND NOT EXISTS (SELECT name from `tabStock Entry` where production_order =`tabProduction Order`.name) ",
+ "query": "SELECT\n `tabProduction Order`.name as \"Production Order:Link/Production Order:200\",\n `tabProduction Order`.creation as \"Date:Date:120\",\n `tabProduction Order`.production_item as \"Item:Link/Item:150\",\n `tabProduction Order`.qty as \"To Produce:Int:100\",\n `tabProduction Order`.produced_qty as \"Produced:Int:100\",\n `tabProduction Order`.company as \"Company:Link/Company:\"\nFROM\n `tabProduction Order`\nWHERE\n `tabProduction Order`.docstatus=1\n AND ifnull(`tabProduction Order`.produced_qty,0) < `tabProduction Order`.qty\n AND NOT EXISTS (SELECT name from `tabStock Entry` where production_order =`tabProduction Order`.name) ",
"ref_doctype": "Production Order",
"report_name": "Open Production Orders",
"report_type": "Query Report"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 0e0fda9..e147ee3 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -101,6 +101,7 @@
execute:frappe.reload_doc('crm', 'doctype', 'opportunity')
erpnext.patches.v5_0.rename_table_fieldnames
execute:frappe.db.sql("update `tabJournal Entry` set voucher_type='Journal Entry' where ifnull(voucher_type, '')=''")
+erpnext.patches.v5_0.is_group
erpnext.patches.v4_2.party_model
erpnext.patches.v5_0.party_model_patch_fix
erpnext.patches.v4_1.fix_jv_remarks
@@ -143,3 +144,7 @@
erpnext.patches.v5_0.execute_on_doctype_update
erpnext.patches.v4_2.fix_recurring_orders
erpnext.patches.v4_2.delete_gl_entries_for_cancelled_invoices
+erpnext.patches.v5_0.project_costing
+erpnext.patches.v5_0.update_temporary_account
+erpnext.patches.v5_0.update_advance_paid
+erpnext.patches.v5_0.link_warehouse_with_account
\ No newline at end of file
diff --git a/erpnext/patches/v4_2/party_model.py b/erpnext/patches/v4_2/party_model.py
index bb4ff0b..d105349 100644
--- a/erpnext/patches/v4_2/party_model.py
+++ b/erpnext/patches/v4_2/party_model.py
@@ -15,24 +15,21 @@
delete_individual_party_account()
remove_customer_supplier_account_report()
-
-def link_warehouse_account():
- frappe.db.sql("""update tabAccount set warehouse=master_name
- where ifnull(account_type, '') = 'Warehouse' and ifnull(master_name, '') != ''""")
-
def create_receivable_payable_account():
receivable_payable_accounts = frappe._dict()
def _create_account(args):
- account = frappe.new_doc("Account")
- account.group_or_ledger = "Ledger"
- account.update(args)
- account.insert()
+ if not frappe.db.get_value("Account",
+ {"account_name": args["account_name"], "company": args["company"]}):
+ account = frappe.new_doc("Account")
+ account.is_group = 0
+ account.update(args)
+ account.insert()
- frappe.db.set_value("Company", args["company"], ("default_receivable_account"
- if args["account_type"]=="Receivable" else "default_payable_account"), account.name)
+ frappe.db.set_value("Company", args["company"], ("default_receivable_account"
+ if args["account_type"]=="Receivable" else "default_payable_account"), account.name)
- receivable_payable_accounts.setdefault(args["company"], {}).setdefault(args["account_type"], account.name)
+ receivable_payable_accounts.setdefault(args["company"], {}).setdefault(args["account_type"], account.name)
for company in frappe.db.sql_list("select name from tabCompany"):
_create_account({
@@ -52,8 +49,11 @@
return receivable_payable_accounts
def get_parent_account(company, master_type):
- parent_account = frappe.db.get_value("Company", company,
- "receivables_group" if master_type=="Customer" else "payables_group")
+ parent_account = None
+
+ if "receivables_group" in frappe.db.get_table_columns("Company"):
+ parent_account = frappe.db.get_value("Company", company,
+ "receivables_group" if master_type=="Customer" else "payables_group")
if not parent_account:
parent_account = frappe.db.get_value("Account", {"company": company,
"account_name": "Accounts Receivable" if master_type=="Customer" else "Accounts Payable"})
@@ -78,7 +78,8 @@
return
for dt in ["Journal Entry Account", "GL Entry"]:
- records = frappe.db.sql("""select name, account from `tab%s` where account in (%s)""" %
+ records = frappe.db.sql("""select name, account from `tab%s`
+ where account in (%s) and ifnull(party, '') = ''""" %
(dt, ", ".join(['%s']*len(account_map))), tuple(account_map.keys()), as_dict=1)
for i, d in enumerate(records):
account_details = account_map.get(d.account, {})
@@ -87,7 +88,7 @@
frappe.db.sql("update `tab{0}` set account=%s, party_type=%s, party=%s where name=%s".format(dt),
(new_account, account_details.get("master_type"), account_details.get("master_name"), d.name))
-
+
if i%500 == 0:
frappe.db.commit()
diff --git a/erpnext/patches/v5_0/is_group.py b/erpnext/patches/v5_0/is_group.py
new file mode 100644
index 0000000..4e3f760
--- /dev/null
+++ b/erpnext/patches/v5_0/is_group.py
@@ -0,0 +1,9 @@
+from __future__ import unicode_literals
+
+import frappe
+
+def execute():
+ frappe.reload_doctype("Account")
+ frappe.reload_doctype("Cost Center")
+ frappe.db.sql("update tabAccount set is_group = if(group_or_ledger='Group', 1, 0)")
+ frappe.db.sql("update `tabCost Center` set is_group = if(group_or_ledger='Group', 1, 0)")
diff --git a/erpnext/patches/v5_0/link_warehouse_with_account.py b/erpnext/patches/v5_0/link_warehouse_with_account.py
new file mode 100644
index 0000000..338fd7a
--- /dev/null
+++ b/erpnext/patches/v5_0/link_warehouse_with_account.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ if "master_name" in frappe.db.get_table_columns("Account"):
+ frappe.db.sql("""update tabAccount set warehouse=master_name
+ where ifnull(account_type, '') = 'Warehouse' and ifnull(master_name, '') != ''""")
\ No newline at end of file
diff --git a/erpnext/patches/v5_0/project_costing.py b/erpnext/patches/v5_0/project_costing.py
new file mode 100644
index 0000000..33bb9c1
--- /dev/null
+++ b/erpnext/patches/v5_0/project_costing.py
@@ -0,0 +1,7 @@
+import frappe
+
+def execute():
+ frappe.reload_doctype("Project")
+ frappe.db.sql("update `tabProject` set expected_start_date = project_start_date, \
+ expected_end_date = completion_date, actual_end_date = act_completion_date, \
+ estimated_costing = project_value, gross_margin = gross_margin_value")
\ No newline at end of file
diff --git a/erpnext/patches/v5_0/taxes_and_totals_in_party_currency.py b/erpnext/patches/v5_0/taxes_and_totals_in_party_currency.py
index 97efe6f..c595f4e 100644
--- a/erpnext/patches/v5_0/taxes_and_totals_in_party_currency.py
+++ b/erpnext/patches/v5_0/taxes_and_totals_in_party_currency.py
@@ -3,6 +3,8 @@
# License: GNU General Public License v3. See license.txt
import frappe
+from frappe.model.meta import get_field_precision
+from frappe.custom.doctype.property_setter.property_setter import make_property_setter
def execute():
selling_doctypes = ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]
@@ -18,19 +20,32 @@
frappe.reload_doctype(dt)
frappe.reload_doctype(dt + " Item")
frappe.reload_doctype(tax_table)
-
+
+ net_total_precision = get_field_precision(frappe.get_meta(dt).get_field("net_total"))
+ for field in ("total", "base_total", "base_net_total"):
+ make_property_setter(dt, field, "precision", net_total_precision, "Select")
+
+ rate_field_precision = get_field_precision(frappe.get_meta(dt + " Item").get_field("rate"))
+ for field in ("net_rate", "base_net_rate", "net_amount", "base_net_amount", "base_rate", "base_amount"):
+ make_property_setter(dt + " Item", field, "precision", rate_field_precision, "Select")
+
+ tax_amount_precision = get_field_precision(frappe.get_meta(tax_table).get_field("tax_amount"))
+ for field in ("base_tax_amount", "total", "base_total", "tax_amount_after_discount_amount",
+ "base_tax_amount_after_discount_amount"):
+ make_property_setter(tax_table, field, "precision", tax_amount_precision, "Select")
+
# update net_total, discount_on
frappe.db.sql("""
UPDATE
`tab{0}`
SET
- total = net_total,
- base_total = net_total*conversion_rate,
- net_total = base_net_total / conversion_rate,
+ total = round(net_total, {1}),
+ base_total = round(net_total*conversion_rate, {1}),
+ net_total = round(base_net_total / conversion_rate, {1}),
apply_discount_on = "Grand Total"
WHERE
docstatus < 2
- """.format(dt))
+ """.format(dt, net_total_precision))
# update net_amount
@@ -40,14 +55,14 @@
SET
item.base_net_amount = item.base_amount,
item.base_net_rate = item.base_rate,
- item.net_amount = item.base_net_amount / par.conversion_rate,
- item.net_rate = item.base_net_rate / par.conversion_rate,
- item.base_amount = item.amount * par.conversion_rate,
- item.base_rate = item.rate * par.conversion_rate
+ item.net_amount = round(item.base_net_amount / par.conversion_rate, {2}),
+ item.net_rate = round(item.base_net_rate / par.conversion_rate, {2}),
+ item.base_amount = round(item.amount * par.conversion_rate, {2}),
+ item.base_rate = round(item.rate * par.conversion_rate, {2})
WHERE
par.name = item.parent
and par.docstatus < 2
- """.format(dt, dt + " Item"))
+ """.format(dt, dt + " Item", rate_field_precision))
# update tax in party currency
frappe.db.sql("""
@@ -55,12 +70,12 @@
`tab{0}` par, `tab{1}` tax
SET
tax.base_tax_amount = tax.tax_amount,
- tax.tax_amount = tax.base_tax_amount / par.conversion_rate,
- tax.base_total = tax.total,
- tax.total = tax.base_total / conversion_rate,
- tax.base_tax_amount_after_discount_amount = tax.tax_amount_after_discount_amount,
- tax.tax_amount_after_discount_amount = tax.base_tax_amount_after_discount_amount / conversion_rate
+ tax.tax_amount = round(tax.base_tax_amount / par.conversion_rate, {2}),
+ tax.base_total = round(tax.total, {2}),
+ tax.total = round(tax.base_total / conversion_rate, {2}),
+ tax.base_tax_amount_after_discount_amount = round(tax.tax_amount_after_discount_amount, {2}),
+ tax.tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount / conversion_rate, {2})
WHERE
par.name = tax.parent
and par.docstatus < 2
- """.format(dt, tax_table))
+ """.format(dt, tax_table, tax_amount_precision))
diff --git a/erpnext/patches/v5_0/update_advance_paid.py b/erpnext/patches/v5_0/update_advance_paid.py
new file mode 100644
index 0000000..74e71e8
--- /dev/null
+++ b/erpnext/patches/v5_0/update_advance_paid.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ for dt in ("Sales Order", "Purchase Order"):
+ orders_with_advance = frappe.db.sql("""select name from `tab{0}`
+ where docstatus < 2 and ifnull(advance_paid, 0) != 0""".format(dt), as_dict=1)
+
+ for order in orders_with_advance:
+ frappe.get_doc(dt, order.name).set_total_advance_paid()
\ No newline at end of file
diff --git a/erpnext/patches/v5_0/update_item_description_and_image.py b/erpnext/patches/v5_0/update_item_description_and_image.py
index 7e61314..6b47052 100644
--- a/erpnext/patches/v5_0/update_item_description_and_image.py
+++ b/erpnext/patches/v5_0/update_item_description_and_image.py
@@ -30,7 +30,8 @@
count = 1
for d in records:
- if cstr(d.description) == item_details.get(d.item_code).old_description:
+ if d.item_code and item_details.get(d.item_code) \
+ and cstr(d.description) == item_details.get(d.item_code).old_description:
image_url = item_details.get(d.item_code).image_url
desc = item_details.get(d.item_code).new_description
else:
diff --git a/erpnext/patches/v5_0/update_projects.py b/erpnext/patches/v5_0/update_projects.py
index f49bc66..edb18af 100644
--- a/erpnext/patches/v5_0/update_projects.py
+++ b/erpnext/patches/v5_0/update_projects.py
@@ -3,6 +3,8 @@
def execute():
# convert milestones to tasks
frappe.reload_doctype("Project")
+ frappe.reload_doc("projects", "doctype", "project_task")
+ frappe.reload_doctype("Task")
for m in frappe.get_all("Project Milestone", "*"):
if (m.milestone and m.milestone_date
diff --git a/erpnext/patches/v5_0/update_temporary_account.py b/erpnext/patches/v5_0/update_temporary_account.py
new file mode 100644
index 0000000..078c871
--- /dev/null
+++ b/erpnext/patches/v5_0/update_temporary_account.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ frappe.db.sql("""Update `tabAccount` set account_type = 'Temporary'
+ where account_name in ('Temporary Assets', 'Temporary Liabilities', 'Temporary Opening')""")
\ No newline at end of file
diff --git a/erpnext/projects/doctype/activity_cost/__init__.py b/erpnext/projects/doctype/activity_cost/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/projects/doctype/activity_cost/__init__.py
diff --git a/erpnext/projects/doctype/activity_cost/activity_cost.json b/erpnext/projects/doctype/activity_cost/activity_cost.json
new file mode 100644
index 0000000..7f7720a
--- /dev/null
+++ b/erpnext/projects/doctype/activity_cost/activity_cost.json
@@ -0,0 +1,170 @@
+{
+ "allow_copy": 0,
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "Activity Cost - .#",
+ "creation": "2015-03-23 02:00:21.861546",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Master",
+ "fields": [
+ {
+ "allow_on_submit": 0,
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Employee",
+ "no_copy": 0,
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0
+ },
+ {
+ "fieldname": "employee_name",
+ "fieldtype": "Read Only",
+ "label": "Employee Name",
+ "options": "employee.employee_name",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "allow_on_submit": 0,
+ "fieldname": "activity_type",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Activity Type",
+ "no_copy": 0,
+ "options": "Activity Type",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "allow_on_submit": 0,
+ "default": "0",
+ "description": "per hour",
+ "fieldname": "billing_rate",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Billing Rate",
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "allow_on_submit": 0,
+ "default": "0",
+ "description": "per hour",
+ "fieldname": "costing_rate",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "in_filter": 0,
+ "in_list_view": 0,
+ "label": "Costing Rate",
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "read_only": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0
+ },
+ {
+ "fieldname": "title",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "title",
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ }
+ ],
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "in_create": 0,
+ "in_dialog": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "modified": "2015-04-14 02:08:33.690406",
+ "modified_by": "Administrator",
+ "module": "Projects",
+ "name": "Activity Cost",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Projects User",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "read_only": 0,
+ "read_only_onload": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "title"
+}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/activity_cost/activity_cost.py b/erpnext/projects/doctype/activity_cost/activity_cost.py
new file mode 100644
index 0000000..121e650
--- /dev/null
+++ b/erpnext/projects/doctype/activity_cost/activity_cost.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.model.document import Document
+
+class DuplicationError(frappe.ValidationError): pass
+
+class ActivityCost(Document):
+ def validate(self):
+ self.set_title()
+ self.check_unique()
+
+ def set_title(self):
+ self.title = _("{0} for {1}").format(self.employee_name, self.activity_type)
+
+ def check_unique(self):
+ if frappe.db.sql("""select name from `tabActivity Cost` where employee_name= %s and activity_type= %s and name != %s""",
+ (self.employee_name, self.activity_type, self.name)):
+ frappe.throw(_("Activity Cost exists for Employee {0} against Activity Type - {1}")
+ .format(self.employee, self.activity_type), DuplicationError)
diff --git a/erpnext/projects/doctype/activity_cost/test_activity_cost.py b/erpnext/projects/doctype/activity_cost/test_activity_cost.py
new file mode 100644
index 0000000..5afd97f
--- /dev/null
+++ b/erpnext/projects/doctype/activity_cost/test_activity_cost.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+from erpnext.projects.doctype.activity_cost.activity_cost import DuplicationError
+
+class TestActivityCost(unittest.TestCase):
+ def test_duplication(self):
+ frappe.db.sql("delete from `tabActivity Cost`")
+ activity_cost1 = frappe.new_doc('Activity Cost')
+ activity_cost1.update({
+ "employee": "_T-Employee-0001",
+ "employee_name": "_Test Employee",
+ "activity_type": "_Test Activity Type",
+ "billing_rate": 100,
+ "costing_rate": 50
+ })
+ activity_cost1.insert()
+ activity_cost2 = frappe.copy_doc(activity_cost1)
+ self.assertRaises(DuplicationError, activity_cost2.insert )
diff --git a/erpnext/projects/doctype/activity_cost/test_records.json b/erpnext/projects/doctype/activity_cost/test_records.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/erpnext/projects/doctype/activity_cost/test_records.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index eeedeb0..aa55876 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -1,6 +1,19 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
+frappe.ui.form.on("Project", {
+ onload: function(frm) {
+ var so = frappe.meta.get_docfield("Project", "sales_order");
+ so.get_route_options_for_new_doc = function(field) {
+ if(frm.is_new()) return;
+ return {
+ "customer": frm.doc.customer,
+ "project_name": frm.doc.name
+ }
+ }
+ }
+});
+
frappe.ui.form.on("Project Task", "edit_task", function(frm, doctype, name) {
var doc = frappe.get_doc(doctype, name);
if(doc.task_id) {
@@ -14,13 +27,21 @@
cur_frm.cscript.refresh = function(doc) {
if(!doc.__islocal) {
cur_frm.add_custom_button(__("Gantt Chart"), function() {
- frappe.route_options = {"project": doc.name, "start": doc.project_start_date, "end": doc.completion_date};
+ frappe.route_options = {"project": doc.name, "start": doc.expected_start_date, "end": doc.expected_end_date};
frappe.set_route("Gantt", "Task");
}, "icon-tasks", true);
cur_frm.add_custom_button(__("Tasks"), function() {
frappe.route_options = {"project": doc.name}
frappe.set_route("List", "Task");
}, "icon-list", true);
+ cur_frm.add_custom_button(__("Time Logs"), function() {
+ frappe.route_options = {"project": doc.name}
+ frappe.set_route("List", "Time Log");
+ }, "icon-list", true);
+ cur_frm.add_custom_button(__("Expense Claims"), function() {
+ frappe.route_options = {"project": doc.name}
+ frappe.set_route("List", "Expense Claim");
+ }, "icon-list", true);
}
}
@@ -29,3 +50,11 @@
query: "erpnext.controllers.queries.customer_query"
}
}
+
+cur_frm.fields_dict['sales_order'].get_query = function(doc) {
+ return {
+ filters:{
+ 'project_name': doc.name
+ }
+ }
+}
diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json
index 6a143ab..2aca991 100644
--- a/erpnext/projects/doctype/project/project.json
+++ b/erpnext/projects/doctype/project/project.json
@@ -8,19 +8,6 @@
"document_type": "Master",
"fields": [
{
- "fieldname": "overview",
- "fieldtype": "Section Break",
- "label": "Overview",
- "options": "icon-file",
- "permlevel": 0
- },
- {
- "fieldname": "cb_project_status",
- "fieldtype": "Column Break",
- "label": "Status",
- "permlevel": 0
- },
- {
"description": "",
"fieldname": "project_name",
"fieldtype": "Data",
@@ -46,6 +33,23 @@
"search_index": 1
},
{
+ "fieldname": "project_type",
+ "fieldtype": "Select",
+ "label": "Project Type",
+ "no_copy": 0,
+ "oldfieldname": "project_type",
+ "oldfieldtype": "Data",
+ "options": "Internal\nExternal\nOther",
+ "permlevel": 0,
+ "search_index": 0
+ },
+ {
+ "fieldname": "column_break_5",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "is_active",
"fieldtype": "Select",
"label": "Is Active",
@@ -69,16 +73,16 @@
"search_index": 0
},
{
- "fieldname": "cb_project_dates",
- "fieldtype": "Column Break",
- "label": "Dates",
- "permlevel": 0
+ "fieldname": "section_break_12",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
},
{
- "fieldname": "project_start_date",
+ "fieldname": "expected_start_date",
"fieldtype": "Date",
"in_filter": 1,
- "label": "Project Start Date",
+ "label": "Expected Start Date",
"no_copy": 0,
"oldfieldname": "project_start_date",
"oldfieldtype": "Date",
@@ -86,9 +90,15 @@
"search_index": 0
},
{
- "fieldname": "completion_date",
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "expected_end_date",
"fieldtype": "Date",
- "label": "Completion Date",
+ "label": "Expected End Date",
"no_copy": 0,
"oldfieldname": "completion_date",
"oldfieldtype": "Date",
@@ -96,25 +106,40 @@
"search_index": 0
},
{
- "fieldname": "act_completion_date",
- "fieldtype": "Date",
- "label": "Actual Completion Date",
- "no_copy": 0,
- "oldfieldname": "act_completion_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "search_index": 0
+ "fieldname": "customer_details",
+ "fieldtype": "Section Break",
+ "label": "",
+ "oldfieldtype": "Section Break",
+ "options": "icon-user",
+ "permlevel": 0
},
{
- "fieldname": "project_type",
- "fieldtype": "Select",
- "label": "Project Type",
+ "fieldname": "customer",
+ "fieldtype": "Link",
+ "in_filter": 1,
+ "label": "Customer",
"no_copy": 0,
- "oldfieldname": "project_type",
- "oldfieldtype": "Data",
- "options": "Internal\nExternal\nOther",
+ "oldfieldname": "customer",
+ "oldfieldtype": "Link",
+ "options": "Customer",
"permlevel": 0,
- "search_index": 0
+ "print_hide": 1,
+ "reqd": 0,
+ "search_index": 1
+ },
+ {
+ "fieldname": "column_break_14",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "sales_order",
+ "fieldtype": "Link",
+ "label": "Sales Order",
+ "options": "Sales Order",
+ "permlevel": 0,
+ "precision": ""
},
{
"fieldname": "sb_milestones",
@@ -130,7 +155,8 @@
"label": "Tasks",
"options": "Project Task",
"permlevel": 0,
- "precision": ""
+ "precision": "",
+ "reqd": 0
},
{
"fieldname": "percent_complete",
@@ -159,25 +185,55 @@
"search_index": 0
},
{
- "fieldname": "company",
- "fieldtype": "Link",
- "label": "Company",
- "options": "Company",
- "permlevel": 0
- },
- {
- "fieldname": "project_details",
+ "fieldname": "section_break_18",
"fieldtype": "Section Break",
- "label": "Project Costing",
- "oldfieldtype": "Section Break",
- "options": "icon-money",
- "permlevel": 0
+ "permlevel": 0,
+ "precision": ""
},
{
- "fieldname": "project_value",
+ "fieldname": "actual_start_date",
+ "fieldtype": "Data",
+ "label": "Actual Start Date",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "actual_time",
+ "fieldtype": "Float",
+ "label": "Actual Time (in Hours)",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_20",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "actual_end_date",
+ "fieldtype": "Date",
+ "label": "Actual End Date",
+ "no_copy": 0,
+ "oldfieldname": "act_completion_date",
+ "oldfieldtype": "Date",
+ "permlevel": 0,
+ "read_only": 1,
+ "search_index": 0
+ },
+ {
+ "fieldname": "section_break_26",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "estimated_costing",
"fieldtype": "Currency",
"in_list_view": 1,
- "label": "Project Value",
+ "label": "Estimated Costing",
"no_copy": 0,
"oldfieldname": "project_value",
"oldfieldtype": "Currency",
@@ -187,15 +243,17 @@
"search_index": 0
},
{
- "fieldname": "est_material_cost",
- "fieldtype": "Currency",
- "label": "Estimated Material Cost",
- "no_copy": 0,
- "oldfieldname": "est_material_cost",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "fieldname": "column_break_22",
+ "fieldtype": "Column Break",
"permlevel": 0,
- "search_index": 0
+ "precision": ""
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": "Company",
+ "options": "Company",
+ "permlevel": 0
},
{
"fieldname": "cost_center",
@@ -205,64 +263,100 @@
"permlevel": 0
},
{
- "fieldname": "column_break0",
+ "fieldname": "project_details",
+ "fieldtype": "Section Break",
+ "label": "",
+ "oldfieldtype": "Section Break",
+ "options": "icon-money",
+ "permlevel": 0
+ },
+ {
+ "description": "",
+ "fieldname": "total_costing_amount",
+ "fieldtype": "Currency",
+ "label": "Total Costing Amount (via Time Logs)",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "description": "",
+ "fieldname": "total_expense_claim",
+ "fieldtype": "Currency",
+ "label": "Total Expense Claim (via Expense Claims)",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_28",
"fieldtype": "Column Break",
- "label": "Margin",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "description": "",
+ "fieldname": "total_billing_amount",
+ "fieldtype": "Currency",
+ "label": "Total Billing Amount (via Time Logs)",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_purchase_cost",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "label": "Total Purchase Cost (via Purchase Invoice)",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "margin",
+ "fieldtype": "Section Break",
+ "label": "",
"oldfieldtype": "Column Break",
"permlevel": 0,
"width": "50%"
},
{
- "fieldname": "gross_margin_value",
+ "fieldname": "gross_margin",
"fieldtype": "Currency",
- "label": "Gross Margin Value",
+ "label": "Gross Margin",
"no_copy": 0,
"oldfieldname": "gross_margin_value",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
+ "read_only": 1,
"reqd": 0,
"search_index": 0
},
{
+ "fieldname": "column_break_37",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "per_gross_margin",
- "fieldtype": "Currency",
+ "fieldtype": "Percent",
"label": "Gross Margin %",
"no_copy": 0,
"oldfieldname": "per_gross_margin",
"oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
+ "options": "",
"permlevel": 0,
+ "read_only": 1,
"reqd": 0,
"search_index": 0
- },
- {
- "fieldname": "customer_details",
- "fieldtype": "Section Break",
- "label": "Customer Details",
- "oldfieldtype": "Section Break",
- "options": "icon-user",
- "permlevel": 0
- },
- {
- "fieldname": "customer",
- "fieldtype": "Link",
- "in_filter": 1,
- "label": "Customer",
- "no_copy": 0,
- "oldfieldname": "customer",
- "oldfieldtype": "Link",
- "options": "Customer",
- "permlevel": 0,
- "print_hide": 1,
- "reqd": 0,
- "search_index": 1
}
],
"icon": "icon-puzzle-piece",
"idx": 1,
"max_attachments": 4,
- "modified": "2015-02-22 11:17:49.051755",
+ "modified": "2015-04-27 07:37:44.239930",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project",
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index c142180..c914f22 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -21,27 +21,23 @@
"status": task.status,
"start_date": task.exp_start_date,
"end_date": task.exp_end_date,
- "desciption": task.description,
+ "description": task.description,
"task_id": task.name
})
- def get_gross_profit(self):
- pft, per_pft =0, 0
- pft = flt(self.project_value) - flt(self.est_material_cost)
- #if pft > 0:
- per_pft = (flt(pft) / flt(self.project_value)) * 100
- ret = {'gross_margin_value': pft, 'per_gross_margin': per_pft}
- return ret
-
def validate(self):
- if self.project_start_date and self.completion_date:
- if getdate(self.completion_date) < getdate(self.project_start_date):
- frappe.throw(_("Expected Completion Date can not be less than Project Start Date"))
-
+ self.validate_dates()
self.sync_tasks()
+ def validate_dates(self):
+ if self.expected_start_date and self.expected_end_date:
+ if getdate(self.expected_end_date) < getdate(self.expected_start_date):
+ frappe.throw(_("Expected End Date can not be less than Expected Start Date"))
+
def sync_tasks(self):
"""sync tasks and remove table"""
+ if self.flags.dont_sync_tasks: return
+
task_names = []
for t in self.tasks:
if t.task_id:
@@ -55,7 +51,7 @@
"status": t.status,
"exp_start_date": t.start_date,
"exp_end_date": t.end_date,
- "desciption": t.description,
+ "description": t.description,
})
task.flags.ignore_links = True
@@ -78,6 +74,25 @@
frappe.db.set_value("Project", self.name, "percent_complete",
int(float(completed) / total * 100))
+ def update_costing(self):
+ total_cost = frappe.db.sql("""select sum(total_costing_amount) as costing_amount,
+ sum(total_billing_amount) as billing_amount, sum(total_expense_claim) as expense_claim,
+ min(act_start_date) as start_date, max(act_end_date) as end_date, sum(actual_time) as time
+ from `tabTask` where project = %s""", self.name, as_dict=1)[0]
+
+ self.total_costing_amount = total_cost.costing_amount
+ self.total_billing_amount = total_cost.billing_amount
+ self.total_expense_claim = total_cost.expense_claim
+ self.actual_start_date = total_cost.start_date
+ self.actual_end_date = total_cost.end_date
+ self.actual_time = total_cost.time
+ self.gross_margin = flt(total_cost.billing_amount) - flt(total_cost.costing_amount)
+ if self.total_billing_amount:
+ self.per_gross_margin = (self.gross_margin / flt(self.total_billing_amount)) *100
+
+ def update_purchase_costing(self):
+ self.total_purchase_cost = frappe.db.sql("""select sum(amount) as cost
+ from `tabPurchase Invoice Item` where project_name = %s and docstatus=1 """, self.name, as_dict=1)[0].cost or 0
@frappe.whitelist()
def get_cost_center_name(project_name):
diff --git a/erpnext/projects/doctype/project/project_list.js b/erpnext/projects/doctype/project/project_list.js
index 8281c7d..b0d1ae8 100644
--- a/erpnext/projects/doctype/project/project_list.js
+++ b/erpnext/projects/doctype/project/project_list.js
@@ -1,5 +1,5 @@
frappe.listview_settings['Project'] = {
- add_fields: ["status", "priority", "is_active", "percent_complete", "completion_date"],
+ add_fields: ["status", "priority", "is_active", "percent_complete", "expected_end_date"],
filters:[["status","=", "Open"]],
get_indicator: function(doc) {
if(doc.status=="Open" && doc.percent_complete) {
diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py
index 744d6b4..f69ce80 100644
--- a/erpnext/projects/doctype/project/test_project.py
+++ b/erpnext/projects/doctype/project/test_project.py
@@ -5,4 +5,3 @@
import frappe
test_records = frappe.get_test_records('Project')
-test_ignore = ["Task"]
diff --git a/erpnext/projects/doctype/project/test_records.json b/erpnext/projects/doctype/project/test_records.json
index 69226f0..9379c22 100644
--- a/erpnext/projects/doctype/project/test_records.json
+++ b/erpnext/projects/doctype/project/test_records.json
@@ -1,10 +1,12 @@
[
{
- "project_name": "_Test Project",
- "status": "Open"
- },
- {
- "project_name": "_Test Project 1",
- "status": "Open"
+ "project_name": "_Test Project",
+ "status": "Open",
+ "tasks":[
+ {
+ "title": "_Test Task",
+ "status": "Open"
+ }
+ ]
}
]
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project_task/project_task.json b/erpnext/projects/doctype/project_task/project_task.json
index c29dcc0..e5aae3e 100644
--- a/erpnext/projects/doctype/project_task/project_task.json
+++ b/erpnext/projects/doctype/project_task/project_task.json
@@ -37,7 +37,7 @@
"in_filter": 0,
"in_list_view": 1,
"label": "Status",
- "no_copy": 0,
+ "no_copy": 1,
"options": "Open\nWorking\nPending Review\nClosed\nCancelled",
"permlevel": 0,
"precision": "",
@@ -49,9 +49,10 @@
"set_only_once": 0
},
{
+ "depends_on": "task_id",
"fieldname": "edit_task",
"fieldtype": "Button",
- "label": "Edit Task",
+ "label": "View Task",
"permlevel": 0,
"precision": ""
},
@@ -143,7 +144,7 @@
"is_submittable": 0,
"issingle": 0,
"istable": 1,
- "modified": "2015-02-23 01:55:18.865117",
+ "modified": "2015-04-23 05:48:00.504508",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project Task",
diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js
index 51aabca..9756331 100644
--- a/erpnext/projects/doctype/task/task.js
+++ b/erpnext/projects/doctype/task/task.js
@@ -25,6 +25,19 @@
this.frm.doc.project && frappe.model.remove_from_locals("Project",
this.frm.doc.project);
},
+
+ refresh: function(doc) {
+ if(!doc.__islocal) {
+ cur_frm.add_custom_button(__("Time Logs"), function() {
+ frappe.route_options = {"project": doc.project, "task": doc.name}
+ frappe.set_route("List", "Time Log");
+ }, "icon-list", true);
+ cur_frm.add_custom_button(__("Expense Claims"), function() {
+ frappe.route_options = {"project": doc.project, "task": doc.name}
+ frappe.set_route("List", "Expense Claim");
+ }, "icon-list", true);
+ }
+ }
});
diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json
index e547834..fc604c2 100644
--- a/erpnext/projects/doctype/task/task.json
+++ b/erpnext/projects/doctype/task/task.json
@@ -7,16 +7,6 @@
"document_type": "Master",
"fields": [
{
- "fieldname": "task_details",
- "fieldtype": "Section Break",
- "label": "",
- "oldfieldtype": "Section Break",
- "permlevel": 0,
- "print_width": "50%",
- "search_index": 0,
- "width": "50%"
- },
- {
"fieldname": "subject",
"fieldtype": "Data",
"in_filter": 1,
@@ -28,24 +18,14 @@
"reqd": 1
},
{
- "fieldname": "exp_start_date",
- "fieldtype": "Date",
- "label": "Expected Start Date",
- "oldfieldname": "exp_start_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "reqd": 0
- },
- {
- "fieldname": "exp_end_date",
- "fieldtype": "Date",
- "in_filter": 1,
- "label": "Expected End Date",
- "oldfieldname": "exp_end_date",
- "oldfieldtype": "Date",
- "permlevel": 0,
- "reqd": 0,
- "search_index": 1
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Project",
+ "oldfieldname": "project",
+ "oldfieldtype": "Link",
+ "options": "Project",
+ "permlevel": 0
},
{
"fieldname": "column_break0",
@@ -67,16 +47,6 @@
"permlevel": 0
},
{
- "fieldname": "project",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Project",
- "oldfieldname": "project",
- "oldfieldtype": "Link",
- "options": "Project",
- "permlevel": 0
- },
- {
"fieldname": "priority",
"fieldtype": "Select",
"in_filter": 1,
@@ -110,41 +80,52 @@
{
"fieldname": "time_and_budget",
"fieldtype": "Section Break",
- "label": "Time and Budget",
+ "label": "",
"oldfieldtype": "Section Break",
"permlevel": 0
},
{
- "fieldname": "expected",
- "fieldtype": "Column Break",
- "label": "Expected",
- "oldfieldtype": "Column Break",
+ "fieldname": "exp_start_date",
+ "fieldtype": "Date",
+ "label": "Expected Start Date",
+ "oldfieldname": "exp_start_date",
+ "oldfieldtype": "Date",
"permlevel": 0,
- "print_width": "50%",
- "width": "50%"
+ "reqd": 0
},
{
- "fieldname": "exp_total_hrs",
- "fieldtype": "Data",
- "label": "Total Hours (Expected)",
+ "default": "0",
+ "description": "",
+ "fieldname": "expected_time",
+ "fieldtype": "Float",
+ "label": "Expected Time (in hours)",
"oldfieldname": "exp_total_hrs",
"oldfieldtype": "Data",
"permlevel": 0,
"reqd": 0
},
{
- "fieldname": "allocated_budget",
- "fieldtype": "Currency",
- "label": "Allocated Budget",
- "oldfieldname": "allocated_budget",
- "oldfieldtype": "Currency",
- "options": "Company:company:default_currency",
- "permlevel": 0
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
},
{
+ "fieldname": "exp_end_date",
+ "fieldtype": "Date",
+ "in_filter": 1,
+ "label": "Expected End Date",
+ "oldfieldname": "exp_end_date",
+ "oldfieldtype": "Date",
+ "permlevel": 0,
+ "reqd": 0,
+ "search_index": 1
+ },
+ {
+ "description": "",
"fieldname": "actual",
- "fieldtype": "Column Break",
- "label": "Actual",
+ "fieldtype": "Section Break",
+ "label": "",
"oldfieldtype": "Column Break",
"permlevel": 0,
"print_width": "50%",
@@ -153,27 +134,77 @@
{
"fieldname": "act_start_date",
"fieldtype": "Date",
- "label": "Actual Start Date",
+ "label": "Actual Start Date (via Time Logs)",
"oldfieldname": "act_start_date",
"oldfieldtype": "Date",
- "permlevel": 0
+ "permlevel": 0,
+ "read_only": 1
+ },
+ {
+ "default": "",
+ "description": "",
+ "fieldname": "actual_time",
+ "fieldtype": "Float",
+ "label": "Actual Time (in hours)",
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
},
{
"fieldname": "act_end_date",
"fieldtype": "Date",
- "label": "Actual End Date",
+ "label": "Actual End Date (via Time Logs)",
"oldfieldname": "act_end_date",
"oldfieldtype": "Date",
- "permlevel": 0
+ "permlevel": 0,
+ "read_only": 1
},
{
- "fieldname": "actual_budget",
+ "fieldname": "section_break_17",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "total_costing_amount",
"fieldtype": "Currency",
- "label": "Actual Budget",
+ "label": "Total Costing Amount (via Time Logs)",
"oldfieldname": "actual_budget",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
- "permlevel": 0
+ "permlevel": 0,
+ "read_only": 1
+ },
+ {
+ "fieldname": "total_expense_claim",
+ "fieldtype": "Currency",
+ "label": "Total Expense Claim (via Expense Claim)",
+ "options": "Company:company:default_currency",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_20",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "total_billing_amount",
+ "fieldtype": "Currency",
+ "hidden": 0,
+ "label": "Total Billing Amount (via Time Logs)",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
},
{
"fieldname": "more_details",
@@ -216,8 +247,9 @@
],
"icon": "icon-check",
"idx": 1,
+ "istable": 0,
"max_attachments": 5,
- "modified": "2015-02-20 05:09:27.295024",
+ "modified": "2015-04-14 07:56:24.481667",
"modified_by": "Administrator",
"module": "Projects",
"name": "Task",
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index acd0877..a03340f 100644
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe, json
-from frappe.utils import getdate, today
+from frappe.utils import getdate
from frappe import _
@@ -26,27 +26,48 @@
return ret
def validate(self):
+ self.validate_dates()
+
+ def validate_dates(self):
if self.exp_start_date and self.exp_end_date and getdate(self.exp_start_date) > getdate(self.exp_end_date):
frappe.throw(_("'Expected Start Date' can not be greater than 'Expected End Date'"))
if self.act_start_date and self.act_end_date and getdate(self.act_start_date) > getdate(self.act_end_date):
frappe.throw(_("'Actual Start Date' can not be greater than 'Actual End Date'"))
- self.update_status()
-
- def update_status(self):
- status = frappe.db.get_value("Task", self.name, "status")
- if self.status=="Working" and status !="Working" and not self.act_start_date:
- self.act_start_date = today()
-
- if self.status=="Closed" and status != "Closed" and not self.act_end_date:
- self.act_end_date = today()
-
def on_update(self):
+ self.update_percentage()
+ self.update_project()
+
+ def update_percentage(self):
"""update percent complete in project"""
if self.project and not self.flags.from_project:
project = frappe.get_doc("Project", self.project)
project.run_method("update_percent_complete")
+
+ def update_total_expense_claim(self):
+ self.total_expense_claim = frappe.db.sql("""select sum(total_sanctioned_amount) from `tabExpense Claim`
+ where project = %s and task = %s and approval_status = "Approved" and docstatus=1""",(self.project, self.name))
+
+ def update_time_and_costing(self):
+ tl = frappe.db.sql("""select min(from_time) as start_date, max(to_time) as end_date,
+ sum(billing_amount) as total_billing_amount, sum(costing_amount) as total_costing_amount,
+ sum(hours) as time from `tabTime Log` where project = %s and task = %s and docstatus=1""",
+ (self.project, self.name),as_dict=1)[0]
+ if self.status == "Open":
+ self.status = "Working"
+ self.total_costing_amount= tl.total_costing_amount
+ self.total_billing_amount= tl.total_billing_amount
+ self.actual_time= tl.time
+ self.act_start_date= tl.start_date
+ self.act_end_date= tl.end_date
+
+ def update_project(self):
+ if self.project and frappe.db.exists("Project", self.project):
+ project = frappe.get_doc("Project", self.project)
+ project.flags.dont_sync_tasks = True
+ project.update_costing()
+ project.save()
@frappe.whitelist()
def get_events(start, end, filters=None):
diff --git a/erpnext/projects/doctype/task/test_records.json b/erpnext/projects/doctype/task/test_records.json
index 1f98172..42ca0e7 100644
--- a/erpnext/projects/doctype/task/test_records.json
+++ b/erpnext/projects/doctype/task/test_records.json
@@ -1,8 +1,8 @@
[
{
- "project": "_Test Project",
"status": "Open",
- "subject": "_Test Task"
+ "subject": "_Test Task",
+ "name": "task001"
},
{
"status": "Open",
diff --git a/erpnext/projects/doctype/task/test_task.py b/erpnext/projects/doctype/task/test_task.py
index 6f75e0d..62e560f 100644
--- a/erpnext/projects/doctype/task/test_task.py
+++ b/erpnext/projects/doctype/task/test_task.py
@@ -5,5 +5,3 @@
import frappe
test_records = frappe.get_test_records('Task')
-test_dependencies = ["Project"]
-test_ignore = ["Customer"]
diff --git a/erpnext/projects/doctype/time_log/test_records.json b/erpnext/projects/doctype/time_log/test_records.json
index d9e67e9..568c012 100644
--- a/erpnext/projects/doctype/time_log/test_records.json
+++ b/erpnext/projects/doctype/time_log/test_records.json
@@ -5,7 +5,6 @@
"doctype": "Time Log",
"from_time": "2013-01-01 10:00:00.000000",
"note": "_Test Note",
- "to_time": "2013-01-01 11:00:00.000000",
- "project": "_Test Project"
+ "to_time": "2013-01-01 11:00:00.000000"
}
]
diff --git a/erpnext/projects/doctype/time_log/test_time_log.py b/erpnext/projects/doctype/time_log/test_time_log.py
index 8f8e31d..3d9e0be 100644
--- a/erpnext/projects/doctype/time_log/test_time_log.py
+++ b/erpnext/projects/doctype/time_log/test_time_log.py
@@ -10,7 +10,6 @@
from erpnext.projects.doctype.time_log.time_log import NotSubmittedError
from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
from erpnext.manufacturing.doctype.workstation.workstation import NotInWorkingHoursError
-from erpnext.projects.doctype.time_log_batch.test_time_log_batch import *
from erpnext.manufacturing.doctype.production_order.test_production_order import make_prod_order_test_record
@@ -85,6 +84,72 @@
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`")
-
+
+ def test_total_activity_cost_for_project(self):
+ frappe.db.sql("""delete from `tabTask` where project = "_Test Project 1" """)
+ frappe.db.sql("""delete from `tabProject` where name = "_Test Project 1" """)
+ frappe.db.sql("""delete from `tabActivity Cost` where employee = "_T-Employee-0001" and activity_type = "_Test Activity Type" """)
+
+ activity_cost = frappe.new_doc('Activity Cost')
+ activity_cost.update({
+ "employee": "_T-Employee-0001",
+ "employee_name": "_Test Employee",
+ "activity_type": "_Test Activity Type",
+ "billing_rate": 100,
+ "costing_rate": 50
+ })
+ activity_cost.insert()
+
+ frappe.get_doc({
+ "project_name": "_Test Project 1",
+ "doctype": "Project",
+ "tasks" :
+ [{ "title": "_Test Project Task 1", "status": "Open" }]
+ }).save()
+
+ task_name = frappe.db.get_value("Task",{"project": "_Test Project 1"})
+
+ time_log = frappe.get_doc({
+ "activity_type": "_Test Activity Type",
+ "docstatus": 1,
+ "doctype": "Time Log",
+ "from_time": "2013-02-02 09:00:00.000000",
+ "to_time": "2013-02-02 11:00:00.000000",
+ "employee": "_T-Employee-0001",
+ "project": "_Test Project 1",
+ "task": task_name,
+ "billable": 1
+ })
+ time_log.save()
+ self.assertEqual(time_log.costing_rate, 50)
+ self.assertEqual(time_log.costing_amount, 100)
+ self.assertEqual(time_log.billing_rate, 100)
+ self.assertEqual(time_log.billing_amount, 200)
+ time_log.submit()
+
+ self.assertEqual(frappe.db.get_value("Task", task_name, "total_billing_amount"), 200)
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_billing_amount"), 200)
+
+ time_log2 = frappe.get_doc({
+ "activity_type": "_Test Activity Type",
+ "docstatus": 1,
+ "doctype": "Time Log",
+ "from_time": "2013-02-03 09:00:00.000000",
+ "to_time": "2013-02-03 11:00:00.000000",
+ "employee": "_T-Employee-0001",
+ "project": "_Test Project 1",
+ "task": task_name,
+ "billable": 1
+ })
+ time_log2.save()
+
+ self.assertEqual(frappe.db.get_value("Task", task_name, "total_billing_amount"), 400)
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_billing_amount"), 400)
+
+ time_log2.cancel()
+
+ self.assertEqual(frappe.db.get_value("Task", task_name, "total_billing_amount"), 200)
+ self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_billing_amount"), 200)
+
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.js b/erpnext/projects/doctype/time_log/time_log.js
index a49b1f1..536ddf8 100644
--- a/erpnext/projects/doctype/time_log/time_log.js
+++ b/erpnext/projects/doctype/time_log/time_log.js
@@ -4,10 +4,12 @@
frappe.provide("erpnext.projects");
frappe.ui.form.on("Time Log", "onload", function(frm) {
- frm.set_query("task", erpnext.queries.task);
if (frm.doc.for_manufacturing) {
frappe.ui.form.trigger("Time Log", "production_order");
}
+ if (frm.doc.from_time && frm.doc.to_time) {
+ frappe.ui.form.trigger("Time Log", "to_time");
+ }
});
frappe.ui.form.on("Time Log", "refresh", function(frm) {
@@ -41,4 +43,60 @@
if(frm._setting_hours) return;
frm.set_value("hours", moment(cur_frm.doc.to_time).diff(moment(cur_frm.doc.from_time),
"hours"));
-});
\ No newline at end of file
+
+});
+
+var calculate_cost = function(frm) {
+ frm.set_value("costing_amount", frm.doc.costing_rate * frm.doc.hours);
+ if (frm.doc.billable==1){
+ frm.set_value("billing_amount", frm.doc.billing_rate * frm.doc.hours);
+ }
+}
+
+var get_activity_cost = function(frm) {
+ if (frm.doc.employee && frm.doc.activity_type){
+ return frappe.call({
+ method: "erpnext.projects.doctype.time_log.time_log.get_activity_cost",
+ args: {
+ "employee": frm.doc.employee,
+ "activity_type": frm.doc.activity_type
+ },
+ callback: function(r) {
+ if(!r.exc && r.message) {
+ frm.set_value("costing_rate", r.message.costing_rate);
+ frm.set_value("billing_rate", r.message.billing_rate);
+ calculate_cost(frm);
+ }
+ }
+ });
+ }
+}
+
+frappe.ui.form.on("Time Log", "hours", function(frm) {
+ calculate_cost(frm);
+});
+
+frappe.ui.form.on("Time Log", "activity_type", function(frm) {
+ get_activity_cost(frm);
+});
+
+frappe.ui.form.on("Time Log", "employee", function(frm) {
+ get_activity_cost(frm);
+});
+
+frappe.ui.form.on("Time Log", "billable", function(frm) {
+ if (frm.doc.billable==1) {
+ calculate_cost(frm);
+ }
+ else {
+ frm.set_value("billing_amount", 0);
+ }
+});
+
+cur_frm.fields_dict['task'].get_query = function(doc) {
+ return {
+ filters:{
+ 'project': doc.project
+ }
+ }
+}
diff --git a/erpnext/projects/doctype/time_log/time_log.json b/erpnext/projects/doctype/time_log/time_log.json
index 20b5c0c..e9e2077 100644
--- a/erpnext/projects/doctype/time_log/time_log.json
+++ b/erpnext/projects/doctype/time_log/time_log.json
@@ -17,44 +17,10 @@
"reqd": 1
},
{
- "fieldname": "from_time",
- "fieldtype": "Datetime",
- "in_list_view": 0,
- "label": "From Time",
- "permlevel": 0,
- "read_only": 0,
- "reqd": 1
- },
- {
- "fieldname": "to_time",
- "fieldtype": "Datetime",
- "in_list_view": 0,
- "label": "To Time",
- "permlevel": 0,
- "read_only": 0,
- "reqd": 1
- },
- {
- "fieldname": "hours",
- "fieldtype": "Float",
- "in_list_view": 1,
- "label": "Hours",
- "permlevel": 0,
- "read_only": 0
- },
- {
- "fieldname": "user",
- "fieldtype": "Link",
- "label": "User",
- "options": "User",
- "permlevel": 0,
- "precision": ""
- },
- {
- "fieldname": "column_break_3",
+ "fieldname": "column_break_2",
"fieldtype": "Column Break",
"permlevel": 0,
- "read_only": 0
+ "precision": ""
},
{
"fieldname": "status",
@@ -67,20 +33,62 @@
"reqd": 0
},
{
- "fieldname": "billable",
- "fieldtype": "Check",
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "from_time",
+ "fieldtype": "Datetime",
"in_list_view": 0,
- "label": "Billable",
+ "label": "From Time",
+ "permlevel": 0,
+ "read_only": 0,
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "hours",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Hours",
"permlevel": 0,
"read_only": 0
},
{
- "fieldname": "for_manufacturing",
- "fieldtype": "Check",
- "label": "For Manufacturing",
+ "fieldname": "to_time",
+ "fieldtype": "Datetime",
+ "in_list_view": 0,
+ "label": "To Time",
"permlevel": 0,
- "precision": "",
- "read_only": 1
+ "read_only": 0,
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "depends_on": "",
+ "fieldname": "project",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Project",
+ "options": "Project",
+ "permlevel": 0,
+ "read_only": 0
+ },
+ {
+ "depends_on": "",
+ "fieldname": "task",
+ "fieldtype": "Link",
+ "label": "Task",
+ "options": "Task",
+ "permlevel": 0,
+ "read_only": 0
},
{
"depends_on": "eval:!doc.for_manufacturing",
@@ -94,11 +102,47 @@
"reqd": 0
},
{
- "depends_on": "eval:!doc.for_manufacturing",
- "fieldname": "task",
+ "fieldname": "section_break_12",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "user",
"fieldtype": "Link",
- "label": "Task",
- "options": "Task",
+ "label": "User",
+ "options": "User",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "employee",
+ "fieldtype": "Link",
+ "label": "Employee",
+ "options": "Employee",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "read_only": 0
+ },
+ {
+ "fieldname": "for_manufacturing",
+ "fieldtype": "Check",
+ "hidden": 1,
+ "label": "For Manufacturing",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "billable",
+ "fieldtype": "Check",
+ "in_list_view": 0,
+ "label": "Billable",
"permlevel": 0,
"read_only": 0
},
@@ -180,20 +224,62 @@
"read_only": 0
},
{
- "fieldname": "section_break_9",
+ "depends_on": "",
+ "fieldname": "section_break_24",
"fieldtype": "Section Break",
"permlevel": 0,
- "read_only": 0
+ "precision": ""
},
{
- "depends_on": "",
- "fieldname": "project",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Project",
- "options": "Project",
+ "default": "0",
+ "description": "",
+ "fieldname": "costing_rate",
+ "fieldtype": "Currency",
+ "label": "Costing Rate (per hour)",
"permlevel": 0,
- "read_only": 0
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "fieldname": "costing_amount",
+ "fieldtype": "Currency",
+ "label": "Costing Amount",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_25",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "default": "0",
+ "description": "",
+ "fieldname": "billing_rate",
+ "fieldtype": "Currency",
+ "label": "Billing Rate (per hour)",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "default": "0",
+ "description": "Will be updated only if Time Log is 'Billable'",
+ "fieldname": "billing_amount",
+ "fieldtype": "Currency",
+ "label": "Billing Amount",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_29",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
},
{
"description": "Will be updated when batched.",
@@ -214,12 +300,6 @@
"read_only": 1
},
{
- "fieldname": "column_break_16",
- "fieldtype": "Column Break",
- "permlevel": 0,
- "read_only": 0
- },
- {
"fieldname": "amended_from",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@@ -242,7 +322,7 @@
"icon": "icon-time",
"idx": 1,
"is_submittable": 1,
- "modified": "2015-04-06 02:47:16.187046",
+ "modified": "2015-04-14 09:07:28.468792",
"modified_by": "Administrator",
"module": "Projects",
"name": "Time Log",
diff --git a/erpnext/projects/doctype/time_log/time_log.py b/erpnext/projects/doctype/time_log/time_log.py
index c385c09..f7b501d 100644
--- a/erpnext/projects/doctype/time_log/time_log.py
+++ b/erpnext/projects/doctype/time_log/time_log.py
@@ -24,12 +24,16 @@
self.check_workstation_timings()
self.validate_production_order()
self.validate_manufacturing()
+ self.validate_task()
+ self.update_cost()
def on_submit(self):
self.update_production_order()
+ self.update_task()
def on_cancel(self):
self.update_production_order()
+ self.update_task()
def before_update_after_submit(self):
self.set_status()
@@ -63,6 +67,7 @@
def validate_overlap(self):
"""Checks if 'Time Log' entries overlap for a user, workstation. """
self.validate_overlap_for("user")
+ self.validate_overlap_for("employee")
self.validate_overlap_for("workstation")
def validate_overlap_for(self, fieldname):
@@ -123,8 +128,8 @@
def update_production_order(self):
"""Updates `start_date`, `end_date`, `status` for operation in Production Order."""
-
- if self.for_manufacturing and self.production_order:
+
+ if self.production_order and self.for_manufacturing:
if not self.operation_id:
frappe.throw(_("Operation ID not set"))
@@ -205,6 +210,27 @@
self.production_order = None
self.operation = None
self.quantity = None
+
+ def update_cost(self):
+ rate = get_activity_cost(self.employee, self.activity_type)
+ if rate:
+ self.costing_rate = rate.get('costing_rate')
+ self.billing_rate = rate.get('billing_rate')
+ self.costing_amount = self.costing_rate * self.hours
+ if self.billable:
+ self.billing_amount = self.billing_rate * self.hours
+ else:
+ self.billing_amount = 0
+
+ def validate_task(self):
+ if self.project and not self.task:
+ frappe.throw(_("Task is Mandatory if Time Log is against a project"))
+
+ def update_task(self):
+ if self.task and frappe.db.exists("Task", self.task):
+ task = frappe.get_doc("Task", self.task)
+ task.update_time_and_costing()
+ task.save()
@frappe.whitelist()
def get_events(start, end, filters=None):
@@ -242,3 +268,9 @@
d.title += " for Project: " + d.project
return data
+
+@frappe.whitelist()
+def get_activity_cost(employee=None, activity_type=None):
+ rate = frappe.db.sql("""select costing_rate, billing_rate from `tabActivity Cost` where employee= %s
+ and activity_type= %s""", (employee, activity_type), as_dict=1)
+ return rate[0] if rate else {}
diff --git a/erpnext/projects/doctype/time_log/time_log_list.js b/erpnext/projects/doctype/time_log/time_log_list.js
index d444806..a2eb05c 100644
--- a/erpnext/projects/doctype/time_log/time_log_list.js
+++ b/erpnext/projects/doctype/time_log/time_log_list.js
@@ -3,7 +3,7 @@
// render
frappe.listview_settings['Time Log'] = {
- add_fields: ["status", "billable", "activity_type", "task", "project", "hours", "for_manufacturing"],
+ add_fields: ["status", "billable", "activity_type", "task", "project", "hours", "for_manufacturing", "billing_amount"],
selectable: true,
onload: function(me) {
me.page.add_menu_item(__("Make Time Log Batch"), function() {
@@ -37,7 +37,7 @@
$.extend(detail, {
"time_log": d.name,
"activity_type": d.activity_type,
- "created_by": d.owner,
+ "billing_amount": d.billing_amount,
"hours": d.hours
});
})
diff --git a/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py b/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py
index 240ca97..faa0a60 100644
--- a/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py
+++ b/erpnext/projects/doctype/time_log_batch/test_time_log_batch.py
@@ -44,7 +44,6 @@
def create_time_log_batch(time_log):
tlb = frappe.get_doc({
"doctype": "Time Log Batch",
- "rate": "500",
"time_logs": [
{
"doctype": "Time Log Batch Detail",
diff --git a/erpnext/projects/doctype/time_log_batch/time_log_batch.js b/erpnext/projects/doctype/time_log_batch/time_log_batch.js
index 0635db0..6b5f080 100644
--- a/erpnext/projects/doctype/time_log_batch/time_log_batch.js
+++ b/erpnext/projects/doctype/time_log_batch/time_log_batch.js
@@ -2,7 +2,7 @@
// License: GNU General Public License v3. See license.txt
cur_frm.add_fetch("time_log", "activity_type", "activity_type");
-cur_frm.add_fetch("time_log", "owner", "created_by");
+cur_frm.add_fetch("time_log", "billing_amount", "billing_amount");
cur_frm.add_fetch("time_log", "hours", "hours");
cur_frm.set_query("time_log", "time_logs", function(doc) {
@@ -36,3 +36,15 @@
});
}
});
+
+frappe.ui.form.on("Time Log Batch Detail", "time_log", function(frm, cdt, cdn) {
+ var tl = frm.doc.time_logs || [];
+ total_hr = 0;
+ total_amt = 0;
+ for(var i=0; i<tl.length; i++) {
+ total_hr += tl[i].hours;
+ total_amt += tl[i].billing_amount;
+ }
+ cur_frm.set_value("total_hours", total_hr);
+ cur_frm.set_value("total_billing_amount", total_amt);
+});
\ No newline at end of file
diff --git a/erpnext/projects/doctype/time_log_batch/time_log_batch.json b/erpnext/projects/doctype/time_log_batch/time_log_batch.json
index a42c4ea..93726ee 100644
--- a/erpnext/projects/doctype/time_log_batch/time_log_batch.json
+++ b/erpnext/projects/doctype/time_log_batch/time_log_batch.json
@@ -15,28 +15,22 @@
"reqd": 1
},
{
- "description": "For Sales Invoice",
- "fieldname": "rate",
- "fieldtype": "Currency",
- "label": "Rate",
- "permlevel": 0
- },
- {
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "permlevel": 0
- },
- {
"default": "Draft",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 0,
"label": "Status",
+ "no_copy": 1,
"options": "Draft\nSubmitted\nBilled\nCancelled",
"permlevel": 0,
"read_only": 1
},
{
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "permlevel": 0
+ },
+ {
"description": "Will be updated after Sales Invoice is Submitted.",
"fieldname": "sales_invoice",
"fieldtype": "Link",
@@ -60,7 +54,14 @@
"reqd": 1
},
{
- "description": "In Hours",
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "default": "0",
+ "description": "updated via Time Logs",
"fieldname": "total_hours",
"fieldtype": "Float",
"in_list_view": 1,
@@ -69,6 +70,22 @@
"read_only": 1
},
{
+ "fieldname": "column_break_10",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
+ "default": "0",
+ "description": "updated via Time Logs",
+ "fieldname": "total_billing_amount",
+ "fieldtype": "Float",
+ "label": "Total Billing Amount",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
+ },
+ {
"fieldname": "amended_from",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@@ -83,7 +100,7 @@
"icon": "icon-time",
"idx": 1,
"is_submittable": 1,
- "modified": "2015-02-05 05:11:48.360822",
+ "modified": "2015-04-15 08:00:52.746961",
"modified_by": "Administrator",
"module": "Projects",
"name": "Time Log Batch",
diff --git a/erpnext/projects/doctype/time_log_batch/time_log_batch.py b/erpnext/projects/doctype/time_log_batch/time_log_batch.py
index 9565536..eaccc8c 100644
--- a/erpnext/projects/doctype/time_log_batch/time_log_batch.py
+++ b/erpnext/projects/doctype/time_log_batch/time_log_batch.py
@@ -7,6 +7,7 @@
import frappe
from frappe import _
+from frappe.utils import flt
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
@@ -14,22 +15,24 @@
def validate(self):
self.set_status()
- self.total_hours = 0.0
for d in self.get("time_logs"):
tl = frappe.get_doc("Time Log", d.time_log)
self.update_time_log_values(d, tl)
self.validate_time_log_is_submitted(tl)
- self.total_hours += float(tl.hours or 0.0)
+ self.total_hours += flt(tl.hours)
+ self.total_billing_amount += flt(tl.billing_amount)
def update_time_log_values(self, d, tl):
d.update({
"hours": tl.hours,
"activity_type": tl.activity_type,
- "created_by": tl.owner
+ "billing_amount": tl.billing_amount
})
def validate_time_log_is_submitted(self, tl):
- if tl.status != "Submitted" and self.docstatus == 0:
+ if tl.status == "Batched for Billing":
+ frappe.throw(_("Time Log {0} already billed").format(tl.name))
+ elif tl.status != "Submitted":
frappe.throw(_("Time Log {0} must be 'Submitted'").format(tl.name))
def set_status(self):
@@ -65,15 +68,15 @@
def update_item(source_doc, target_doc, source_parent):
target_doc.stock_uom = "Hour"
target_doc.description = "via Time Logs"
+ target_doc.qty = 1
target = frappe.new_doc("Sales Invoice")
target.append("items", get_mapped_doc("Time Log Batch", source_name, {
"Time Log Batch": {
"doctype": "Sales Invoice Item",
"field_map": {
- "rate": "base_rate",
- "name": "time_log_batch",
- "total_hours": "qty",
+ "total_billing_amount": "rate",
+ "name": "time_log_batch"
},
"postprocess": update_item
}
diff --git a/erpnext/projects/doctype/time_log_batch/time_log_batch_list.js b/erpnext/projects/doctype/time_log_batch/time_log_batch_list.js
index f4876b8..9c02ac3 100644
--- a/erpnext/projects/doctype/time_log_batch/time_log_batch_list.js
+++ b/erpnext/projects/doctype/time_log_batch/time_log_batch_list.js
@@ -1,5 +1,5 @@
frappe.listview_settings['Time Log Batch'] = {
- add_fields: ["status", "total_hours", "rate"],
+ add_fields: ["status", "total_hours"],
get_indicator: function(doc) {
return [__(doc.status), frappe.utils.guess_colour(doc.status), "status,=," + doc.status];
}
diff --git a/erpnext/projects/doctype/time_log_batch_detail/time_log_batch_detail.json b/erpnext/projects/doctype/time_log_batch_detail/time_log_batch_detail.json
index 15e7e8e..da8ff4c 100644
--- a/erpnext/projects/doctype/time_log_batch_detail/time_log_batch_detail.json
+++ b/erpnext/projects/doctype/time_log_batch_detail/time_log_batch_detail.json
@@ -1,5 +1,5 @@
{
- "creation": "2013-03-05 09:11:06.000000",
+ "creation": "2013-03-05 09:11:06",
"docstatus": 0,
"doctype": "DocType",
"fields": [
@@ -15,15 +15,20 @@
"width": "200px"
},
{
- "fieldname": "created_by",
- "fieldtype": "Link",
+ "fieldname": "hours",
+ "fieldtype": "Float",
"in_list_view": 1,
- "label": "Created By",
- "options": "User",
+ "label": "Hours",
"permlevel": 0,
"read_only": 1
},
{
+ "fieldname": "section_break_3",
+ "fieldtype": "Column Break",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "activity_type",
"fieldtype": "Data",
"in_list_view": 1,
@@ -32,18 +37,21 @@
"read_only": 1
},
{
- "fieldname": "hours",
+ "fieldname": "billing_amount",
"fieldtype": "Float",
"in_list_view": 1,
- "label": "Hours",
- "permlevel": 0
+ "label": "Billing Amount",
+ "permlevel": 0,
+ "precision": "",
+ "read_only": 1
}
],
"idx": 1,
"istable": 1,
- "modified": "2013-12-20 19:21:54.000000",
+ "modified": "2015-04-15 05:35:08.805589",
"modified_by": "Administrator",
"module": "Projects",
"name": "Time Log Batch Detail",
- "owner": "Administrator"
+ "owner": "Administrator",
+ "permissions": []
}
\ No newline at end of file
diff --git a/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py b/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py
index 1ef760e..5800156 100644
--- a/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py
+++ b/erpnext/projects/report/project_wise_stock_tracking/project_wise_stock_tracking.py
@@ -17,8 +17,8 @@
data.append([project.name, pr_item_map.get(project.name, 0),
se_item_map.get(project.name, 0), dn_item_map.get(project.name, 0),
project.project_name, project.status, project.company,
- project.customer, project.project_value, project.project_start_date,
- project.completion_date])
+ project.customer, project.estimated_costing, project.expected_start_date,
+ project.expected_end_date])
return columns, data
@@ -30,8 +30,8 @@
_("Project Start Date") + ":Date:120", _("Completion Date") + ":Date:120"]
def get_project_details():
- return frappe.db.sql(""" select name, project_name, status, company, customer, project_value,
- project_start_date, completion_date from tabProject where docstatus < 2""", as_dict=1)
+ return frappe.db.sql(""" select name, project_name, status, company, customer, estimated_costing,
+ expected_start_date, expected_end_date from tabProject where docstatus < 2""", as_dict=1)
def get_purchased_items_cost():
pr_items = frappe.db.sql("""select project_name, sum(base_net_amount) as amount
diff --git a/erpnext/public/js/account_tree_grid.js b/erpnext/public/js/account_tree_grid.js
index ed3704a..ac8784d 100644
--- a/erpnext/public/js/account_tree_grid.js
+++ b/erpnext/public/js/account_tree_grid.js
@@ -178,7 +178,7 @@
var me= this;
$.each(this.data, function(i, account) {
// update groups
- if((account.group_or_ledger == "Ledger") || (account.rgt - account.lft == 1)) {
+ if((account.is_group == 0) || (account.rgt - account.lft == 1)) {
var parent = me.parent_map[account.name];
while(parent) {
var parent_account = me.item_by_name[parent];
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index 5d779fa..212d2ae 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -5,6 +5,66 @@
frappe.provide("erpnext.taxes");
frappe.provide("erpnext.taxes.flags");
+frappe.ui.form.on(cur_frm.doctype, {
+ onload: function(frm) {
+ if(frm.get_field("taxes")) {
+ frm.set_query("account_head", "taxes", function(doc) {
+ if(frm.cscript.tax_table == "Sales Taxes and Charges") {
+ var account_type = ["Tax", "Chargeable", "Expense Account"];
+ } else {
+ var account_type = ["Tax", "Chargeable", "Income Account"];
+ }
+
+ return {
+ query: "erpnext.controllers.queries.tax_account_query",
+ filters: {
+ "account_type": account_type,
+ "company": doc.company
+ }
+ }
+ });
+
+ frm.set_query("cost_center", "taxes", function(doc) {
+ return {
+ filters: {
+ 'company': doc.company,
+ "is_group": 0
+ }
+ }
+ });
+ }
+ },
+ validate: function(frm) {
+ // neither is absolutely mandatory
+ // check mandatory based on charge_type
+ frm.get_docfield("taxes", "rate").reqd = 0;
+ frm.get_docfield("taxes", "tax_amount").reqd = 0;
+
+ $.each(frm.doc.taxes || [], function(i, d) {
+ if(d.charge_type==="Actual") {
+ d.rate = 0;
+ if(!d.tax_amount) {
+ msgprint(__("Amount is mandatory for {0}", [d.account_head]));
+ validated = false;
+ }
+ } else {
+ d.tax_amount = 0;
+ if(!d.rate) {
+ msgprint(__("Rate is mandatory for {0}", [d.account_head]));
+ validated = false;
+ }
+ }
+ });
+ },
+ taxes_on_form_rendered: function(frm) {
+ erpnext.taxes.set_conditional_mandatory_rate_or_amount(frm);
+ }
+});
+
+
+
+
+
cur_frm.cscript.account_head = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
@@ -134,42 +194,6 @@
}
}
-// setup conditional mandatory for tax and rates
-frappe.ui.form.on(cur_frm.doctype, "taxes_on_form_rendered", function(frm) {
- erpnext.taxes.set_conditional_mandatory_rate_or_amount(frm);
-});
-
-// setup queries for taxes
-frappe.ui.form.on(cur_frm.doctype, "onload", function(frm) {
- if(frm.get_field("taxes")) {
- frm.set_query("account_head", "taxes", function(doc) {
- if(frm.cscript.tax_table == "Sales Taxes and Charges") {
- var account_type = ["Tax", "Chargeable", "Expense Account"];
- } else {
- var account_type = ["Tax", "Chargeable", "Income Account"];
- }
-
- return {
- query: "erpnext.controllers.queries.tax_account_query",
- filters: {
- "account_type": account_type,
- "company": doc.company
- }
- }
- });
-
- frm.set_query("cost_center", "taxes", function(doc) {
- return {
- filters: {
- 'company': doc.company,
- 'group_or_ledger': "Ledger"
- }
- }
- });
- }
-});
-
-
// For customizing print
cur_frm.pformat.total = function(doc) { return ''; }
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index d39cc1a..6acf64c 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -335,9 +335,9 @@
var diff = me.frm.doc.net_total
- flt(last_tax.total / me.frm.doc.conversion_rate, precision("grand_total"));
- if ( diff && Math.abs(diff) <= (2.0 / Math.pow(10, last_tax.precision("tax_amount"))) ) {
+ if ( diff && Math.abs(diff) <= (2.0 / Math.pow(10, precision("tax_amount", last_tax))) ) {
var adjustment_amount = flt(diff * me.frm.doc.conversion_rate,
- last_tax.precision("tax_amount"));
+ precision("tax_amount", last_tax));
last_tax.tax_amount += adjustment_amount;
last_tax.tax_amount_after_discount += adjustment_amount;
last_tax.total += adjustment_amount;
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 7ee342f..b45e120 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -190,8 +190,11 @@
if (this.frm.doc.posting_date) var date = this.frm.doc.posting_date;
else var date = this.frm.doc.transaction_date;
erpnext.get_fiscal_year(this.frm.doc.company, date, fn);
-
erpnext.get_letter_head(this.frm.doc.company);
+
+ if(this.frm.doc.company) {
+ erpnext.last_selected_company = this.frm.doc.company;
+ }
},
transaction_date: function() {
@@ -211,7 +214,8 @@
this.set_dynamic_labels();
var company_currency = this.get_company_currency();
- if(this.frm.doc.currency !== company_currency) {
+ // Added `ignore_pricing_rule` to determine if document is loading after mapping from another doc
+ if(this.frm.doc.currency !== company_currency && !this.frm.doc.ignore_pricing_rule) {
this.get_exchange_rate(this.frm.doc.currency, company_currency,
function(exchange_rate) {
me.frm.set_value("conversion_rate", exchange_rate);
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 111ad6d..355fe7d 100644
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -41,6 +41,8 @@
if(companies.length === 1) {
if(!cur_frm.doc.company) cur_frm.set_value("company", companies[0]);
cur_frm.toggle_display("company", false);
+ } else if(erpnext.last_selected_company) {
+ if(!cur_frm.doc.company) cur_frm.set_value("company", erpnext.last_selected_company);
}
}
},
@@ -76,8 +78,8 @@
"options": "Serial No",
"label": __("Serial No"),
"get_query": function () {
- return {
- filters: {
+ return {
+ filters: {
item_code:grid_row.doc.item_code ,
warehouse:grid_row.doc.warehouse
}
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index b87d7c0..d83628d 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -93,7 +93,7 @@
filters: {
'account_type': 'Receivable',
'company': d.company,
- 'group_or_ledger': 'Ledger'
+ "is_group": 0
}
}
}
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 7e722fc..2d0f850 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -161,7 +161,7 @@
# If not authorized person raise exception
credit_controller = frappe.db.get_value('Accounts Settings', None, 'credit_controller')
- if not credit_controller or credit_controller not in frappe.user.get_roles():
+ if not credit_controller or credit_controller not in frappe.get_roles():
throw(_("Please contact to the user who have Sales Master Manager {0} role")
.format(" / " + credit_controller if credit_controller else ""))
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index e627824..553064c 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -595,6 +595,7 @@
"fieldname": "advance_paid",
"fieldtype": "Currency",
"label": "Advance Paid",
+ "no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 1,
@@ -1079,7 +1080,7 @@
"idx": 1,
"is_submittable": 1,
"issingle": 0,
- "modified": "2015-03-23 14:46:09.478285",
+ "modified": "2015-04-28 15:27:40.852414",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 9525fa5..398e1e1 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -51,7 +51,7 @@
d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
unique_chk_list = set(check_list)
if len(unique_chk_list) != len(check_list):
- frappe.msgprint(_("Warning:Same item has been entered multiple times."))
+ frappe.msgprint(_("Warning: Same item has been entered multiple times."))
def validate_sales_mntc_quotation(self):
for d in self.get('items'):
diff --git a/erpnext/setup/doctype/authorization_control/authorization_control.py b/erpnext/setup/doctype/authorization_control/authorization_control.py
index 5d937ac..f1c198c 100644
--- a/erpnext/setup/doctype/authorization_control/authorization_control.py
+++ b/erpnext/setup/doctype/authorization_control/authorization_control.py
@@ -32,7 +32,7 @@
if(d[0]): appr_users.append(d[0])
if(d[1]): appr_roles.append(d[1])
- if not has_common(appr_roles, frappe.user.get_roles()) and not has_common(appr_users, [session['user']]):
+ if not has_common(appr_roles, frappe.get_roles()) and not has_common(appr_users, [session['user']]):
frappe.msgprint(_("Not authroized since {0} exceeds limits").format(_(based_on)))
frappe.throw(_("Can be approved by {0}").format(comma_or(appr_roles + appr_users)))
@@ -77,7 +77,7 @@
auth_value = av_dis
if val == 1: add_cond += " and system_user = '"+session['user'].replace("'", "\\'")+"'"
- elif val == 2: add_cond += " and system_role IN %s" % ("('"+"','".join(frappe.user.get_roles())+"')")
+ elif val == 2: add_cond += " and system_role IN %s" % ("('"+"','".join(frappe.get_roles())+"')")
else: add_cond += " and ifnull(system_user,'') = '' and ifnull(system_role,'') = ''"
if based_on == 'Grand Total': auth_value = total
@@ -130,7 +130,7 @@
where transaction = %s and system_role IN (%s) and based_on IN (%s)
and (company = %s or ifnull(company,'')='')
and docstatus != 2
- """ % ('%s', "'"+"','".join(frappe.user.get_roles())+"'", "'"+"','".join(final_based_on)+"'", '%s'), (doctype_name, company))]
+ """ % ('%s', "'"+"','".join(frappe.get_roles())+"'", "'"+"','".join(final_based_on)+"'", '%s'), (doctype_name, company))]
for d in based_on:
self.bifurcate_based_on_type(doctype_name, total, av_dis, d, doc_obj, 2, company)
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 5ff256d..817fdb6 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -5,37 +5,35 @@
frappe.ui.form.on("Company", {
onload_post_render: function(frm) {
- frm.get_field("delete_company").$input.addClass("btn-danger");
+ frm.get_field("delete_company_transactions").$input.addClass("btn-danger");
},
country: function(frm) {
erpnext.company.set_chart_of_accounts_options(frm.doc);
},
- delete_company: function(frm) {
+ delete_company_transactions: function(frm) {
var d = frappe.prompt({
fieldtype:"Data",
fieldname: "company_name",
label: __("Please re-type company name to confirm"),
reqd: 1,
- description: __("Please make sure you really want to delete this company and all its transactions. Your master data will remain as it is. This action cannot be undone.")},
+ description: __("Please make sure you really want to delete all the transactions for this company. Your master data will remain as it is. This action cannot be undone.")},
function(data) {
if(data.company_name !== frm.doc.name) {
frappe.msgprint("Company name not same");
return;
}
frappe.call({
- method: "erpnext.setup.doctype.company.delete_company.delete_company",
+ method: "erpnext.setup.doctype.company.delete_company_transactions.delete_company_transactions",
args: {
company_name: data.company_name
},
freeze: true,
- callback: function(r) {
- if(!r.exc) {
- frappe.model.clear_doc("Company", data.company_name);
- window.history.back();
- }
+ callback: function(r, rt) {
+ if(!r.exc)
+ frappe.msgprint(__("Successfully deleted all transactions related to this company!"));
}
});
- }, __("Delete Comany and all Related Transactions"), __("Delete"));
+ }, __("Delete all the Transactions for this Company"), __("Delete"));
d.get_primary_btn().addClass("btn-danger");
}
@@ -114,7 +112,7 @@
return{
filters: [
['Account', 'account_type', '=', 'Bank'],
- ['Account', 'group_or_ledger', '=', 'Ledger'],
+ ['Account', 'is_group', '=', 0],
['Account', 'company', '=', doc.name]
]
}
@@ -124,7 +122,7 @@
return{
filters: [
['Account', 'account_type', '=', 'Cash'],
- ['Account', 'group_or_ledger', '=', 'Ledger'],
+ ['Account', 'is_group', '=', 0],
['Account', 'company', '=', doc.name]
]
}
@@ -134,7 +132,7 @@
return{
filters:{
'company': doc.name,
- 'group_or_ledger': "Ledger",
+ "is_group": 0,
"account_type": "Receivable"
}
}
@@ -144,7 +142,7 @@
return{
filters:{
'company': doc.name,
- 'group_or_ledger': "Ledger",
+ "is_group": 0,
"account_type": "Payable"
}
}
@@ -156,7 +154,7 @@
return{
filters:{
'company': doc.name,
- 'group_or_ledger': "Ledger",
+ "is_group": 0,
"report_type": "Profit and Loss"
}
}
@@ -166,7 +164,7 @@
return{
filters:{
'company': doc.name,
- 'group_or_ledger': "Ledger",
+ "is_group": 0,
"report_type": "Profit and Loss"
}
}
@@ -176,7 +174,7 @@
return{
filters:{
'company': doc.name,
- 'group_or_ledger': "Ledger",
+ "is_group": 0,
}
}
}
@@ -187,7 +185,7 @@
"filters": {
"report_type": "Profit and Loss",
"company": doc.name,
- 'group_or_ledger': "Ledger"
+ "is_group": 0
}
}
}
@@ -200,7 +198,7 @@
"filters": {
"report_type": "Balance Sheet",
"company": doc.name,
- 'group_or_ledger': "Ledger"
+ "is_group": 0
}
}
}
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index f7faf96..0e7b17a 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -397,16 +397,16 @@
"read_only": 0
},
{
- "fieldname": "delete_company",
+ "fieldname": "delete_company_transactions",
"fieldtype": "Button",
- "label": "Delete Company",
+ "label": "Delete Company Transactions",
"permlevel": 0,
"precision": ""
}
],
"icon": "icon-building",
"idx": 1,
- "modified": "2015-04-17 01:37:32.304374",
+ "modified": "2015-05-04 11:22:42.116328",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index a89fc51..ad89114 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -55,7 +55,7 @@
self.create_default_warehouses()
self.install_country_fixtures()
- if not frappe.db.get_value("Cost Center", {"group_or_ledger": "Ledger", "company": self.name}):
+ if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
self.create_default_cost_center()
self.set_default_accounts()
@@ -71,7 +71,7 @@
for whname in (_("Stores"), _("Work In Progress"), _("Finished Goods")):
if not frappe.db.exists("Warehouse", whname + " - " + self.abbr):
stock_group = frappe.db.get_value("Account", {"account_type": "Stock",
- "group_or_ledger": "Group", "company": self.name})
+ "is_group": 1, "company": self.name})
if stock_group:
frappe.get_doc({
"doctype":"Warehouse",
@@ -125,7 +125,7 @@
return
account = frappe.db.get_value("Account", {"account_type": account_type,
- "group_or_ledger": "Ledger", "company": self.name})
+ "is_group": 0, "company": self.name})
if account:
self.db_set(fieldname, account)
@@ -135,13 +135,13 @@
{
'cost_center_name': self.name,
'company':self.name,
- 'group_or_ledger':'Group',
+ 'is_group': 1,
'parent_cost_center':None
},
{
'cost_center_name':_('Main'),
'company':self.name,
- 'group_or_ledger':'Ledger',
+ 'is_group':0,
'parent_cost_center':self.name + ' - ' + self.abbr
},
]
@@ -167,6 +167,33 @@
where defkey='Company' and defvalue=%s""", (newdn, olddn))
frappe.defaults.clear_cache()
+
+ def on_trash(self):
+ """
+ Trash accounts and cost centers for this company if no gl entry exists
+ """
+ rec = frappe.db.sql("SELECT name from `tabGL Entry` where company = %s", self.name)
+ if not rec:
+ # delete Account
+ frappe.db.sql("delete from `tabAccount` where company = %s", self.name)
+
+ # delete cost center child table - budget detail
+ frappe.db.sql("""delete bd.* from `tabBudget Detail` bd, `tabCost Center` cc
+ where bd.parent = cc.name and cc.company = %s""", self.name)
+ #delete cost center
+ frappe.db.sql("delete from `tabCost Center` WHERE company = %s", self.name)
+
+ # delete account from customer and supplier
+ frappe.db.sql("delete from `tabParty Account` where company=%s", self.name)
+
+ if not frappe.db.get_value("Stock Ledger Entry", {"company": self.name}):
+ frappe.db.sql("""delete from `tabWarehouse` where company=%s""", self.name)
+
+ frappe.defaults.clear_default("company", value=self.name)
+
+ frappe.db.sql("""update `tabSingles` set value=""
+ where doctype='Global Defaults' and field='default_company'
+ and value=%s""", self.name)
@frappe.whitelist()
def replace_abbr(company, old, new):
diff --git a/erpnext/setup/doctype/company/delete_company.py b/erpnext/setup/doctype/company/delete_company_transactions.py
similarity index 82%
rename from erpnext/setup/doctype/company/delete_company.py
rename to erpnext/setup/doctype/company/delete_company_transactions.py
index 92b6c52..f27ba86 100644
--- a/erpnext/setup/doctype/company/delete_company.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -8,26 +8,19 @@
from frappe import _
@frappe.whitelist()
-def delete_company(company_name):
+def delete_company_transactions(company_name):
frappe.only_for("System Manager")
doc = frappe.get_doc("Company", company_name)
if frappe.session.user != doc.owner:
- frappe.throw(_("Company can only be deleted by the creator"), frappe.PermissionError)
+ frappe.throw(_("Transactions can only be deleted by the creator of the Company"), frappe.PermissionError)
delete_bins(company_name)
for doctype in frappe.db.sql_list("""select parent from
tabDocField where fieldtype='Link' and options='Company'"""):
- delete_for_doctype(doctype, company_name)
-
- frappe.delete_doc("Company", company_name)
-
- frappe.defaults.clear_default("company", value=doc.name)
-
- frappe.db.sql("""update `tabSingles` set value=""
- where doctype='Global Defaults' and field='default_company'
- and value=%s""", doc.name)
+ if doctype not in ("Account", "Cost Center", "Warehouse", "Budget Detail", "Party Account"):
+ delete_for_doctype(doctype, company_name)
def delete_for_doctype(doctype, company_name):
meta = frappe.get_meta(doctype)
diff --git a/erpnext/setup/doctype/customer_group/customer_group.js b/erpnext/setup/doctype/customer_group/customer_group.js
index 8e31119..7a5d2fa 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.js
+++ b/erpnext/setup/doctype/customer_group/customer_group.js
@@ -32,7 +32,7 @@
filters: {
'account_type': 'Receivable',
'company': d.company,
- 'group_or_ledger': 'Ledger'
+ "is_group": 0
}
}
}
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 15a3781..87a1043 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -394,7 +394,7 @@
if not hasattr(self, "accounts"):
self.accounts = frappe.db.sql("""select name, account_type, account_name, root_type
from `tabAccount` where company=%s and docstatus < 2
- and group_or_ledger = "Ledger" order by lft""",
+ and is_group = 0 order by lft""",
(self.company,), as_dict=1)
return self.accounts
diff --git a/erpnext/setup/doctype/supplier_type/supplier_type.js b/erpnext/setup/doctype/supplier_type/supplier_type.js
index 7b2464b..f1c5d70 100644
--- a/erpnext/setup/doctype/supplier_type/supplier_type.js
+++ b/erpnext/setup/doctype/supplier_type/supplier_type.js
@@ -11,7 +11,7 @@
filters: {
'account_type': 'Payable',
'company': d.company,
- 'group_or_ledger': 'Ledger'
+ "is_group": 0
}
}
}
diff --git a/erpnext/setup/page/setup_wizard/setup_wizard.py b/erpnext/setup/page/setup_wizard/setup_wizard.py
index 7fd3542..b80d55e 100644
--- a/erpnext/setup/page/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/page/setup_wizard/setup_wizard.py
@@ -297,14 +297,14 @@
try:
tax_group = frappe.db.get_value("Account", {"company": args.get("company_name"),
- "group_or_ledger": "Group", "account_type": "Tax", "root_type": "Liability"})
+ "is_group": 1, "account_type": "Tax", "root_type": "Liability"})
if tax_group:
frappe.get_doc({
"doctype":"Account",
"company": args.get("company_name").strip(),
"parent_account": tax_group,
"account_name": args.get("tax_" + str(i)),
- "group_or_ledger": "Ledger",
+ "is_group": 0,
"report_type": "Balance Sheet",
"account_type": "Tax",
"tax_rate": flt(tax_rate) if tax_rate else None
@@ -330,69 +330,78 @@
"company": args.get("company_name").strip()
})
- frappe.get_doc({
- "doctype":"Item",
- "item_code": item,
- "item_name": item,
- "description": item,
- "is_sales_item": "Yes" if is_sales_item else "No",
- "is_purchase_item": "Yes" if is_purchase_item else "No",
- "show_in_website": 1,
- "is_stock_item": is_stock_item and "Yes" or "No",
- "item_group": item_group,
- "stock_uom": args.get("item_uom_" + str(i)),
- "default_warehouse": default_warehouse
- }).insert()
+ try:
+ frappe.get_doc({
+ "doctype":"Item",
+ "item_code": item,
+ "item_name": item,
+ "description": item,
+ "is_sales_item": "Yes" if is_sales_item else "No",
+ "is_purchase_item": "Yes" if is_purchase_item else "No",
+ "show_in_website": 1,
+ "is_stock_item": is_stock_item and "Yes" or "No",
+ "item_group": item_group,
+ "stock_uom": args.get("item_uom_" + str(i)),
+ "default_warehouse": default_warehouse
+ }).insert()
- if args.get("item_img_" + str(i)):
- item_image = args.get("item_img_" + str(i)).split(",")
- if len(item_image)==3:
- filename, filetype, content = item_image
- fileurl = save_file(filename, content, "Item", item, decode=True).file_url
- frappe.db.set_value("Item", item, "image", fileurl)
+ if args.get("item_img_" + str(i)):
+ item_image = args.get("item_img_" + str(i)).split(",")
+ if len(item_image)==3:
+ filename, filetype, content = item_image
+ fileurl = save_file(filename, content, "Item", item, decode=True).file_url
+ frappe.db.set_value("Item", item, "image", fileurl)
+ except frappe.NameError:
+ pass
def create_customers(args):
for i in xrange(1,6):
customer = args.get("customer_" + str(i))
if customer:
- frappe.get_doc({
- "doctype":"Customer",
- "customer_name": customer,
- "customer_type": "Company",
- "customer_group": _("Commercial"),
- "territory": args.get("country"),
- "company": args.get("company_name").strip()
- }).insert()
-
- if args.get("customer_contact_" + str(i)):
- contact = args.get("customer_contact_" + str(i)).split(" ")
+ try:
frappe.get_doc({
- "doctype":"Contact",
- "customer": customer,
- "first_name":contact[0],
- "last_name": len(contact) > 1 and contact[1] or ""
+ "doctype":"Customer",
+ "customer_name": customer,
+ "customer_type": "Company",
+ "customer_group": _("Commercial"),
+ "territory": args.get("country"),
+ "company": args.get("company_name").strip()
}).insert()
+ if args.get("customer_contact_" + str(i)):
+ contact = args.get("customer_contact_" + str(i)).split(" ")
+ frappe.get_doc({
+ "doctype":"Contact",
+ "customer": customer,
+ "first_name":contact[0],
+ "last_name": len(contact) > 1 and contact[1] or ""
+ }).insert()
+ except frappe.NameError:
+ pass
+
def create_suppliers(args):
for i in xrange(1,6):
supplier = args.get("supplier_" + str(i))
if supplier:
- frappe.get_doc({
- "doctype":"Supplier",
- "supplier_name": supplier,
- "supplier_type": _("Local"),
- "company": args.get("company_name").strip()
- }).insert()
-
- if args.get("supplier_contact_" + str(i)):
- contact = args.get("supplier_contact_" + str(i)).split(" ")
+ try:
frappe.get_doc({
- "doctype":"Contact",
- "supplier": supplier,
- "first_name":contact[0],
- "last_name": len(contact) > 1 and contact[1] or ""
+ "doctype":"Supplier",
+ "supplier_name": supplier,
+ "supplier_type": _("Local"),
+ "company": args.get("company_name").strip()
}).insert()
+ if args.get("supplier_contact_" + str(i)):
+ contact = args.get("supplier_contact_" + str(i)).split(" ")
+ frappe.get_doc({
+ "doctype":"Contact",
+ "supplier": supplier,
+ "first_name":contact[0],
+ "last_name": len(contact) > 1 and contact[1] or ""
+ }).insert()
+ except frappe.NameError:
+ pass
+
def create_letter_head(args):
if args.get("attach_letterhead"):
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index b4ae5ef..e3a034c 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -7,7 +7,7 @@
from frappe.utils import flt
def get_company_currency(company):
- currency = frappe.db.get_value("Company", company, "default_currency")
+ currency = frappe.db.get_value("Company", company, "default_currency", cache=True)
if not currency:
currency = frappe.db.get_default("currency")
if not currency:
diff --git a/erpnext/startup/report_data_map.py b/erpnext/startup/report_data_map.py
index 813090f..b8653cd 100644
--- a/erpnext/startup/report_data_map.py
+++ b/erpnext/startup/report_data_map.py
@@ -19,7 +19,7 @@
# Accounts
"Account": {
"columns": ["name", "parent_account", "lft", "rgt", "report_type",
- "company", "group_or_ledger"],
+ "company", "is_group"],
"conditions": ["docstatus < 2"],
"order_by": "lft",
"links": {
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 00916c2..631009f 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -214,7 +214,7 @@
filters: {
"report_type": "Profit and Loss",
"company": doc.company,
- "group_or_ledger": "Ledger"
+ "is_group": 0
}
}
}
@@ -236,7 +236,7 @@
filters: {
'company': doc.company,
- 'group_or_ledger': "Ledger"
+ "is_group": 0
}
}
}
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index 473e9ad..e045eb9 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -1070,7 +1070,7 @@
"idx": 1,
"in_create": 0,
"is_submittable": 1,
- "modified": "2015-04-07 00:12:12.119039",
+ "modified": "2015-04-24 00:12:12.119039",
"modified_by": "Administrator",
"module": "Stock",
"name": "Delivery Note",
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 24851dd..55d6d33 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -122,7 +122,7 @@
return {
filters: {
"report_type": "Profit and Loss",
- "group_or_ledger": "Ledger"
+ "is_group": 0
}
}
}
@@ -133,7 +133,7 @@
return {
filters: {
"report_type": "Profit and Loss",
- 'group_or_ledger': "Ledger",
+ "is_group": 0,
'account_type': "Income Account"
}
}
@@ -144,7 +144,7 @@
// -----------------------------
frm.fields_dict['buying_cost_center'].get_query = function(doc) {
return {
- filters:{ 'group_or_ledger': "Ledger" }
+ filters:{ "is_group": 0 }
}
}
@@ -153,7 +153,7 @@
// -----------------------------
frm.fields_dict['selling_cost_center'].get_query = function(doc) {
return {
- filters:{ 'group_or_ledger': "Ledger" }
+ filters:{ "is_group": 0 }
}
}
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index b34983d..282d182 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -428,6 +428,7 @@
"reqd": 1
},
{
+ "depends_on": "eval:doc.is_purchase_item==\"Yes\"",
"fieldname": "default_supplier",
"fieldtype": "Link",
"ignore_user_permissions": 1,
@@ -448,7 +449,7 @@
"read_only": 0
},
{
- "depends_on": "eval:doc.is_purchase_item==\"Yes\"",
+ "depends_on": "",
"description": "Default Purchase Account in which cost of the item will be debited.",
"fieldname": "expense_account",
"fieldtype": "Link",
@@ -461,7 +462,7 @@
"read_only": 0
},
{
- "depends_on": "eval:doc.is_purchase_item==\"Yes\"",
+ "depends_on": "",
"description": "",
"fieldname": "buying_cost_center",
"fieldtype": "Link",
@@ -877,7 +878,7 @@
"icon": "icon-tag",
"idx": 1,
"max_attachments": 1,
- "modified": "2015-03-03 06:18:35.717586",
+ "modified": "2015-05-04 18:44:46.090445",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
diff --git a/erpnext/stock/doctype/item/item_list.js b/erpnext/stock/doctype/item/item_list.js
index 168252e..c6beeff 100644
--- a/erpnext/stock/doctype/item/item_list.js
+++ b/erpnext/stock/doctype/item/item_list.js
@@ -3,7 +3,7 @@
"has_variants", "end_of_life", "is_sales_item"],
get_indicator: function(doc) {
- if(doc.end_of_life < frappe.datetime.get_today()) {
+ if(doc.end_of_life && doc.end_of_life < frappe.datetime.get_today()) {
return [__("Expired"), "grey", "end_of_life,<,Today"]
} else if(doc.has_variants) {
return [__("Template"), "blue", "has_variant,=,1"]
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index c7c7aaa..6bb2e2f 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -51,7 +51,7 @@
return {
filters: {
"company": me.frm.doc.company,
- "group_or_ledger": "Ledger"
+ "is_group": 0
}
}
}
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index 1b3dc06..97e7c20 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -82,14 +82,14 @@
stock_frozen_upto = frappe.db.get_value('Stock Settings', None, 'stock_frozen_upto') or ''
if stock_frozen_upto:
stock_auth_role = frappe.db.get_value('Stock Settings', None,'stock_auth_role')
- if getdate(self.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in frappe.user.get_roles():
+ if getdate(self.posting_date) <= getdate(stock_frozen_upto) and not stock_auth_role in frappe.get_roles():
frappe.throw(_("Stock transactions before {0} are frozen").format(formatdate(stock_frozen_upto)), StockFreezeError)
stock_frozen_upto_days = int(frappe.db.get_value('Stock Settings', None, 'stock_frozen_upto_days') or 0)
if stock_frozen_upto_days:
stock_auth_role = frappe.db.get_value('Stock Settings', None,'stock_auth_role')
older_than_x_days_ago = (add_days(getdate(self.posting_date), stock_frozen_upto_days) <= date.today())
- if older_than_x_days_ago and not stock_auth_role in frappe.user.get_roles():
+ if older_than_x_days_ago and not stock_auth_role in frappe.get_roles():
frappe.throw(_("Not allowed to update stock transactions older than {0}").format(stock_frozen_upto_days), StockFreezeError)
def scrub_posting_time(self):
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index 67eb882..c0ae213 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -65,7 +65,7 @@
return {
"filters": {
'company': me.frm.doc.company,
- 'group_or_ledger': 'Ledger'
+ "is_group": 0
}
}
}
@@ -73,7 +73,7 @@
return {
"filters": {
'company': me.frm.doc.company,
- 'group_or_ledger': 'Ledger'
+ "is_group": 0
}
}
}
diff --git a/erpnext/stock/doctype/warehouse/warehouse.js b/erpnext/stock/doctype/warehouse/warehouse.js
index 27b63b5..22396b7 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.js
+++ b/erpnext/stock/doctype/warehouse/warehouse.js
@@ -9,7 +9,7 @@
return {
filters: {
"company": cur_frm.doc.company,
- 'group_or_ledger': "Group"
+ 'is_group': 1
}
}
})
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index 1643f93..2024ebe 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -48,7 +48,7 @@
"doctype": "Account",
'account_name': self.warehouse_name,
'parent_account': self.create_account_under,
- 'group_or_ledger':'Ledger',
+ 'is_group':0,
'company':self.company,
"account_type": "Warehouse",
"warehouse": self.name,
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index 1922d8a..0395987 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -8,20 +8,21 @@
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)
+ 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,
- qty_dict.opening_qty, qty_dict.in_qty,
- qty_dict.out_qty, qty_dict.bal_qty
+ data.append([item, item_map[item]["item_name"], item_map[item]["description"], wh, batch,
+ flt(qty_dict.opening_qty, float_precision), flt(qty_dict.in_qty, float_precision),
+ flt(qty_dict.out_qty, float_precision), flt(qty_dict.bal_qty, float_precision)
])
return columns, data
@@ -56,8 +57,7 @@
where docstatus < 2 %s order by item_code, warehouse""" %
conditions, as_dict=1)
-def get_item_warehouse_batch_map(filters):
- float_precision = cint(frappe.db.get_default("float_precision")) or 3
+def get_item_warehouse_batch_map(filters, float_precision):
sle = get_stock_ledger_entries(filters)
iwb_map = {}
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 5bb2f0c..954a03b 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -98,7 +98,7 @@
self.company = frappe.db.get_value("Warehouse", self.warehouse, "company")
self.precision = get_field_precision(frappe.get_meta("Stock Ledger Entry").get_field("stock_value"),
- currency=frappe.db.get_value("Company", self.company, "default_currency"))
+ currency=frappe.db.get_value("Company", self.company, "default_currency", cache=True))
self.prev_stock_value = self.previous_sle.stock_value or 0.0
self.stock_queue = json.loads(self.previous_sle.stock_queue or "[]")
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index dc6809f..0ab03cb 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -10,14 +10,12 @@
from frappe.utils import now
from frappe.utils.user import is_website_user
+sender_field = "raised_by"
+
class Issue(Document):
def get_feed(self):
return "{0}: {1}".format(_(self.status), self.subject)
- def set_sender(self, sender):
- """Will be called by **Communication** when the Issue is created from an incoming email."""
- self.raised_by = sender
-
def validate(self):
self.update_status()
self.set_lead_contact(self.raised_by)
@@ -59,7 +57,7 @@
from frappe.templates.pages.list import get_list
user = frappe.session.user
ignore_permissions = False
- if is_website_user(user):
+ if is_website_user():
if not filters: filters = []
filters.append(("Issue", "raised_by", "=", user))
ignore_permissions = True
diff --git a/erpnext/templates/pages/address.html b/erpnext/templates/pages/address.html
index 0e221ac..8544604 100644
--- a/erpnext/templates/pages/address.html
+++ b/erpnext/templates/pages/address.html
@@ -40,8 +40,8 @@
<div class="container content">
<ul class="breadcrumb">
- <li><a href="index">Home</a></li>
- <li><a href="addresses">My Addresses</a></li>
+ <li><a href="/index">Home</a></li>
+ <li><a href="/addresses">My Addresses</a></li>
<li class="active"><i class="icon-map-marker icon-fixed-width"></i> {{ title }}</li>
</ul>
<h3><i class="icon-map-marker icon-fixed-width"></i> {{ title }}</h3>
diff --git a/erpnext/templates/pages/addresses.html b/erpnext/templates/pages/addresses.html
index 997143a..a0562c6 100644
--- a/erpnext/templates/pages/addresses.html
+++ b/erpnext/templates/pages/addresses.html
@@ -6,7 +6,7 @@
{% block content %}
<div class="addresses-content">
- <p><a class="btn btn-default" href="address"><i class="icon-plus"> New Address</i></a></p>
+ <p><a class="btn btn-default" href="/address"><i class="icon-plus"> New Address</i></a></p>
<hr>
<div id="address-list">
<div class="text-muted progress">{{ _("Loading") }}...</div>
@@ -30,7 +30,7 @@
$.each(r.message, function(i, address) {
address.url_name = encodeURIComponent(address.name);
$(repl('<div> \
- <p><a href="address?name=%(url_name)s">%(name)s</a></p> \
+ <p><a href="/address?name=%(url_name)s">%(name)s</a></p> \
<p>%(display)s</p> \
<hr> \
</div>', address)).appendTo($list);
diff --git a/erpnext/templates/pages/ticket.html b/erpnext/templates/pages/ticket.html
index cff019c..67d4800 100644
--- a/erpnext/templates/pages/ticket.html
+++ b/erpnext/templates/pages/ticket.html
@@ -11,8 +11,8 @@
<div class="ticket-content">
<ul class="breadcrumb">
- <li><a href="index">Home</a></li>
- <li><a href="tickets">My Tickets</a></li>
+ <li><a href="/index">Home</a></li>
+ <li><a href="/tickets">My Tickets</a></li>
<li class="active"><i class="icon-ticket icon-fixed-width"></i> {{ doc.name or "" }}</li>
</ul>
{% if not doc -%}
diff --git a/erpnext/templates/pages/user.html b/erpnext/templates/pages/user.html
index 1d1d0b3..e9f356d 100644
--- a/erpnext/templates/pages/user.html
+++ b/erpnext/templates/pages/user.html
@@ -5,7 +5,7 @@
{% block content %}
<div class="user-content" style="max-width: 500px;">
<ul class="breadcrumb">
- <li><a href="index">Home</a></li>
+ <li><a href="/index">Home</a></li>
<li class="active"><i class="icon-user icon-fixed-width"></i> My Profile</li>
</ul>
<div class="alert alert-warning" id="message" style="display: none;"></div>
diff --git a/setup.py b/setup.py
index 8011b75..8ac87b9 100644
--- a/setup.py
+++ b/setup.py
@@ -1,10 +1,6 @@
from setuptools import setup, find_packages
-<<<<<<< HEAD
version = "5.0.0-beta"
-=======
-version = "4.25.1"
->>>>>>> 3b8682f534f12bd72e52685d1286a2cc72713857
with open("requirements.txt", "r") as f:
install_requires = f.readlines()