Merge branch 'sla_fix' of https://github.com/hrwx/erpnext into sla_fix
diff --git a/.travis.yml b/.travis.yml
index 869fe95..a8a0d82 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,11 @@
python:
- "2.7"
+ - "3.6"
+
+env:
+ - TEST_TYPE="Server Side Test"
+ - TEST_TYPE="Patch Test"
services:
- mysql
@@ -39,18 +44,8 @@
- bench start &
- sleep 10
-jobs:
- include:
- - stage: test
- script:
- - set -e
- - bench run-tests --app erpnext --coverage
- after_script:
- - coveralls -b apps/erpnext -d ../../sites/.coverage
- env: Server Side Test
- - # stage
- script:
- - wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
- - bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
- - bench migrate
- env: Patch Testing
+script:
+ - bash $TRAVIS_BUILD_DIR/travis/run-tests.sh
+
+after_script:
+ - coveralls -b apps/erpnext -d ../../sites/.coverage
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 8a8e329..5795b8f 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -232,7 +232,7 @@
if len(pricing_rules) > 1:
rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
- pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) \
+ pricing_rules = list(filter(lambda x: x.for_price_list==args.price_list, pricing_rules)) \
or pricing_rules
if len(pricing_rules) > 1 and not args.for_shopping_cart:
diff --git a/erpnext/demo/user/hr.py b/erpnext/demo/user/hr.py
index 79f3c19..0211bc8 100644
--- a/erpnext/demo/user/hr.py
+++ b/erpnext/demo/user/hr.py
@@ -97,7 +97,7 @@
"expense_date": frappe.flags.current_date,
"expense_type": expense_type.name,
"default_account": expense_type.default_account or "Miscellaneous Expenses - WPL",
- "claim_amount": claim_amount,
+ "amount": claim_amount,
"sanctioned_amount": claim_amount
})
@@ -107,7 +107,7 @@
for expense in expense_claim.expenses:
sanctioned_amount = random.randint(1,20)*10
- if sanctioned_amount < expense.claim_amount:
+ if sanctioned_amount < expense.amount:
expense.sanctioned_amount = sanctioned_amount
def get_timesheet_based_salary_slip_employee():
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index b272f60..e5dbd12 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -10,6 +10,7 @@
app_email = "info@erpnext.com"
app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext"
+app_logo_url = '/assets/erpnext/images/erp-icon.svg'
develop_version = '12.x.x-develop'
diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
index 376d0c0..22ba5ad 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
+++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.js
@@ -2,9 +2,8 @@
refresh: function(frm) {
frm.disable_save();
},
-
+
onload: function(frm) {
- frm.doc.department = frm.doc.branch = frm.doc.company = "All";
frm.set_value("date", frappe.datetime.get_today());
erpnext.employee_attendance_tool.load_employees(frm);
},
@@ -24,7 +23,7 @@
company: function(frm) {
erpnext.employee_attendance_tool.load_employees(frm);
}
-
+
});
diff --git a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
index ea5f4bd..32fcee1 100644
--- a/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
+++ b/erpnext/hr/doctype/employee_attendance_tool/employee_attendance_tool.py
@@ -17,12 +17,11 @@
attendance_not_marked = []
attendance_marked = []
filters = {"status": "Active", "date_of_joining": ["<=", date]}
- if department != "All":
- filters["department"] = department
- if branch != "All":
- filters["branch"] = branch
- if company != "All":
- filters["company"] = company
+
+ for field, value in {'department': department,
+ 'branch': branch, 'company': company}.items():
+ if value:
+ filters[field] = value
employee_list = frappe.get_list("Employee", fields=["employee", "employee_name"], filters=filters, order_by="employee_name")
marked_employee = {}
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 7c6abc7..40bec6d 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -109,12 +109,9 @@
doc.total_claimed_amount = 0;
doc.total_sanctioned_amount = 0;
$.each((doc.expenses || []), function(i, d) {
- doc.total_claimed_amount += d.claim_amount;
+ doc.total_claimed_amount += d.amount;
doc.total_sanctioned_amount += d.sanctioned_amount;
});
-
- refresh_field("total_claimed_amount");
- refresh_field('total_sanctioned_amount');
};
cur_frm.cscript.calculate_total_amount = function(doc,cdt,cdn){
@@ -157,6 +154,14 @@
}
};
});
+ frm.set_query("account_head", "taxes", function(doc) {
+ return {
+ filters: [
+ ['company', '=', doc.company],
+ ['account_type', 'in', ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation"]]
+ ]
+ };
+ });
},
onload: function(frm) {
@@ -197,6 +202,12 @@
}
},
+ calculate_grand_total: function(frm) {
+ var grand_total = flt(frm.doc.total_sanctioned_amount) + flt(frm.doc.total_taxes_and_charges) - flt(frm.doc.total_advance_amount);
+ frm.set_value("grand_total", grand_total);
+ frm.refresh_fields();
+ },
+
make_payment_entry: function(frm) {
var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
if(frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
@@ -259,6 +270,18 @@
frm.events.get_advances(frm);
},
+ get_taxes: function(frm) {
+ if(frm.doc.taxes) {
+ frappe.call({
+ method: "calculate_taxes",
+ doc: frm.doc,
+ callback: () => {
+ refresh_field("taxes");
+ }
+ });
+ }
+ },
+
get_advances: function(frm) {
frappe.model.clear_table(frm.doc, "advances");
if (frm.doc.employee) {
@@ -288,16 +311,18 @@
});
frappe.ui.form.on("Expense Claim Detail", {
- claim_amount: function(frm, cdt, cdn) {
+ amount: function(frm, cdt, cdn) {
var child = locals[cdt][cdn];
var doc = frm.doc;
- frappe.model.set_value(cdt, cdn, 'sanctioned_amount', child.claim_amount);
+ frappe.model.set_value(cdt, cdn, 'sanctioned_amount', child.amount);
cur_frm.cscript.calculate_total(doc,cdt,cdn);
},
sanctioned_amount: function(frm, cdt, cdn) {
var doc = frm.doc;
cur_frm.cscript.calculate_total(doc,cdt,cdn);
+ frm.trigger("get_taxes");
+ frm.trigger("calculate_grand_total");
}
});
@@ -324,6 +349,7 @@
child.advance_paid = r.message[0].paid_amount;
child.unclaimed_amount = flt(r.message[0].paid_amount) - flt(r.message[0].claimed_amount);
child.allocated_amount = flt(r.message[0].paid_amount) - flt(r.message[0].claimed_amount);
+ frm.trigger('calculate_grand_total');
refresh_field("advances");
}
}
@@ -332,6 +358,43 @@
}
});
+frappe.ui.form.on("Expense Taxes and Charges", {
+ account_head: function(frm, cdt, cdn) {
+ var child = locals[cdt][cdn];
+ if(child.account_head && !child.description) {
+ // set description from account head
+ child.description = child.account_head.split(' - ').slice(0, -1).join(' - ');
+ refresh_field("taxes");
+ }
+ },
+
+ calculate_total_tax: function(frm, cdt, cdn) {
+ var child = locals[cdt][cdn];
+ child.total = flt(frm.doc.total_sanctioned_amount) + flt(child.tax_amount);
+ frm.trigger("calculate_tax_amount", cdt, cdn);
+ },
+
+ calculate_tax_amount: function(frm) {
+ frm.doc.total_taxes_and_charges = 0;
+ (frm.doc.taxes || []).forEach(function(d) {
+ frm.doc.total_taxes_and_charges += d.tax_amount;
+ });
+ frm.trigger("calculate_grand_total");
+ },
+
+ rate: function(frm, cdt, cdn) {
+ var child = locals[cdt][cdn];
+ if(!child.amount) {
+ child.tax_amount = flt(frm.doc.total_sanctioned_amount) * (flt(child.rate)/100);
+ }
+ frm.trigger("calculate_total_tax", cdt, cdn);
+ },
+
+ tax_amount: function(frm, cdt, cdn) {
+ frm.trigger("calculate_total_tax", cdt, cdn);
+ }
+});
+
cur_frm.fields_dict['task'].get_query = function(doc) {
return {
filters:{
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.json b/erpnext/hr/doctype/expense_claim/expense_claim.json
index 6e04644..f0bc268 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.json
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.json
@@ -4,6 +4,7 @@
"creation": "2013-01-10 16:34:14",
"doctype": "DocType",
"document_type": "Setup",
+ "engine": "InnoDB",
"field_order": [
"naming_series",
"employee",
@@ -12,17 +13,24 @@
"column_break_5",
"expense_approver",
"approval_status",
- "total_claimed_amount",
- "total_sanctioned_amount",
"is_paid",
"expense_details",
"expenses",
"sb1",
+ "taxes",
+ "transactions_section",
+ "total_sanctioned_amount",
+ "total_taxes_and_charges",
+ "total_advance_amount",
+ "column_break_17",
+ "grand_total",
+ "total_claimed_amount",
+ "total_amount_reimbursed",
+ "section_break_16",
"posting_date",
"vehicle_log",
"task",
"cb1",
- "total_amount_reimbursed",
"remark",
"title",
"email_id",
@@ -39,8 +47,7 @@
"status",
"amended_from",
"advance_payments",
- "advances",
- "total_advance_amount"
+ "advances"
],
"fields": [
{
@@ -117,7 +124,6 @@
{
"fieldname": "total_sanctioned_amount",
"fieldtype": "Currency",
- "in_list_view": 1,
"label": "Total Sanctioned Amount",
"no_copy": 1,
"oldfieldname": "total_sanctioned_amount",
@@ -315,12 +321,45 @@
{
"fieldname": "dimension_col_break",
"fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "taxes",
+ "fieldtype": "Table",
+ "label": "Expense Taxes and Charges",
+ "options": "Expense Taxes and Charges"
+ },
+ {
+ "fieldname": "section_break_16",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "transactions_section",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Grand Total",
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_17",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_taxes_and_charges",
+ "fieldtype": "Currency",
+ "label": "Total Taxes and Charges",
+ "options": "Company:company:default_currency",
+ "read_only": 1
}
],
"icon": "fa fa-money",
"idx": 1,
"is_submittable": 1,
- "modified": "2019-05-25 22:53:31.682151",
+ "modified": "2019-06-13 18:05:52.530462",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim",
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index d6b0eca..caeb2dd 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -12,6 +12,7 @@
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
from erpnext.controllers.accounts_controller import AccountsController
from frappe.utils.csvutils import getlink
+from erpnext.accounts.utils import get_account_currency
class InvalidExpenseApproverError(frappe.ValidationError): pass
class ExpenseApproverIdentityError(frappe.ValidationError): pass
@@ -29,6 +30,7 @@
self.set_expense_account(validate=True)
self.set_payable_account()
self.set_cost_center()
+ self.calculate_taxes()
self.set_status()
if self.task and not self.project:
self.project = frappe.db.get_value("Task", self.task, "project")
@@ -93,7 +95,7 @@
elif self.project:
frappe.get_doc("Project", self.project).update_project()
- def make_gl_entries(self, cancel = False):
+ def make_gl_entries(self, cancel=False):
if flt(self.total_sanctioned_amount) > 0:
gl_entries = self.get_gl_entries()
make_gl_entries(gl_entries, cancel)
@@ -102,15 +104,13 @@
gl_entry = []
self.validate_account_details()
- payable_amount = flt(self.total_sanctioned_amount) - flt(self.total_advance_amount)
-
# payable entry
- if payable_amount:
+ if self.grand_total:
gl_entry.append(
self.get_gl_dict({
"account": self.payable_account,
- "credit": payable_amount,
- "credit_in_account_currency": payable_amount,
+ "credit": self.grand_total,
+ "credit_in_account_currency": self.grand_total,
"against": ",".join([d.default_account for d in self.expenses]),
"party_type": "Employee",
"party": self.employee,
@@ -144,15 +144,16 @@
"against_voucher": self.name
})
)
+ self.add_tax_gl_entries(gl_entry)
- if self.is_paid and payable_amount:
+ if self.is_paid and self.grand_total:
# payment entry
payment_account = get_bank_cash_account(self.mode_of_payment, self.company).get("account")
gl_entry.append(
self.get_gl_dict({
"account": payment_account,
- "credit": payable_amount,
- "credit_in_account_currency": payable_amount,
+ "credit": self.grand_total,
+ "credit_in_account_currency": self.grand_total,
"against": self.employee
})
)
@@ -163,8 +164,8 @@
"party_type": "Employee",
"party": self.employee,
"against": payment_account,
- "debit": payable_amount,
- "debit_in_account_currency": payable_amount,
+ "debit": self.grand_total,
+ "debit_in_account_currency": self.grand_total,
"against_voucher": self.name,
"against_voucher_type": self.doctype,
})
@@ -172,6 +173,21 @@
return gl_entry
+ def add_tax_gl_entries(self, gl_entries):
+ # tax table gl entries
+ for tax in self.get("taxes"):
+ gl_entries.append(
+ self.get_gl_dict({
+ "account": tax.account_head,
+ "debit": tax.tax_amount,
+ "debit_in_account_currency": tax.tax_amount,
+ "against": self.employee,
+ "cost_center": self.cost_center,
+ "against_voucher_type": self.doctype,
+ "against_voucher": self.name
+ })
+ )
+
def validate_account_details(self):
if not self.cost_center:
frappe.throw(_("Cost center is required to book an expense claim"))
@@ -190,9 +206,20 @@
if self.approval_status == 'Rejected':
d.sanctioned_amount = 0.0
- self.total_claimed_amount += flt(d.claim_amount)
+ self.total_claimed_amount += flt(d.amount)
self.total_sanctioned_amount += flt(d.sanctioned_amount)
+ def calculate_taxes(self):
+ self.total_taxes_and_charges = 0
+ for tax in self.taxes:
+ if tax.rate:
+ tax.tax_amount = flt(self.total_sanctioned_amount) * flt(tax.rate/100)
+
+ tax.total = flt(tax.tax_amount) + flt(self.total_sanctioned_amount)
+ self.total_taxes_and_charges += flt(tax.tax_amount)
+
+ self.grand_total = flt(self.total_sanctioned_amount) + flt(self.total_taxes_and_charges) - flt(self.total_advance_amount)
+
def update_task(self):
task = frappe.get_doc("Task", self.task)
task.update_total_expense_claim()
@@ -224,7 +251,7 @@
def validate_sanctioned_amount(self):
for d in self.get('expenses'):
- if flt(d.sanctioned_amount) > flt(d.claim_amount):
+ if flt(d.sanctioned_amount) > flt(d.amount):
frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
def set_expense_account(self, validate=False):
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.js b/erpnext/hr/doctype/expense_claim/test_expense_claim.js
index 070474e..d0c43d3 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.js
@@ -17,7 +17,7 @@
d.expense_date = '2017-08-01',
d.expense_type = 'Test Expense Type 1',
d.description = 'This is just to test Expense Claim',
- d.claim_amount = 2000,
+ d.amount = 2000,
d.sanctioned_amount=2000,
refresh_field('expenses');
},
diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
index 075bc63..a42209f 100644
--- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py
@@ -6,6 +6,7 @@
import unittest
from frappe.utils import random_string, nowdate
from erpnext.hr.doctype.expense_claim.expense_claim import make_bank_entry
+from erpnext.accounts.doctype.account.test_account import create_account
test_records = frappe.get_test_records('Expense Claim')
test_dependencies = ['Employee']
@@ -26,7 +27,7 @@
task_name = frappe.db.get_value("Task", {"project": "_Test Project 1"})
payable_account = get_payable_account("Wind Power LLC")
- make_expense_claim(payable_account, 300, 200, "Wind Power LLC","Travel Expenses - WP", "_Test Project 1", task_name)
+ make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP", "_Test Project 1", task_name)
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)
@@ -62,7 +63,8 @@
def test_expense_claim_gl_entry(self):
payable_account = get_payable_account("Wind Power LLC")
- expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP")
+ taxes = generate_taxes()
+ expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP", do_not_submit=True, taxes=taxes)
expense_claim.submit()
gl_entries = frappe.db.sql("""select account, debit, credit
@@ -72,7 +74,8 @@
self.assertTrue(gl_entries)
expected_values = dict((d[0], d) for d in [
- [payable_account, 0.0, 200.0],
+ ['CGST - WP',10.0, 0.0],
+ [payable_account, 0.0, 210.0],
["Travel Expenses - WP", 200.0, 0.0]
])
@@ -89,7 +92,7 @@
"payable_account": payable_account,
"approval_status": "Rejected",
"expenses":
- [{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 300, "sanctioned_amount": 200 }]
+ [{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "amount": 300, "sanctioned_amount": 200 }]
})
expense_claim.submit()
@@ -100,22 +103,44 @@
self.assertEquals(len(gl_entry), 0)
def get_payable_account(company):
- return frappe.get_cached_value('Company', company, 'default_payable_account')
+ return frappe.get_cached_value('Company', company, 'default_payable_account')
-def make_expense_claim(payable_account,claim_amount, sanctioned_amount, company, account, project=None, task_name=None):
- expense_claim = frappe.get_doc({
+def generate_taxes():
+ parent_account = frappe.db.get_value('Account',
+ {'company': "Wind Power LLC", 'is_group':1, 'account_type': 'Tax'},
+ 'name')
+ account = create_account(company="Wind Power LLC", account_name="CGST", account_type="Tax", parent_account=parent_account)
+ return {'taxes':[{
+ "account_head": account,
+ "rate": 0,
+ "description": "CGST",
+ "tax_amount": 10,
+ "total": 210
+ }]}
+
+def make_expense_claim(payable_account, amount, sanctioned_amount, company, account, project=None, task_name=None, do_not_submit=False, taxes=None):
+ expense_claim = {
"doctype": "Expense Claim",
"employee": "_T-Employee-00001",
"payable_account": payable_account,
"approval_status": "Approved",
"company": company,
"expenses":
- [{ "expense_type": "Travel", "default_account": account, "claim_amount": claim_amount, "sanctioned_amount": sanctioned_amount }]
- })
+ [{"expense_type": "Travel",
+ "default_account": account,
+ "amount": amount,
+ "sanctioned_amount": sanctioned_amount}]}
+ if taxes:
+ expense_claim.update(taxes)
+
+ expense_claim = frappe.get_doc(expense_claim)
+
if project:
expense_claim.project = project
if task_name:
expense_claim.task = task_name
+ if do_not_submit:
+ return expense_claim
expense_claim.submit()
return expense_claim
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 d4e7057..b23fb6a 100644
--- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
+++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
@@ -253,7 +253,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "claim_amount",
+ "fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -262,7 +262,7 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
- "label": "Claim Amount",
+ "label": "Amount",
"length": 0,
"no_copy": 0,
"oldfieldname": "claim_amount",
@@ -360,7 +360,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2019-02-24 08:41:36.122565",
+ "modified": "2019-06-10 08:41:36.122565",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim Detail",
diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/__init__.py b/erpnext/hr/doctype/expense_taxes_and_charges/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/expense_taxes_and_charges/__init__.py
diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
new file mode 100644
index 0000000..9bf69da
--- /dev/null
+++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
@@ -0,0 +1,105 @@
+{
+ "autoname": "hash",
+ "creation": "2019-06-03 11:42:33.123976",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "account_head",
+ "cost_center",
+ "col_break1",
+ "rate",
+ "description",
+ "section_break_6",
+ "tax_amount",
+ "column_break_8",
+ "total"
+ ],
+ "fields": [
+ {
+ "fieldname": "col_break1",
+ "fieldtype": "Column Break"
+ },
+ {
+ "columns": 2,
+ "fieldname": "account_head",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Account Head",
+ "oldfieldname": "account_head",
+ "oldfieldtype": "Link",
+ "options": "Account",
+ "reqd": 1
+ },
+ {
+ "default": ":Company",
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "label": "Cost Center",
+ "oldfieldname": "cost_center",
+ "oldfieldtype": "Link",
+ "options": "Cost Center"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Small Text",
+ "print_width": "300px",
+ "reqd": 1,
+ "width": "300px"
+ },
+ {
+ "columns": 2,
+ "fetch_from": "account_head.tax_rate",
+ "fetch_if_empty": 1,
+ "fieldname": "rate",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Rate",
+ "oldfieldname": "rate",
+ "oldfieldtype": "Currency"
+ },
+ {
+ "columns": 2,
+ "fieldname": "tax_amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "oldfieldname": "tax_amount",
+ "oldfieldtype": "Currency",
+ "options": "currency"
+ },
+ {
+ "columns": 2,
+ "fieldname": "total",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Total",
+ "oldfieldname": "total",
+ "oldfieldtype": "Currency",
+ "options": "currency",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-06-20 12:01:33.919555",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Expense Taxes and Charges",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "ASC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py
new file mode 100644
index 0000000..4103bef
--- /dev/null
+++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class ExpenseTaxesandCharges(Document):
+ pass
diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.py b/erpnext/hr/doctype/vehicle_log/vehicle_log.py
index ceea493..df63361 100644
--- a/erpnext/hr/doctype/vehicle_log/vehicle_log.py
+++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.py
@@ -18,11 +18,11 @@
if (service_detail.service_item or service_detail.type or service_detail.frequency or service_detail.expense_amount):
if not (service_detail.service_item and service_detail.type and service_detail.frequency and service_detail.expense_amount):
frappe.throw(_("Service Item,Type,frequency and expense amount are required"))
-
+
def on_submit(self):
frappe.db.sql("update `tabVehicle` set last_odometer=%s where license_plate=%s",
(self.odometer, self.license_plate))
-
+
@frappe.whitelist()
def get_make_model(license_plate):
vehicle=frappe.get_doc("Vehicle",license_plate)
@@ -41,7 +41,7 @@
for serdetail in vehicle_log.service_detail:
total_exp_amt = total_exp_amt + serdetail.expense_amount
return total_exp_amt
-
+
vehicle_log = frappe.get_doc("Vehicle Log", docname)
exp_claim = frappe.new_doc("Expense Claim")
exp_claim.employee=vehicle_log.employee
@@ -52,6 +52,6 @@
exp_claim.append("expenses",{
"expense_date":vehicle_log.date,
"description":_("Vehicle Expenses"),
- "claim_amount":total_claim_amt
+ "amount":total_claim_amt
})
return exp_claim.as_dict()
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index 42fce5a..e9ef70c 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -152,7 +152,7 @@
make_bom(item = item, raw_materials = raw_materials)
production_plan = create_production_plan(item_code = 'Production Item CUST')
production_plan.make_material_request()
- material_request = frappe.get_value('Material Request Item', {'production_plan': production_plan.name}, 'parent')
+ material_request = frappe.db.get_value('Material Request Item', {'production_plan': production_plan.name, 'item_code': 'CUST-0987'}, 'parent')
mr = frappe.get_doc('Material Request', material_request)
self.assertTrue(mr.material_request_type, 'Customer Provided')
self.assertTrue(mr.customer, '_Test Customer')
diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js
index 477781b..047922f 100644
--- a/erpnext/public/js/conf.js
+++ b/erpnext/public/js/conf.js
@@ -11,9 +11,6 @@
href="https://discuss.erpnext.com">Feedback</a></p>'
- $('.navbar-home').html('<img class="erpnext-icon" src="'+
- frappe.urllib.get_base_url()+'/assets/erpnext/images/erp-icon.svg" />');
-
$('[data-link="docs"]').attr("href", "https://erpnext.com/docs")
$('[data-link="issues"]').attr("href", "https://github.com/frappe/erpnext/issues")
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index f44fb0c..f4bb64a 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -65,6 +65,9 @@
},
get_dimension_filters: async function() {
+ if (!frappe.model.can_read('Accounting Dimension')) {
+ return [];
+ }
let dimensions = await frappe.db.get_list('Accounting Dimension', {
fields: ['label', 'fieldname', 'document_type'],
filters: {
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 9d8fa2a..3a8149d 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -60,11 +60,8 @@
else:
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv)
- for key, items in items_based_on_rate.items():
- rate = key[0]
- account = key[1]
-
- row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, account, items)
+ for rate, items in items_based_on_rate.items():
+ row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
if self.filters.get("type_of_business") == "CDNR":
row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N")
@@ -103,7 +100,7 @@
for key, value in iteritems(b2cs_output):
self.data.append(value)
- def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, account, items):
+ def get_row_data_for_invoice(self, invoice, invoice_details, tax_rate, items):
row = []
for fieldname in self.invoice_fields:
if self.filters.get("type_of_business") == "CDNR" and fieldname == "invoice_value":
@@ -120,10 +117,8 @@
taxable_value = 0
for item_code, net_amount in self.invoice_items.get(invoice).items():
if item_code in items:
- if self.item_tax_rate.get(invoice) and self.item_tax_rate.get(invoice, {}).get(item_code):
- item_tax_rate = self.item_tax_rate.get(invoice, {}).get(item_code)
- if account in item_tax_rate and tax_rate == item_tax_rate.get(account):
- taxable_value += abs(net_amount)
+ if self.item_tax_rate.get(invoice) and tax_rate in self.item_tax_rate.get(invoice, {}).get(item_code):
+ taxable_value += abs(net_amount)
elif not self.item_tax_rate.get(invoice):
taxable_value += abs(net_amount)
@@ -214,8 +209,9 @@
if d.item_tax_rate:
item_tax_rate = json.loads(d.item_tax_rate)
- if item_tax_rate:
- self.item_tax_rate.setdefault(d.parent, {}).setdefault(d.item_code, item_tax_rate)
+ for account, rate in item_tax_rate.items():
+ tax_rate_dict = self.item_tax_rate.setdefault(d.parent, {}).setdefault(d.item_code, [])
+ tax_rate_dict.append(rate)
def get_items_based_on_tax_rate(self):
self.tax_details = frappe.db.sql("""
@@ -255,7 +251,7 @@
tax_rate *= 2
rate_based_dict = self.items_based_on_tax_rate\
- .setdefault(parent, {}).setdefault((tax_rate, account), [])
+ .setdefault(parent, {}).setdefault(tax_rate, [])
if item_code not in rate_based_dict:
rate_based_dict.append(item_code)
except ValueError:
diff --git a/erpnext/regional/report/gstr_2/gstr_2.py b/erpnext/regional/report/gstr_2/gstr_2.py
index d9cab63..a362269 100644
--- a/erpnext/regional/report/gstr_2/gstr_2.py
+++ b/erpnext/regional/report/gstr_2/gstr_2.py
@@ -43,11 +43,8 @@
self.get_igst_invoices()
for inv, items_based_on_rate in self.items_based_on_tax_rate.items():
invoice_details = self.invoices.get(inv)
- for key, items in items_based_on_rate.items():
- rate = key[0]
- account = key[1]
-
- row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, account, items)
+ for rate, items in items_based_on_rate.items():
+ row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items)
tax_amount = taxable_value * rate / 100
if inv in self.igst_invoices:
row += [tax_amount, 0, 0]
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index fb7a335..b87ad03 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -581,8 +581,8 @@
if item:
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center") \
- or item.get("selling_cost_center") \
- or item_group.get("selling_cost_center")
+ or item.get("buying_cost_center") \
+ or item_group.get("buying_cost_center")
target_doc = get_mapped_doc("Sales Order", source_name, {
"Sales Order": {
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 4869335..1a88473 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -67,8 +67,6 @@
from frappe.model.naming import set_name_by_naming_series
set_name_by_naming_series(self)
self.item_code = self.name
- elif not self.item_code:
- msgprint(_("Item Code is mandatory because Item is not automatically numbered"), raise_exception=1)
self.item_code = strip(self.item_code)
self.name = self.item_code
diff --git a/travis/run-tests.sh b/travis/run-tests.sh
new file mode 100755
index 0000000..7cfd648
--- /dev/null
+++ b/travis/run-tests.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -e
+
+if [[ $TEST_TYPE == 'Server Side Test' ]]; then
+ bench run-tests --app erpnext --coverage
+
+elif [[ $TEST_TYPE == 'Patch Test' ]]; then
+ wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
+ bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
+ bench migrate
+fi