Merge branch 'develop' into tally-migration-feat
This commit is contained in:
commit
c333797d67
@ -1,134 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:account_subtype",
|
||||
"beta": 0,
|
||||
"creation": "2018-10-25 15:46:08.054586",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "account_subtype",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Account Subtype",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-25 15:47:03.841390",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Subtype",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
/* eslint-disable */
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Account Subtype", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Account Subtype
|
||||
() => frappe.tests.make('Account Subtype', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
||||
() => {
|
||||
assert.equal(cur_frm.doc.key, 'value');
|
||||
},
|
||||
() => done()
|
||||
]);
|
||||
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Account Type', {
|
||||
refresh: function() {
|
||||
|
||||
}
|
||||
});
|
@ -1,134 +0,0 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:account_type",
|
||||
"beta": 0,
|
||||
"creation": "2018-10-25 15:45:45.789963",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "account_type",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Account Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-25 15:46:51.042604",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account Type",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestAccountType(unittest.TestCase):
|
||||
pass
|
@ -64,13 +64,13 @@
|
||||
"fieldname": "account_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Account Type",
|
||||
"options": "Account Type"
|
||||
"options": "Bank Account Type"
|
||||
},
|
||||
{
|
||||
"fieldname": "account_subtype",
|
||||
"fieldtype": "Link",
|
||||
"label": "Account Subtype",
|
||||
"options": "Account Subtype"
|
||||
"options": "Bank Account Subtype"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_7",
|
||||
@ -200,7 +200,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-01-30 20:42:26.458316",
|
||||
"modified": "2020-04-06 21:00:45.379804",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Account",
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Account Subtype', {
|
||||
frappe.ui.form.on('Bank Account Subtype', {
|
||||
refresh: function() {
|
||||
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:account_subtype",
|
||||
"beta": 0,
|
||||
"creation": "2018-10-25 15:46:08.054586",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "account_subtype",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Account Subtype",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-25 15:47:03.841390",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Account Subtype",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
}
|
@ -5,5 +5,5 @@
|
||||
from __future__ import unicode_literals
|
||||
from frappe.model.document import Document
|
||||
|
||||
class AccountType(Document):
|
||||
class BankAccountSubtype(Document):
|
||||
pass
|
@ -2,15 +2,15 @@
|
||||
// rename this file from _test_[name] to test_[name] to activate
|
||||
// and remove above this line
|
||||
|
||||
QUnit.test("test: Account Type", function (assert) {
|
||||
QUnit.test("test: Bank Account Subtype", function (assert) {
|
||||
let done = assert.async();
|
||||
|
||||
// number of asserts
|
||||
assert.expect(1);
|
||||
|
||||
frappe.run_serially([
|
||||
// insert a new Account Type
|
||||
() => frappe.tests.make('Account Type', [
|
||||
// insert a new Bank Account Subtype
|
||||
() => frappe.tests.make('Bank Account Subtype', [
|
||||
// values to be set
|
||||
{key: 'value'}
|
||||
]),
|
@ -5,5 +5,5 @@ from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestAccountSubtype(unittest.TestCase):
|
||||
class TestBankAccountSubtype(unittest.TestCase):
|
||||
pass
|
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Bank Account Type', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -0,0 +1,68 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:account_type",
|
||||
"creation": "2018-10-25 15:45:45.789963",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"account_type"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "account_type",
|
||||
"fieldtype": "Data",
|
||||
"label": "Account Type",
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-04-10 21:13:09.137898",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Account Type",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, 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 BankAccountType(Document):
|
||||
pass
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestBankAccountType(unittest.TestCase):
|
||||
pass
|
@ -9,6 +9,7 @@ from frappe.utils import flt, getdate, add_months, get_last_day, fmt_money, nowd
|
||||
from frappe.model.naming import make_autoname
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from frappe.model.document import Document
|
||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
|
||||
|
||||
class BudgetError(frappe.ValidationError): pass
|
||||
class DuplicateBudgetError(frappe.ValidationError): pass
|
||||
@ -98,30 +99,32 @@ def validate_expense_against_budget(args):
|
||||
if not (args.get('account') and args.get('cost_center')) and args.item_code:
|
||||
args.cost_center, args.account = get_item_details(args)
|
||||
|
||||
if not (args.cost_center or args.project) and not args.account:
|
||||
if not args.account:
|
||||
return
|
||||
|
||||
for budget_against in ['project', 'cost_center']:
|
||||
for budget_against in ['project', 'cost_center'] + get_accounting_dimensions():
|
||||
if (args.get(budget_against) and args.account
|
||||
and frappe.db.get_value("Account", {"name": args.account, "root_type": "Expense"})):
|
||||
|
||||
if args.project and budget_against == 'project':
|
||||
condition = "and b.project=%s" % frappe.db.escape(args.project)
|
||||
args.budget_against_field = "Project"
|
||||
doctype = frappe.unscrub(budget_against)
|
||||
|
||||
elif args.cost_center and budget_against == 'cost_center':
|
||||
cc_lft, cc_rgt = frappe.db.get_value("Cost Center", args.cost_center, ["lft", "rgt"])
|
||||
condition = """and exists(select name from `tabCost Center`
|
||||
where lft<=%s and rgt>=%s and name=b.cost_center)""" % (cc_lft, cc_rgt)
|
||||
args.budget_against_field = "Cost Center"
|
||||
if frappe.get_cached_value('DocType', doctype, 'is_tree'):
|
||||
lft, rgt = frappe.db.get_value(doctype, args.get(budget_against), ["lft", "rgt"])
|
||||
condition = """and exists(select name from `tab%s`
|
||||
where lft<=%s and rgt>=%s and name=b.%s)""" % (doctype, lft, rgt, budget_against) #nosec
|
||||
args.is_tree = True
|
||||
else:
|
||||
condition = "and b.%s=%s" % (budget_against, frappe.db.escape(args.get(budget_against)))
|
||||
args.is_tree = False
|
||||
|
||||
args.budget_against = args.get(budget_against)
|
||||
args.budget_against_field = budget_against
|
||||
args.budget_against_doctype = doctype
|
||||
|
||||
budget_records = frappe.db.sql("""
|
||||
select
|
||||
b.{budget_against_field} as budget_against, ba.budget_amount, b.monthly_distribution,
|
||||
ifnull(b.applicable_on_material_request, 0) as for_material_request,
|
||||
ifnull(applicable_on_purchase_order,0) as for_purchase_order,
|
||||
ifnull(applicable_on_purchase_order, 0) as for_purchase_order,
|
||||
ifnull(applicable_on_booking_actual_expenses,0) as for_actual_expenses,
|
||||
b.action_if_annual_budget_exceeded, b.action_if_accumulated_monthly_budget_exceeded,
|
||||
b.action_if_annual_budget_exceeded_on_mr, b.action_if_accumulated_monthly_budget_exceeded_on_mr,
|
||||
@ -132,9 +135,7 @@ def validate_expense_against_budget(args):
|
||||
b.name=ba.parent and b.fiscal_year=%s
|
||||
and ba.account=%s and b.docstatus=1
|
||||
{condition}
|
||||
""".format(condition=condition,
|
||||
budget_against_field=frappe.scrub(args.get("budget_against_field"))),
|
||||
(args.fiscal_year, args.account), as_dict=True)
|
||||
""".format(condition=condition, budget_against_field=budget_against), (args.fiscal_year, args.account), as_dict=True) #nosec
|
||||
|
||||
if budget_records:
|
||||
validate_budget_records(args, budget_records)
|
||||
@ -230,10 +231,10 @@ def get_ordered_amount(args, budget):
|
||||
|
||||
def get_other_condition(args, budget, for_doc):
|
||||
condition = "expense_account = '%s'" % (args.expense_account)
|
||||
budget_against_field = frappe.scrub(args.get("budget_against_field"))
|
||||
budget_against_field = args.get("budget_against_field")
|
||||
|
||||
if budget_against_field and args.get(budget_against_field):
|
||||
condition += " and child.%s = '%s'" %(budget_against_field, args.get(budget_against_field))
|
||||
condition += " and child.%s = '%s'" % (budget_against_field, args.get(budget_against_field))
|
||||
|
||||
if args.get('fiscal_year'):
|
||||
date_field = 'schedule_date' if for_doc == 'Material Request' else 'transaction_date'
|
||||
@ -246,19 +247,30 @@ def get_other_condition(args, budget, for_doc):
|
||||
return condition
|
||||
|
||||
def get_actual_expense(args):
|
||||
if not args.budget_against_doctype:
|
||||
args.budget_against_doctype = frappe.unscrub(args.budget_against_field)
|
||||
|
||||
budget_against_field = args.get('budget_against_field')
|
||||
condition1 = " and gle.posting_date <= %(month_end_date)s" \
|
||||
if args.get("month_end_date") else ""
|
||||
if args.budget_against_field == "Cost Center":
|
||||
lft_rgt = frappe.db.get_value(args.budget_against_field,
|
||||
args.budget_against, ["lft", "rgt"], as_dict=1)
|
||||
|
||||
if args.is_tree:
|
||||
lft_rgt = frappe.db.get_value(args.budget_against_doctype,
|
||||
args.get(budget_against_field), ["lft", "rgt"], as_dict=1)
|
||||
|
||||
args.update(lft_rgt)
|
||||
condition2 = """and exists(select name from `tabCost Center`
|
||||
where lft>=%(lft)s and rgt<=%(rgt)s and name=gle.cost_center)"""
|
||||
|
||||
elif args.budget_against_field == "Project":
|
||||
condition2 = "and exists(select name from `tabProject` where name=gle.project and gle.project = %(budget_against)s)"
|
||||
condition2 = """and exists(select name from `tab{doctype}`
|
||||
where lft>=%(lft)s and rgt<=%(rgt)s
|
||||
and name=gle.{budget_against_field})""".format(doctype=args.budget_against_doctype, #nosec
|
||||
budget_against_field=budget_against_field)
|
||||
else:
|
||||
condition2 = """and exists(select name from `tab{doctype}`
|
||||
where name=gle.{budget_against} and
|
||||
gle.{budget_against} = %({budget_against})s)""".format(doctype=args.budget_against_doctype,
|
||||
budget_against = budget_against_field)
|
||||
|
||||
return flt(frappe.db.sql("""
|
||||
amount = flt(frappe.db.sql("""
|
||||
select sum(gle.debit) - sum(gle.credit)
|
||||
from `tabGL Entry` gle
|
||||
where gle.account=%(account)s
|
||||
@ -267,7 +279,9 @@ def get_actual_expense(args):
|
||||
and gle.company=%(company)s
|
||||
and gle.docstatus=1
|
||||
{condition2}
|
||||
""".format(condition1=condition1, condition2=condition2), (args))[0][0])
|
||||
""".format(condition1=condition1, condition2=condition2), (args))[0][0]) #nosec
|
||||
|
||||
return amount
|
||||
|
||||
def get_accumulated_monthly_budget(monthly_distribution, posting_date, fiscal_year, annual_budget):
|
||||
distribution = {}
|
||||
|
@ -13,7 +13,7 @@ from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journ
|
||||
|
||||
class TestBudget(unittest.TestCase):
|
||||
def test_monthly_budget_crossed_ignore(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
set_total_expense_zero("2013-02-28", "cost_center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
@ -26,7 +26,7 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
|
||||
def test_monthly_budget_crossed_stop1(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
set_total_expense_zero("2013-02-28", "cost_center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
@ -41,7 +41,7 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
|
||||
def test_exception_approver_role(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
set_total_expense_zero("2013-02-28", "cost_center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
@ -114,7 +114,7 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
|
||||
def test_monthly_budget_crossed_stop2(self):
|
||||
set_total_expense_zero("2013-02-28", "Project")
|
||||
set_total_expense_zero("2013-02-28", "project")
|
||||
|
||||
budget = make_budget(budget_against="Project")
|
||||
|
||||
@ -129,7 +129,7 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
|
||||
def test_yearly_budget_crossed_stop1(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
set_total_expense_zero("2013-02-28", "cost_center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
@ -141,7 +141,7 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
|
||||
def test_yearly_budget_crossed_stop2(self):
|
||||
set_total_expense_zero("2013-02-28", "Project")
|
||||
set_total_expense_zero("2013-02-28", "project")
|
||||
|
||||
budget = make_budget(budget_against="Project")
|
||||
|
||||
@ -153,7 +153,7 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
|
||||
def test_monthly_budget_on_cancellation1(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
set_total_expense_zero("2013-02-28", "cost_center")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center")
|
||||
|
||||
@ -177,7 +177,7 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
|
||||
def test_monthly_budget_on_cancellation2(self):
|
||||
set_total_expense_zero("2013-02-28", "Project")
|
||||
set_total_expense_zero("2013-02-28", "project")
|
||||
|
||||
budget = make_budget(budget_against="Project")
|
||||
|
||||
@ -201,8 +201,8 @@ class TestBudget(unittest.TestCase):
|
||||
budget.cancel()
|
||||
|
||||
def test_monthly_budget_against_group_cost_center(self):
|
||||
set_total_expense_zero("2013-02-28", "Cost Center")
|
||||
set_total_expense_zero("2013-02-28", "Cost Center", "_Test Cost Center 2 - _TC")
|
||||
set_total_expense_zero("2013-02-28", "cost_center")
|
||||
set_total_expense_zero("2013-02-28", "cost_center", "_Test Cost Center 2 - _TC")
|
||||
|
||||
budget = make_budget(budget_against="Cost Center", cost_center="_Test Company - _TC")
|
||||
frappe.db.set_value("Budget", budget.name, "action_if_accumulated_monthly_budget_exceeded", "Stop")
|
||||
@ -241,25 +241,30 @@ class TestBudget(unittest.TestCase):
|
||||
|
||||
|
||||
def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
|
||||
if budget_against_field == "Project":
|
||||
if budget_against_field == "project":
|
||||
budget_against = "_Test Project"
|
||||
else:
|
||||
budget_against = budget_against_CC or "_Test Cost Center - _TC"
|
||||
existing_expense = get_actual_expense(frappe._dict({
|
||||
|
||||
args = frappe._dict({
|
||||
"account": "_Test Account Cost for Goods Sold - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"monthly_end_date": posting_date,
|
||||
"company": "_Test Company",
|
||||
"fiscal_year": "_Test Fiscal Year 2013",
|
||||
"budget_against_field": budget_against_field,
|
||||
"budget_against": budget_against
|
||||
}))
|
||||
})
|
||||
|
||||
if not args.get(budget_against_field):
|
||||
args[budget_against_field] = budget_against
|
||||
|
||||
existing_expense = get_actual_expense(args)
|
||||
|
||||
if existing_expense:
|
||||
if budget_against_field == "Cost Center":
|
||||
if budget_against_field == "cost_center":
|
||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date="2013-02-28", submit=True)
|
||||
elif budget_against_field == "Project":
|
||||
elif budget_against_field == "project":
|
||||
make_journal_entry("_Test Account Cost for Goods Sold - _TC",
|
||||
"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date="2013-02-28")
|
||||
|
||||
|
@ -106,6 +106,21 @@ frappe.ui.form.on('Payment Entry', {
|
||||
};
|
||||
});
|
||||
|
||||
frm.set_query('payment_term', 'references', function(frm, cdt, cdn) {
|
||||
const child = locals[cdt][cdn];
|
||||
if (in_list(['Purchase Invoice', 'Sales Invoice'], child.reference_doctype) && child.reference_name) {
|
||||
let payment_term_list = frappe.get_list('Payment Schedule', {'parent': child.reference_name});
|
||||
|
||||
payment_term_list = payment_term_list.map(pt => pt.payment_term);
|
||||
|
||||
return {
|
||||
filters: {
|
||||
'name': ['in', payment_term_list]
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frm.set_query("reference_name", "references", function(doc, cdt, cdn) {
|
||||
const child = locals[cdt][cdn];
|
||||
const filters = {"docstatus": 1, "company": doc.company};
|
||||
@ -287,7 +302,7 @@ frappe.ui.form.on('Payment Entry', {
|
||||
frm.set_value("contact_email", "");
|
||||
frm.set_value("contact_person", "");
|
||||
}
|
||||
if(frm.doc.payment_type && frm.doc.party_type && frm.doc.party) {
|
||||
if(frm.doc.payment_type && frm.doc.party_type && frm.doc.party && frm.doc.company) {
|
||||
if(!frm.doc.posting_date) {
|
||||
frappe.msgprint(__("Please select Posting Date before selecting Party"))
|
||||
frm.set_value("party", "");
|
||||
@ -1033,4 +1048,4 @@ frappe.ui.form.on('Payment Entry', {
|
||||
});
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
@ -71,9 +71,9 @@ class PaymentEntry(AccountsController):
|
||||
self.update_outstanding_amounts()
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.update_payment_schedule()
|
||||
self.set_status()
|
||||
|
||||
|
||||
def on_cancel(self):
|
||||
self.setup_party_account_field()
|
||||
self.make_gl_entries(cancel=1)
|
||||
@ -81,6 +81,7 @@ class PaymentEntry(AccountsController):
|
||||
self.update_advance_paid()
|
||||
self.update_expense_claim()
|
||||
self.delink_advance_entry_references()
|
||||
self.update_payment_schedule(cancel=1)
|
||||
self.set_payment_req_status()
|
||||
self.set_status()
|
||||
|
||||
@ -94,10 +95,10 @@ class PaymentEntry(AccountsController):
|
||||
def validate_duplicate_entry(self):
|
||||
reference_names = []
|
||||
for d in self.get("references"):
|
||||
if (d.reference_doctype, d.reference_name) in reference_names:
|
||||
if (d.reference_doctype, d.reference_name, d.payment_term) in reference_names:
|
||||
frappe.throw(_("Row #{0}: Duplicate entry in References {1} {2}")
|
||||
.format(d.idx, d.reference_doctype, d.reference_name))
|
||||
reference_names.append((d.reference_doctype, d.reference_name))
|
||||
reference_names.append((d.reference_doctype, d.reference_name, d.payment_term))
|
||||
|
||||
def set_bank_account_data(self):
|
||||
if self.bank_account:
|
||||
@ -285,6 +286,36 @@ class PaymentEntry(AccountsController):
|
||||
frappe.throw(_("Against Journal Entry {0} does not have any unmatched {1} entry")
|
||||
.format(d.reference_name, dr_or_cr))
|
||||
|
||||
def update_payment_schedule(self, cancel=0):
|
||||
invoice_payment_amount_map = {}
|
||||
invoice_paid_amount_map = {}
|
||||
|
||||
for reference in self.get('references'):
|
||||
if reference.payment_term and reference.reference_name:
|
||||
key = (reference.payment_term, reference.reference_name)
|
||||
invoice_payment_amount_map.setdefault(key, 0.0)
|
||||
invoice_payment_amount_map[key] += reference.allocated_amount
|
||||
|
||||
if not invoice_paid_amount_map.get(reference.reference_name):
|
||||
payment_schedule = frappe.get_all('Payment Schedule', filters={'parent': reference.reference_name},
|
||||
fields=['paid_amount', 'payment_amount', 'payment_term'])
|
||||
for term in payment_schedule:
|
||||
invoice_key = (term.payment_term, reference.reference_name)
|
||||
invoice_paid_amount_map.setdefault(invoice_key, {})
|
||||
invoice_paid_amount_map[invoice_key]['outstanding'] = term.payment_amount - term.paid_amount
|
||||
|
||||
for key, amount in iteritems(invoice_payment_amount_map):
|
||||
if cancel:
|
||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` - %s
|
||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||
else:
|
||||
outstanding = invoice_paid_amount_map.get(key)['outstanding']
|
||||
if amount > outstanding:
|
||||
frappe.throw(_('Cannot allocate more than {0} against payment term {1}').format(outstanding, key[0]))
|
||||
|
||||
frappe.db.sql(""" UPDATE `tabPayment Schedule` SET paid_amount = `paid_amount` + %s
|
||||
WHERE parent = %s and payment_term = %s""", (amount, key[1], key[0]))
|
||||
|
||||
def set_status(self):
|
||||
if self.docstatus == 2:
|
||||
self.status = 'Cancelled'
|
||||
@ -1012,15 +1043,22 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
if doc.doctype == "Purchase Invoice" and doc.invoice_is_blocked():
|
||||
frappe.msgprint(_('{0} is on hold till {1}').format(doc.name, doc.release_date))
|
||||
else:
|
||||
pe.append("references", {
|
||||
'reference_doctype': dt,
|
||||
'reference_name': dn,
|
||||
"bill_no": doc.get("bill_no"),
|
||||
"due_date": doc.get("due_date"),
|
||||
'total_amount': grand_total,
|
||||
'outstanding_amount': outstanding_amount,
|
||||
'allocated_amount': outstanding_amount
|
||||
})
|
||||
if (doc.doctype in ('Sales Invoice', 'Purchase Invoice')
|
||||
and frappe.get_value('Payment Terms Template',
|
||||
{'name': doc.payment_terms_template}, 'allocate_payment_based_on_payment_terms')):
|
||||
|
||||
for reference in get_reference_as_per_payment_terms(doc.payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
||||
pe.append('references', reference)
|
||||
else:
|
||||
pe.append("references", {
|
||||
'reference_doctype': dt,
|
||||
'reference_name': dn,
|
||||
"bill_no": doc.get("bill_no"),
|
||||
"due_date": doc.get("due_date"),
|
||||
'total_amount': grand_total,
|
||||
'outstanding_amount': outstanding_amount,
|
||||
'allocated_amount': outstanding_amount
|
||||
})
|
||||
|
||||
pe.setup_party_account_field()
|
||||
pe.set_missing_values()
|
||||
@ -1029,6 +1067,22 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=
|
||||
pe.set_amounts()
|
||||
return pe
|
||||
|
||||
def get_reference_as_per_payment_terms(payment_schedule, dt, dn, doc, grand_total, outstanding_amount):
|
||||
references = []
|
||||
for payment_term in payment_schedule:
|
||||
references.append({
|
||||
'reference_doctype': dt,
|
||||
'reference_name': dn,
|
||||
'bill_no': doc.get('bill_no'),
|
||||
'due_date': doc.get('due_date'),
|
||||
'total_amount': grand_total,
|
||||
'outstanding_amount': outstanding_amount,
|
||||
'payment_term': payment_term.payment_term,
|
||||
'allocated_amount': flt(payment_term.payment_amount - payment_term.paid_amount,
|
||||
payment_term.precision('payment_amount'))
|
||||
})
|
||||
|
||||
return references
|
||||
|
||||
def get_paid_amount(dt, dn, party_type, party, account, due_date):
|
||||
if party_type=="Customer":
|
||||
|
@ -171,6 +171,32 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
self.assertEqual(flt(outstanding_amount), 100)
|
||||
self.assertEqual(status, 'Unpaid')
|
||||
|
||||
def test_payment_entry_against_payment_terms(self):
|
||||
si = create_sales_invoice(do_not_save=1, qty=1, rate=200)
|
||||
create_payment_terms_template()
|
||||
si.payment_terms_template = 'Test Receivable Template'
|
||||
|
||||
si.append('taxes', {
|
||||
"charge_type": "On Net Total",
|
||||
"account_head": "_Test Account Service Tax - _TC",
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"description": "Service Tax",
|
||||
"rate": 18
|
||||
})
|
||||
si.save()
|
||||
|
||||
si.submit()
|
||||
|
||||
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC")
|
||||
pe.submit()
|
||||
si.load_from_db()
|
||||
|
||||
self.assertEqual(pe.references[0].payment_term, 'Basic Amount Receivable')
|
||||
self.assertEqual(pe.references[1].payment_term, 'Tax Receivable')
|
||||
self.assertEqual(si.payment_schedule[0].paid_amount, 200.0)
|
||||
self.assertEqual(si.payment_schedule[1].paid_amount, 36.0)
|
||||
|
||||
|
||||
def test_payment_against_purchase_invoice_to_check_status(self):
|
||||
pi = make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC",
|
||||
currency="USD", conversion_rate=50)
|
||||
@ -609,4 +635,38 @@ class TestPaymentEntry(unittest.TestCase):
|
||||
self.assertEqual(expected_party_account_balance, party_account_balance)
|
||||
|
||||
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
|
||||
accounts_settings.save()
|
||||
accounts_settings.save()
|
||||
|
||||
def create_payment_terms_template():
|
||||
|
||||
create_payment_term('Basic Amount Receivable')
|
||||
create_payment_term('Tax Receivable')
|
||||
|
||||
if not frappe.db.exists('Payment Terms Template', 'Test Receivable Template'):
|
||||
payment_term_template = frappe.get_doc({
|
||||
'doctype': 'Payment Terms Template',
|
||||
'template_name': 'Test Receivable Template',
|
||||
'allocate_payment_based_on_payment_terms': 1,
|
||||
'terms': [{
|
||||
'doctype': 'Payment Terms Template Detail',
|
||||
'payment_term': 'Basic Amount Receivable',
|
||||
'invoice_portion': 84.746,
|
||||
'credit_days_based_on': 'Day(s) after invoice date',
|
||||
'credit_days': 1
|
||||
},
|
||||
{
|
||||
'doctype': 'Payment Terms Template Detail',
|
||||
'payment_term': 'Tax Receivable',
|
||||
'invoice_portion': 15.254,
|
||||
'credit_days_based_on': 'Day(s) after invoice date',
|
||||
'credit_days': 2
|
||||
}]
|
||||
}).insert()
|
||||
|
||||
|
||||
def create_payment_term(name):
|
||||
if not frappe.db.exists('Payment Term', name):
|
||||
frappe.get_doc({
|
||||
'doctype': 'Payment Term',
|
||||
'payment_term_name': name
|
||||
}).insert()
|
@ -1,343 +1,107 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"actions": [],
|
||||
"creation": "2016-06-01 16:55:32.196722",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"reference_doctype",
|
||||
"reference_name",
|
||||
"due_date",
|
||||
"bill_no",
|
||||
"payment_term",
|
||||
"column_break_4",
|
||||
"total_amount",
|
||||
"outstanding_amount",
|
||||
"allocated_amount",
|
||||
"exchange_rate"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "reference_doctype",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "reference_doctype",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "due_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Due Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "bill_no",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Supplier Invoice No",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "total_amount",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Total Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "outstanding_amount",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Outstanding",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "allocated_amount",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allocated",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"label": "Allocated"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:(doc.reference_doctype=='Purchase Invoice')",
|
||||
"fetch_if_empty": 0,
|
||||
"fieldname": "exchange_rate",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Exchange Rate",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "payment_term",
|
||||
"fieldtype": "Link",
|
||||
"label": "Payment Term",
|
||||
"options": "Payment Term"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2019-05-01 13:24:56.586677",
|
||||
"links": [],
|
||||
"modified": "2020-03-13 12:07:19.362539",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Entry Reference",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
"track_changes": 1
|
||||
}
|
@ -326,7 +326,7 @@ def make_payment_request(**args):
|
||||
"reference_doctype": args.dt,
|
||||
"reference_name": args.dn,
|
||||
"party_type": args.get("party_type") or "Customer",
|
||||
"party": args.get("party") or ref_doc.customer,
|
||||
"party": args.get("party") or ref_doc.get("customer"),
|
||||
"bank_account": bank_account
|
||||
})
|
||||
|
||||
@ -420,7 +420,7 @@ def make_payment_entry(docname):
|
||||
|
||||
def update_payment_req_status(doc, method):
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_reference_details
|
||||
|
||||
|
||||
for ref in doc.references:
|
||||
payment_request_name = frappe.db.get_value("Payment Request",
|
||||
{"reference_doctype": ref.reference_doctype, "reference_name": ref.reference_name,
|
||||
@ -430,7 +430,7 @@ def update_payment_req_status(doc, method):
|
||||
ref_details = get_reference_details(ref.reference_doctype, ref.reference_name, doc.party_account_currency)
|
||||
pay_req_doc = frappe.get_doc('Payment Request', payment_request_name)
|
||||
status = pay_req_doc.status
|
||||
|
||||
|
||||
if status != "Paid" and not ref_details.outstanding_amount:
|
||||
status = 'Paid'
|
||||
elif status != "Partially Paid" and ref_details.outstanding_amount != ref_details.total_amount:
|
||||
|
@ -1,243 +1,82 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"autoname": "",
|
||||
"beta": 0,
|
||||
"creation": "2017-08-10 15:38:00.080575",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"creation": "2017-08-10 15:38:00.080575",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"payment_term",
|
||||
"description",
|
||||
"due_date",
|
||||
"invoice_portion",
|
||||
"payment_amount",
|
||||
"mode_of_payment",
|
||||
"paid_amount"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "payment_term",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Term",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Payment Term",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "payment_term",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Payment Term",
|
||||
"options": "Payment Term",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fetch_from": "",
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Description",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "due_date",
|
||||
"fieldtype": "Date",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Due Date",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "due_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Due Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fetch_from": "",
|
||||
"fieldname": "invoice_portion",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Invoice Portion",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "invoice_portion",
|
||||
"fieldtype": "Percent",
|
||||
"in_list_view": 1,
|
||||
"label": "Invoice Portion",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 2,
|
||||
"fieldname": "payment_amount",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Amount",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "currency",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"columns": 2,
|
||||
"fieldname": "payment_amount",
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Payment Amount",
|
||||
"options": "currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "mode_of_payment",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Mode of Payment",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Mode of Payment",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
"fieldname": "mode_of_payment",
|
||||
"fieldtype": "Link",
|
||||
"label": "Mode of Payment",
|
||||
"options": "Mode of Payment"
|
||||
},
|
||||
{
|
||||
"fieldname": "paid_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Paid Amount"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-09-06 17:35:44.580209",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Schedule",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-03-13 17:58:24.729526",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Schedule",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -1,164 +1,84 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:template_name",
|
||||
"beta": 0,
|
||||
"creation": "2017-08-10 15:34:28.058054",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:template_name",
|
||||
"creation": "2017-08-10 15:34:28.058054",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"template_name",
|
||||
"allocate_payment_based_on_payment_terms",
|
||||
"terms"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "template_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Template Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "template_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Template Name",
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "terms",
|
||||
"fieldtype": "Table",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Payment Terms",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Payment Terms Template Detail",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldname": "terms",
|
||||
"fieldtype": "Table",
|
||||
"label": "Payment Terms",
|
||||
"options": "Payment Terms Template Detail",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If this checkbox is checked, paid amount will be splitted and allocated as per the amounts in payment schedule against each payment term",
|
||||
"fieldname": "allocate_payment_based_on_payment_terms",
|
||||
"fieldtype": "Check",
|
||||
"label": "Allocate Payment Based On Payment Terms"
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-01-24 11:13:31.158613",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Terms Template",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-04-01 15:35:18.112619",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Terms Template",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -237,6 +237,7 @@ def get_pricing_rule_for_item(args, price_list_rate=0, doc=None, for_validate=Fa
|
||||
if pricing_rule.mixed_conditions or pricing_rule.apply_rule_on_other:
|
||||
item_details.update({
|
||||
'apply_rule_on_other_items': json.dumps(pricing_rule.apply_rule_on_other_items),
|
||||
'price_or_product_discount': pricing_rule.price_or_product_discount,
|
||||
'apply_rule_on': (frappe.scrub(pricing_rule.apply_rule_on_other)
|
||||
if pricing_rule.apply_rule_on_other else frappe.scrub(pricing_rule.get('apply_on')))
|
||||
})
|
||||
|
@ -330,9 +330,9 @@ def get_qty_and_rate_for_mixed_conditions(doc, pr_doc, args):
|
||||
if pr_doc.mixed_conditions:
|
||||
amt = args.get('qty') * args.get("price_list_rate")
|
||||
if args.get("item_code") != row.get("item_code"):
|
||||
amt = row.get('qty') * (row.get("price_list_rate") or args.get("rate"))
|
||||
amt = flt(row.get('qty')) * flt(row.get("price_list_rate") or args.get("rate"))
|
||||
|
||||
sum_qty += row.get("stock_qty") or args.get("stock_qty") or args.get("qty")
|
||||
sum_qty += flt(row.get("stock_qty")) or flt(args.get("stock_qty")) or flt(args.get("qty"))
|
||||
sum_amt += amt
|
||||
|
||||
if pr_doc.is_cumulative:
|
||||
|
@ -261,12 +261,25 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
|
||||
price_list: this.frm.doc.buying_price_list
|
||||
}, function() {
|
||||
me.apply_pricing_rule();
|
||||
|
||||
me.frm.doc.apply_tds = me.frm.supplier_tds ? 1 : 0;
|
||||
me.frm.doc.tax_withholding_category = me.frm.supplier_tds;
|
||||
me.frm.set_df_property("apply_tds", "read_only", me.frm.supplier_tds ? 0 : 1);
|
||||
me.frm.set_df_property("tax_withholding_category", "hidden", me.frm.supplier_tds ? 0 : 1);
|
||||
})
|
||||
},
|
||||
|
||||
apply_tds: function(frm) {
|
||||
var me = this;
|
||||
|
||||
if (!me.frm.doc.apply_tds) {
|
||||
me.frm.set_value("tax_withholding_category", '');
|
||||
me.frm.set_df_property("tax_withholding_category", "hidden", 1);
|
||||
} else {
|
||||
me.frm.set_value("tax_withholding_category", me.frm.supplier_tds);
|
||||
me.frm.set_df_property("tax_withholding_category", "hidden", 0);
|
||||
}
|
||||
},
|
||||
|
||||
credit_to: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.credit_to) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
"supplier_name",
|
||||
"tax_id",
|
||||
"due_date",
|
||||
"tax_withholding_category",
|
||||
"column_break1",
|
||||
"company",
|
||||
"posting_date",
|
||||
@ -1294,13 +1295,21 @@
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Internal Supplier",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "tax_withholding_category",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Tax Withholding Category",
|
||||
"options": "Tax Withholding Category",
|
||||
"print_hide": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 204,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-17 13:05:25.199832",
|
||||
"modified": "2020-04-18 13:05:25.199832",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
@ -1002,7 +1002,7 @@ class PurchaseInvoice(BuyingController):
|
||||
if not self.apply_tds:
|
||||
return
|
||||
|
||||
tax_withholding_details = get_party_tax_withholding_details(self)
|
||||
tax_withholding_details = get_party_tax_withholding_details(self, self.tax_withholding_category)
|
||||
|
||||
if not tax_withholding_details:
|
||||
return
|
||||
|
@ -550,24 +550,21 @@
|
||||
},
|
||||
{
|
||||
"fieldname": "brand",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"label": "Brand",
|
||||
"oldfieldname": "brand",
|
||||
"oldfieldtype": "Data",
|
||||
"print_hide": 1
|
||||
"print_hide": 1,
|
||||
"options": "Brand"
|
||||
},
|
||||
{
|
||||
"fetch_from": "item_code.item_group",
|
||||
"fetch_if_empty": 1,
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Link",
|
||||
"label": "Item Group",
|
||||
"oldfieldname": "item_group",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Item Group",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
"read_only": 1,
|
||||
"options": "Item Group"
|
||||
},
|
||||
{
|
||||
"description": "Tax detail table fetched from item master as a string and stored in this field.\nUsed for Taxes and Charges",
|
||||
@ -777,7 +774,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-07 18:34:35.104178",
|
||||
"modified": "2020-04-22 10:37:35.103176",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice Item",
|
||||
@ -785,4 +782,4 @@
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "hash",
|
||||
"creation": "2013-05-21 16:16:04",
|
||||
"doctype": "DocType",
|
||||
@ -14,11 +15,11 @@
|
||||
"col_break1",
|
||||
"account_head",
|
||||
"description",
|
||||
"section_break_10",
|
||||
"rate",
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
"dimension_col_break",
|
||||
"section_break_10",
|
||||
"rate",
|
||||
"section_break_9",
|
||||
"tax_amount",
|
||||
"tax_amount_after_discount_amount",
|
||||
@ -27,8 +28,7 @@
|
||||
"base_tax_amount",
|
||||
"base_total",
|
||||
"base_tax_amount_after_discount_amount",
|
||||
"item_wise_tax_detail",
|
||||
"parenttype"
|
||||
"item_wise_tax_detail"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -53,6 +53,7 @@
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"default": "On Net Total",
|
||||
"fieldname": "charge_type",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
@ -196,15 +197,6 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "parenttype",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Parenttype",
|
||||
"oldfieldname": "parenttype",
|
||||
"oldfieldtype": "Data",
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "accounting_dimensions_section",
|
||||
"fieldtype": "Section Break",
|
||||
@ -217,11 +209,14 @@
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-05-25 23:08:38.281025",
|
||||
"links": [],
|
||||
"modified": "2020-03-12 14:53:47.679439",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Taxes and Charges",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -26,16 +26,24 @@ frappe.ui.form.on("Sales Invoice", {
|
||||
&& !frm.doc.is_return && !frm.doc.ewaybill) {
|
||||
|
||||
frm.add_custom_button('E-Way Bill JSON', () => {
|
||||
var w = window.open(
|
||||
frappe.urllib.get_full_url(
|
||||
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
|
||||
+ "dt=" + encodeURIComponent(frm.doc.doctype)
|
||||
+ "&dn=" + encodeURIComponent(frm.doc.name)
|
||||
)
|
||||
);
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
||||
}
|
||||
frappe.call({
|
||||
method: 'erpnext.regional.india.utils.generate_ewb_json',
|
||||
args: {
|
||||
'dt': frm.doc.doctype,
|
||||
'dn': [frm.doc.name]
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
const args = {
|
||||
cmd: 'erpnext.regional.india.utils.download_ewb_json',
|
||||
data: r.message,
|
||||
docname: frm.doc.name
|
||||
};
|
||||
open_url_post(frappe.request.url, args);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}, __("Create"));
|
||||
}
|
||||
}
|
||||
|
@ -16,17 +16,23 @@ frappe.listview_settings['Sales Invoice'].onload = function (doclist) {
|
||||
}
|
||||
}
|
||||
|
||||
var w = window.open(
|
||||
frappe.urllib.get_full_url(
|
||||
"/api/method/erpnext.regional.india.utils.generate_ewb_json?"
|
||||
+ "dt=" + encodeURIComponent(doclist.doctype)
|
||||
+ "&dn=" + encodeURIComponent(docnames)
|
||||
)
|
||||
);
|
||||
if (!w) {
|
||||
frappe.msgprint(__("Please enable pop-ups")); return;
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: 'erpnext.regional.india.utils.generate_ewb_json',
|
||||
args: {
|
||||
'dt': doclist.doctype,
|
||||
'dn': docnames
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
const args = {
|
||||
cmd: 'erpnext.regional.india.utils.download_ewb_json',
|
||||
data: r.message,
|
||||
docname: docnames
|
||||
};
|
||||
open_url_post(frappe.request.url, args);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
doclist.page.add_actions_menu_item(__('Generate E-Way Bill JSON'), action, false);
|
||||
|
@ -32,6 +32,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
|
||||
me.frm.script_manager.trigger("is_pos");
|
||||
me.frm.refresh_fields();
|
||||
}
|
||||
erpnext.queries.setup_warehouse_query(this.frm);
|
||||
},
|
||||
|
||||
refresh: function(doc, dt, dn) {
|
||||
@ -586,7 +587,9 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
frm.set_query("account_for_change_amount", function() {
|
||||
return {
|
||||
filters: {
|
||||
account_type: ['in', ["Cash", "Bank"]]
|
||||
account_type: ['in', ["Cash", "Bank"]],
|
||||
company: frm.doc.company,
|
||||
is_group: 0
|
||||
}
|
||||
};
|
||||
});
|
||||
@ -667,7 +670,8 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
frm.fields_dict["loyalty_redemption_account"].get_query = function() {
|
||||
return {
|
||||
filters:{
|
||||
"company": frm.doc.company
|
||||
"company": frm.doc.company,
|
||||
"is_group": 0
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -676,7 +680,8 @@ frappe.ui.form.on('Sales Invoice', {
|
||||
frm.fields_dict["loyalty_redemption_cost_center"].get_query = function() {
|
||||
return {
|
||||
filters:{
|
||||
"company": frm.doc.company
|
||||
"company": frm.doc.company,
|
||||
"is_group": 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1892,7 +1892,7 @@ class TestSalesInvoice(unittest.TestCase):
|
||||
|
||||
si.submit()
|
||||
|
||||
data = get_ewb_data("Sales Invoice", si.name)
|
||||
data = get_ewb_data("Sales Invoice", [si.name])
|
||||
|
||||
self.assertEqual(data['version'], '1.0.1118')
|
||||
self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
|
||||
|
@ -6,23 +6,42 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import flt
|
||||
from frappe.utils import flt, getdate
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
class TaxWithholdingCategory(Document):
|
||||
pass
|
||||
|
||||
def get_party_tax_withholding_details(ref_doc):
|
||||
tax_withholding_category = frappe.db.get_value('Supplier', ref_doc.supplier, 'tax_withholding_category')
|
||||
def get_party_tax_withholding_details(ref_doc, tax_withholding_category=None):
|
||||
|
||||
pan_no = ''
|
||||
suppliers = []
|
||||
|
||||
if not tax_withholding_category:
|
||||
tax_withholding_category, pan_no = frappe.db.get_value('Supplier', ref_doc.supplier, ['tax_withholding_category', 'pan'])
|
||||
|
||||
if not tax_withholding_category:
|
||||
return
|
||||
|
||||
if not pan_no:
|
||||
pan_no = frappe.db.get_value('Supplier', ref_doc.supplier, 'pan')
|
||||
|
||||
# Get others suppliers with the same PAN No
|
||||
if pan_no:
|
||||
suppliers = [d.name for d in frappe.get_all('Supplier', fields=['name'], filters={'pan': pan_no})]
|
||||
|
||||
if not suppliers:
|
||||
suppliers.append(ref_doc.supplier)
|
||||
|
||||
fy = get_fiscal_year(ref_doc.posting_date, company=ref_doc.company)
|
||||
tax_details = get_tax_withholding_details(tax_withholding_category, fy[0], ref_doc.company)
|
||||
if not tax_details:
|
||||
frappe.throw(_('Please set associated account in Tax Withholding Category {0} against Company {1}')
|
||||
.format(tax_withholding_category, ref_doc.company))
|
||||
tds_amount = get_tds_amount(ref_doc, tax_details, fy)
|
||||
|
||||
tds_amount = get_tds_amount(suppliers, ref_doc.net_total, ref_doc.company,
|
||||
tax_details, fy, ref_doc.posting_date, pan_no)
|
||||
|
||||
tax_row = get_tax_row(tax_details, tds_amount)
|
||||
|
||||
return tax_row
|
||||
@ -51,6 +70,7 @@ def get_tax_withholding_rates(tax_withholding, fiscal_year):
|
||||
frappe.throw(_("No Tax Withholding data found for the current Fiscal Year."))
|
||||
|
||||
def get_tax_row(tax_details, tds_amount):
|
||||
|
||||
return {
|
||||
"category": "Total",
|
||||
"add_deduct_tax": "Deduct",
|
||||
@ -60,25 +80,36 @@ def get_tax_row(tax_details, tds_amount):
|
||||
"tax_amount": tds_amount
|
||||
}
|
||||
|
||||
def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
|
||||
def get_tds_amount(suppliers, net_total, company, tax_details, fiscal_year_details, posting_date, pan_no=None):
|
||||
fiscal_year, year_start_date, year_end_date = fiscal_year_details
|
||||
tds_amount = 0
|
||||
tds_deducted = 0
|
||||
|
||||
def _get_tds(amount):
|
||||
def _get_tds(amount, rate):
|
||||
if amount <= 0:
|
||||
return 0
|
||||
|
||||
return amount * tax_details.rate / 100
|
||||
return amount * rate / 100
|
||||
|
||||
ldc_name = frappe.db.get_value('Lower Deduction Certificate',
|
||||
{
|
||||
'pan_no': pan_no,
|
||||
'fiscal_year': fiscal_year
|
||||
}, 'name')
|
||||
ldc = ''
|
||||
|
||||
if ldc_name:
|
||||
ldc = frappe.get_doc('Lower Deduction Certificate', ldc_name)
|
||||
|
||||
entries = frappe.db.sql("""
|
||||
select voucher_no, credit
|
||||
from `tabGL Entry`
|
||||
where party=%s and fiscal_year=%s and credit > 0
|
||||
""", (ref_doc.supplier, fiscal_year), as_dict=1)
|
||||
where company = %s and
|
||||
party in %s and fiscal_year=%s and credit > 0
|
||||
""", (company, tuple(suppliers), fiscal_year), as_dict=1)
|
||||
|
||||
vouchers = [d.voucher_no for d in entries]
|
||||
advance_vouchers = get_advance_vouchers(ref_doc.supplier, fiscal_year)
|
||||
advance_vouchers = get_advance_vouchers(suppliers, fiscal_year=fiscal_year, company=company)
|
||||
|
||||
tds_vouchers = vouchers + advance_vouchers
|
||||
|
||||
@ -93,7 +124,20 @@ def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
|
||||
tds_deducted = tds_deducted[0][0] if tds_deducted and tds_deducted[0][0] else 0
|
||||
|
||||
if tds_deducted:
|
||||
tds_amount = _get_tds(ref_doc.net_total)
|
||||
if ldc:
|
||||
limit_consumed = frappe.db.get_value('Purchase Invoice',
|
||||
{
|
||||
'supplier': ('in', suppliers),
|
||||
'apply_tds': 1,
|
||||
'docstatus': 1
|
||||
}, 'sum(net_total)')
|
||||
|
||||
if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, limit_consumed, net_total,
|
||||
ldc.certificate_limit):
|
||||
|
||||
tds_amount = get_ltds_amount(net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details)
|
||||
else:
|
||||
tds_amount = _get_tds(net_total, tax_details.rate)
|
||||
else:
|
||||
supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
|
||||
fields = ['sum(net_amount)'],
|
||||
@ -106,43 +150,79 @@ def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
|
||||
fields = ['sum(credit_in_account_currency)'],
|
||||
filters = {
|
||||
'parent': ('in', vouchers), 'docstatus': 1,
|
||||
'party': ref_doc.supplier,
|
||||
'party': ('in', suppliers),
|
||||
'reference_type': ('not in', ['Purchase Invoice'])
|
||||
}, as_list=1)
|
||||
|
||||
supplier_credit_amount += (jv_supplier_credit_amt[0][0]
|
||||
if jv_supplier_credit_amt and jv_supplier_credit_amt[0][0] else 0)
|
||||
|
||||
supplier_credit_amount += ref_doc.net_total
|
||||
supplier_credit_amount += net_total
|
||||
|
||||
debit_note_amount = get_debit_note_amount(ref_doc.supplier, year_start_date, year_end_date)
|
||||
debit_note_amount = get_debit_note_amount(suppliers, year_start_date, year_end_date)
|
||||
supplier_credit_amount -= debit_note_amount
|
||||
|
||||
if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
|
||||
or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
|
||||
tds_amount = _get_tds(supplier_credit_amount)
|
||||
|
||||
if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, tds_deducted, net_total,
|
||||
ldc.certificate_limit):
|
||||
tds_amount = get_ltds_amount(supplier_credit_amount, 0, ldc.certificate_limit, ldc.rate,
|
||||
tax_details)
|
||||
else:
|
||||
tds_amount = _get_tds(supplier_credit_amount, tax_details.rate)
|
||||
|
||||
return tds_amount
|
||||
|
||||
def get_advance_vouchers(supplier, fiscal_year=None, company=None, from_date=None, to_date=None):
|
||||
def get_advance_vouchers(suppliers, fiscal_year=None, company=None, from_date=None, to_date=None):
|
||||
condition = "fiscal_year=%s" % fiscal_year
|
||||
|
||||
if company:
|
||||
condition += "and company =%s" % (company)
|
||||
if from_date and to_date:
|
||||
condition = "company=%s and posting_date between %s and %s" % (company, from_date, to_date)
|
||||
condition += "and posting_date between %s and %s" % (company, from_date, to_date)
|
||||
|
||||
## Appending the same supplier again if length of suppliers list is 1
|
||||
## since tuple of single element list contains None, For example ('Test Supplier 1', )
|
||||
## and the below query fails
|
||||
if len(suppliers) == 1:
|
||||
suppliers.append(suppliers[0])
|
||||
|
||||
return frappe.db.sql_list("""
|
||||
select distinct voucher_no
|
||||
from `tabGL Entry`
|
||||
where party=%s and %s and debit > 0
|
||||
""", (supplier, condition)) or []
|
||||
where party in %s and %s and debit > 0
|
||||
""", (tuple(suppliers), condition)) or []
|
||||
|
||||
def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None):
|
||||
condition = ""
|
||||
def get_debit_note_amount(suppliers, year_start_date, year_end_date, company=None):
|
||||
condition = "and 1=1"
|
||||
if company:
|
||||
condition = " and company=%s " % company
|
||||
|
||||
if len(suppliers) == 1:
|
||||
suppliers.append(suppliers[0])
|
||||
|
||||
return flt(frappe.db.sql("""
|
||||
select abs(sum(net_total))
|
||||
from `tabPurchase Invoice`
|
||||
where supplier=%s %s and is_return=1 and docstatus=1
|
||||
and posting_date between %s and %s
|
||||
""", (supplier, condition, year_start_date, year_end_date)))
|
||||
where supplier in %s and is_return=1 and docstatus=1
|
||||
and posting_date between %s and %s %s
|
||||
""", (tuple(suppliers), year_start_date, year_end_date, condition)))
|
||||
|
||||
def get_ltds_amount(current_amount, deducted_amount, certificate_limit, rate, tax_details):
|
||||
if current_amount < (certificate_limit - deducted_amount):
|
||||
return current_amount * rate/100
|
||||
else:
|
||||
ltds_amount = (certificate_limit - deducted_amount)
|
||||
tds_amount = current_amount - ltds_amount
|
||||
|
||||
return ltds_amount * rate/100 + tds_amount * tax_details.rate/100
|
||||
|
||||
def is_valid_certificate(valid_from, valid_upto, posting_date, deducted_amount, current_amount, certificate_limit):
|
||||
valid = False
|
||||
|
||||
if ((getdate(valid_from) <= getdate(posting_date) <= getdate(valid_upto)) and
|
||||
certificate_limit > deducted_amount):
|
||||
valid = True
|
||||
|
||||
return valid
|
@ -344,26 +344,28 @@ class ReceivablePayableReport(object):
|
||||
def allocate_outstanding_based_on_payment_terms(self, row):
|
||||
self.get_payment_terms(row)
|
||||
for term in row.payment_terms:
|
||||
term.outstanding = term.invoiced
|
||||
|
||||
# update "paid" and "oustanding" for this term
|
||||
self.allocate_closing_to_term(row, term, 'paid')
|
||||
if not term.paid:
|
||||
self.allocate_closing_to_term(row, term, 'paid')
|
||||
|
||||
# update "credit_note" and "oustanding" for this term
|
||||
if term.outstanding:
|
||||
self.allocate_closing_to_term(row, term, 'credit_note')
|
||||
|
||||
row.payment_terms = sorted(row.payment_terms, key=lambda x: x['due_date'])
|
||||
|
||||
def get_payment_terms(self, row):
|
||||
# build payment_terms for row
|
||||
payment_terms_details = frappe.db.sql("""
|
||||
select
|
||||
si.name, si.party_account_currency, si.currency, si.conversion_rate,
|
||||
ps.due_date, ps.payment_amount, ps.description
|
||||
ps.due_date, ps.payment_amount, ps.description, ps.paid_amount
|
||||
from `tab{0}` si, `tabPayment Schedule` ps
|
||||
where
|
||||
si.name = ps.parent and
|
||||
si.name = %s
|
||||
order by ps.due_date
|
||||
order by ps.paid_amount desc, due_date
|
||||
""".format(row.voucher_type), row.voucher_no, as_dict = 1)
|
||||
|
||||
|
||||
@ -389,11 +391,14 @@ class ReceivablePayableReport(object):
|
||||
"invoiced": invoiced,
|
||||
"invoice_grand_total": row.invoiced,
|
||||
"payment_term": d.description,
|
||||
"paid": 0.0,
|
||||
"paid": d.paid_amount,
|
||||
"credit_note": 0.0,
|
||||
"outstanding": 0.0
|
||||
"outstanding": invoiced - d.paid_amount
|
||||
}))
|
||||
|
||||
if d.paid_amount:
|
||||
row['paid'] -= d.paid_amount
|
||||
|
||||
def allocate_closing_to_term(self, row, term, key):
|
||||
if row[key]:
|
||||
if row[key] > term.outstanding:
|
||||
|
@ -84,6 +84,7 @@ def get_balance_sheet_data(fiscal_year, companies, columns, filters):
|
||||
|
||||
def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
||||
income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
|
||||
company_currency = get_company_currency(filters)
|
||||
|
||||
data = []
|
||||
data.extend(income or [])
|
||||
@ -93,7 +94,7 @@ def get_profit_loss_data(fiscal_year, companies, columns, filters):
|
||||
|
||||
chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
|
||||
|
||||
report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, True)
|
||||
report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, True)
|
||||
|
||||
return data, None, chart, report_summary
|
||||
|
||||
|
@ -8,7 +8,6 @@ from frappe.utils import flt
|
||||
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
|
||||
import copy
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
||||
filters.periodicity, filters.accumulated_values, filters.company)
|
||||
@ -27,17 +26,19 @@ def execute(filters=None):
|
||||
|
||||
|
||||
gross_income = get_revenue(income, period_list)
|
||||
|
||||
gross_expense = get_revenue(expense, period_list)
|
||||
|
||||
if(len(gross_income)==0 and len(gross_expense)== 0):
|
||||
data.append({"account_name": "'" + _("Nothing is included in gross") + "'",
|
||||
"account": "'" + _("Nothing is included in gross") + "'"})
|
||||
|
||||
data.append({
|
||||
"account_name": "'" + _("Nothing is included in gross") + "'",
|
||||
"account": "'" + _("Nothing is included in gross") + "'"
|
||||
})
|
||||
return columns, data
|
||||
|
||||
data.append({"account_name": "'" + _("Included in Gross Profit") + "'",
|
||||
"account": "'" + _("Included in Gross Profit") + "'"})
|
||||
data.append({
|
||||
"account_name": "'" + _("Included in Gross Profit") + "'",
|
||||
"account": "'" + _("Included in Gross Profit") + "'"
|
||||
})
|
||||
|
||||
data.append({})
|
||||
data.extend(gross_income or [])
|
||||
@ -111,7 +112,6 @@ def set_total(node, value, complete_list, totals):
|
||||
|
||||
|
||||
def get_profit(gross_income, gross_expense, period_list, company, profit_type, currency=None, consolidated=False):
|
||||
|
||||
profit_loss = {
|
||||
"account_name": "'" + _(profit_type) + "'",
|
||||
"account": "'" + _(profit_type) + "'",
|
||||
@ -123,7 +123,9 @@ def get_profit(gross_income, gross_expense, period_list, company, profit_type, c
|
||||
|
||||
for period in period_list:
|
||||
key = period if consolidated else period.key
|
||||
profit_loss[key] = flt(gross_income[0].get(key, 0)) - flt(gross_expense[0].get(key, 0))
|
||||
gross_income_for_period = flt(gross_income[0].get(key, 0)) if gross_income else 0
|
||||
gross_expense_for_period = flt(gross_expense[0].get(key, 0)) if gross_expense else 0
|
||||
profit_loss[key] = gross_income_for_period - gross_expense_for_period
|
||||
|
||||
if profit_loss[key]:
|
||||
has_value=True
|
||||
@ -143,12 +145,18 @@ def get_net_profit(non_gross_income, gross_income, gross_expense, non_gross_expe
|
||||
|
||||
for period in period_list:
|
||||
key = period if consolidated else period.key
|
||||
total_income = flt(gross_income[0].get(key, 0)) + flt(non_gross_income[0].get(key, 0))
|
||||
total_expense = flt(gross_expense[0].get(key, 0)) + flt(non_gross_expense[0].get(key, 0))
|
||||
gross_income_for_period = flt(gross_income[0].get(key, 0)) if gross_income else 0
|
||||
non_gross_income_for_period = flt(non_gross_income[0].get(key, 0)) if non_gross_income else 0
|
||||
|
||||
gross_expense_for_period = flt(gross_expense[0].get(key, 0)) if gross_expense else 0
|
||||
non_gross_expense_for_period = flt(non_gross_expense[0].get(key, 0)) if non_gross_expense else 0
|
||||
|
||||
total_income = gross_income_for_period + non_gross_income_for_period
|
||||
total_expense = gross_expense_for_period + non_gross_expense_for_period
|
||||
profit_loss[key] = flt(total_income) - flt(total_expense)
|
||||
|
||||
if profit_loss[key]:
|
||||
has_value=True
|
||||
|
||||
if has_value:
|
||||
return profit_loss
|
||||
return profit_loss
|
@ -55,27 +55,27 @@ def get_columns(group_wise_columns, filters):
|
||||
columns = []
|
||||
column_map = frappe._dict({
|
||||
"parent": _("Sales Invoice") + ":Link/Sales Invoice:120",
|
||||
"posting_date": _("Posting Date") + ":Date",
|
||||
"posting_time": _("Posting Time"),
|
||||
"item_code": _("Item Code") + ":Link/Item",
|
||||
"item_name": _("Item Name"),
|
||||
"item_group": _("Item Group") + ":Link/Item Group",
|
||||
"brand": _("Brand"),
|
||||
"description": _("Description"),
|
||||
"warehouse": _("Warehouse") + ":Link/Warehouse",
|
||||
"qty": _("Qty") + ":Float",
|
||||
"base_rate": _("Avg. Selling Rate") + ":Currency/currency",
|
||||
"buying_rate": _("Valuation Rate") + ":Currency/currency",
|
||||
"base_amount": _("Selling Amount") + ":Currency/currency",
|
||||
"buying_amount": _("Buying Amount") + ":Currency/currency",
|
||||
"gross_profit": _("Gross Profit") + ":Currency/currency",
|
||||
"gross_profit_percent": _("Gross Profit %") + ":Percent",
|
||||
"project": _("Project") + ":Link/Project",
|
||||
"posting_date": _("Posting Date") + ":Date:100",
|
||||
"posting_time": _("Posting Time") + ":Data:100",
|
||||
"item_code": _("Item Code") + ":Link/Item:100",
|
||||
"item_name": _("Item Name") + ":Data:100",
|
||||
"item_group": _("Item Group") + ":Link/Item Group:100",
|
||||
"brand": _("Brand") + ":Link/Brand:100",
|
||||
"description": _("Description") +":Data:100",
|
||||
"warehouse": _("Warehouse") + ":Link/Warehouse:100",
|
||||
"qty": _("Qty") + ":Float:80",
|
||||
"base_rate": _("Avg. Selling Rate") + ":Currency/currency:100",
|
||||
"buying_rate": _("Valuation Rate") + ":Currency/currency:100",
|
||||
"base_amount": _("Selling Amount") + ":Currency/currency:100",
|
||||
"buying_amount": _("Buying Amount") + ":Currency/currency:100",
|
||||
"gross_profit": _("Gross Profit") + ":Currency/currency:100",
|
||||
"gross_profit_percent": _("Gross Profit %") + ":Percent:100",
|
||||
"project": _("Project") + ":Link/Project:100",
|
||||
"sales_person": _("Sales person"),
|
||||
"allocated_amount": _("Allocated Amount") + ":Currency/currency",
|
||||
"customer": _("Customer") + ":Link/Customer",
|
||||
"customer_group": _("Customer Group") + ":Link/Customer Group",
|
||||
"territory": _("Territory") + ":Link/Territory"
|
||||
"allocated_amount": _("Allocated Amount") + ":Currency/currency:100",
|
||||
"customer": _("Customer") + ":Link/Customer:100",
|
||||
"customer_group": _("Customer Group") + ":Link/Customer Group:100",
|
||||
"territory": _("Territory") + ":Link/Territory:100"
|
||||
})
|
||||
|
||||
for col in group_wise_columns.get(scrub(filters.group_by)):
|
||||
@ -85,7 +85,8 @@ def get_columns(group_wise_columns, filters):
|
||||
"fieldname": "currency",
|
||||
"label" : _("Currency"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Currency"
|
||||
"options": "Currency",
|
||||
"hidden": 1
|
||||
})
|
||||
|
||||
return columns
|
||||
@ -277,7 +278,7 @@ class GrossProfitGenerator(object):
|
||||
from `tabPurchase Invoice Item` a
|
||||
where a.item_code = %s and a.docstatus=1
|
||||
and modified <= %s
|
||||
order by a.modified desc limit 1""", (item_code,self.filters.to_date))
|
||||
order by a.modified desc limit 1""", (item_code, self.filters.to_date))
|
||||
else:
|
||||
last_purchase_rate = frappe.db.sql("""
|
||||
select (a.base_rate / a.conversion_factor)
|
||||
|
@ -102,7 +102,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
|
||||
data.append(row)
|
||||
|
||||
if filters.get('group_by'):
|
||||
if filters.get('group_by') and item_list:
|
||||
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
||||
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
||||
data.append(total_row)
|
||||
|
@ -111,7 +111,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
|
||||
|
||||
data.append(row)
|
||||
|
||||
if filters.get('group_by'):
|
||||
if filters.get('group_by') and item_list:
|
||||
total_row = total_row_map.get(prev_group_by_value or d.get('item_name'))
|
||||
total_row['percent_gt'] = flt(total_row['total']/grand_total * 100)
|
||||
data.append(total_row)
|
||||
|
@ -44,9 +44,14 @@ def get_result(filters):
|
||||
out = []
|
||||
for supplier in filters.supplier:
|
||||
tds = frappe.get_doc("Tax Withholding Category", supplier.tax_withholding_category)
|
||||
rate = [d.tax_withholding_rate for d in tds.rates if d.fiscal_year == filters.fiscal_year][0]
|
||||
rate = [d.tax_withholding_rate for d in tds.rates if d.fiscal_year == filters.fiscal_year]
|
||||
|
||||
if rate:
|
||||
rate = rate[0]
|
||||
|
||||
try:
|
||||
account = [d.account for d in tds.accounts if d.company == filters.company][0]
|
||||
|
||||
except IndexError:
|
||||
account = []
|
||||
total_invoiced_amount, tds_deducted = get_invoice_and_tds_amount(supplier.name, account,
|
||||
@ -76,7 +81,7 @@ def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date):
|
||||
supplier_credit_amount = flt(sum([d.credit for d in entries]))
|
||||
|
||||
vouchers = [d.voucher_no for d in entries]
|
||||
vouchers += get_advance_vouchers(supplier, company=company,
|
||||
vouchers += get_advance_vouchers([supplier], company=company,
|
||||
from_date=from_date, to_date=to_date)
|
||||
|
||||
tds_deducted = 0
|
||||
@ -89,7 +94,7 @@ def get_invoice_and_tds_amount(supplier, account, company, from_date, to_date):
|
||||
""".format(', '.join(["'%s'" % d for d in vouchers])),
|
||||
(account, from_date, to_date, company))[0][0])
|
||||
|
||||
debit_note_amount = get_debit_note_amount(supplier, from_date, to_date, company=company)
|
||||
debit_note_amount = get_debit_note_amount([supplier], from_date, to_date, company=company)
|
||||
|
||||
total_invoiced_amount = supplier_credit_amount + tds_deducted - debit_note_amount
|
||||
|
||||
|
@ -24,26 +24,6 @@ frappe.ui.form.on('Asset Maintenance', {
|
||||
return indicator;
|
||||
}
|
||||
);
|
||||
|
||||
frm.set_query('select_serial_no', function(doc){
|
||||
return {
|
||||
asset: frm.doc.asset_name
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
select_serial_no: (frm) => {
|
||||
let serial_nos = frm.doc.serial_no || frm.doc.select_serial_no;
|
||||
if (serial_nos) {
|
||||
serial_nos = serial_nos.split('\n');
|
||||
serial_nos.push(frm.doc.select_serial_no);
|
||||
|
||||
const unique_sn = serial_nos.filter(function(elem, index, self) {
|
||||
return index === self.indexOf(elem);
|
||||
});
|
||||
|
||||
frm.set_value("serial_no", unique_sn.join('\n'));
|
||||
}
|
||||
},
|
||||
|
||||
refresh: (frm) => {
|
||||
@ -93,25 +73,6 @@ frappe.ui.form.on('Asset Maintenance Task', {
|
||||
},
|
||||
end_date: (frm, cdt, cdn) => {
|
||||
get_next_due_date(frm, cdt, cdn);
|
||||
},
|
||||
assign_to: (frm, cdt, cdn) => {
|
||||
var d = locals[cdt][cdn];
|
||||
if (frm.doc.__islocal) {
|
||||
frappe.model.set_value(cdt, cdn, "assign_to", "");
|
||||
frappe.model.set_value(cdt, cdn, "assign_to_name", "");
|
||||
frappe.throw(__("Please save before assigning task."));
|
||||
}
|
||||
if (d.assign_to) {
|
||||
return frappe.call({
|
||||
method: 'erpnext.assets.doctype.asset_maintenance.asset_maintenance.assign_tasks',
|
||||
args: {
|
||||
asset_maintenance_name: frm.doc.name,
|
||||
assign_to_member: d.assign_to,
|
||||
maintenance_task: d.maintenance_task,
|
||||
next_due_date: d.next_due_date
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -16,12 +16,11 @@ class AssetMaintenance(Document):
|
||||
throw(_("Start date should be less than end date for task {0}").format(task.maintenance_task))
|
||||
if getdate(task.next_due_date) < getdate(nowdate()):
|
||||
task.maintenance_status = "Overdue"
|
||||
if not task.assign_to and self.docstatus == 0:
|
||||
throw(_("Row #{}: Please asign task to a member.").format(task.idx))
|
||||
|
||||
def on_update(self):
|
||||
for task in self.get('asset_maintenance_tasks'):
|
||||
if not task.assign_to:
|
||||
task.db_set("assign_to", self.maintenance_manager)
|
||||
task.db_set("assign_to_name", self.maintenance_manager_name)
|
||||
assign_tasks(self.name, task.assign_to, task.maintenance_task, task.next_due_date)
|
||||
self.sync_maintenance_tasks()
|
||||
|
||||
@ -108,7 +107,7 @@ def update_maintenance_log(asset_maintenance, item_code, item_name, task):
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_team_members(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.get_values('Maintenance Team Member', {'parent':filters.get("maintenance_team")})
|
||||
return frappe.db.get_values('Maintenance Team Member', { 'parent': filters.get("maintenance_team") })
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_maintenance_log(asset_name):
|
||||
|
@ -125,13 +125,15 @@ def get_maintenance_tasks():
|
||||
"start_date": nowdate(),
|
||||
"periodicity": "Monthly",
|
||||
"maintenance_type": "Preventive Maintenance",
|
||||
"maintenance_status": "Planned"
|
||||
"maintenance_status": "Planned",
|
||||
"assign_to": "marcus@abc.com"
|
||||
},
|
||||
{"maintenance_task": "Check Gears",
|
||||
"start_date": nowdate(),
|
||||
"periodicity": "Yearly",
|
||||
"maintenance_type": "Calibration",
|
||||
"maintenance_status": "Planned"
|
||||
"maintenance_status": "Planned",
|
||||
"assign_to": "thalia@abc.com"
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -27,15 +27,6 @@ frappe.ui.form.on("Purchase Order", {
|
||||
frm.set_indicator_formatter('item_code',
|
||||
function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
|
||||
|
||||
frm.set_query("blanket_order", "items", function() {
|
||||
return {
|
||||
filters: {
|
||||
"company": frm.doc.company,
|
||||
"docstatus": 1
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frm.set_query("expense_account", "items", function() {
|
||||
return {
|
||||
query: "erpnext.controllers.queries.get_expense_account",
|
||||
@ -365,9 +356,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
|
||||
source_doctype: "Material Request",
|
||||
target: me.frm,
|
||||
setters: {
|
||||
company: me.frm.doc.company
|
||||
},
|
||||
setters: {},
|
||||
get_query_filters: {
|
||||
material_request_type: "Purchase",
|
||||
docstatus: 1,
|
||||
@ -384,7 +373,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
||||
source_doctype: "Supplier Quotation",
|
||||
target: me.frm,
|
||||
setters: {
|
||||
company: me.frm.doc.company
|
||||
supplier: me.frm.doc.supplier
|
||||
},
|
||||
get_query_filters: {
|
||||
docstatus: 1,
|
||||
|
@ -54,11 +54,6 @@
|
||||
"items_section",
|
||||
"scan_barcode",
|
||||
"items",
|
||||
"section_break_48",
|
||||
"pricing_rules",
|
||||
"raw_material_details",
|
||||
"set_reserve_warehouse",
|
||||
"supplied_items",
|
||||
"sb_last_purchase",
|
||||
"total_qty",
|
||||
"base_total",
|
||||
@ -67,6 +62,11 @@
|
||||
"total_net_weight",
|
||||
"total",
|
||||
"net_total",
|
||||
"section_break_48",
|
||||
"pricing_rules",
|
||||
"raw_material_details",
|
||||
"set_reserve_warehouse",
|
||||
"supplied_items",
|
||||
"taxes_section",
|
||||
"tax_category",
|
||||
"column_break_50",
|
||||
@ -105,23 +105,25 @@
|
||||
"payment_schedule_section",
|
||||
"payment_terms_template",
|
||||
"payment_schedule",
|
||||
"tracking_section",
|
||||
"per_billed",
|
||||
"column_break_75",
|
||||
"per_received",
|
||||
"terms_section_break",
|
||||
"tc_name",
|
||||
"terms",
|
||||
"more_info",
|
||||
"status",
|
||||
"ref_sq",
|
||||
"column_break_74",
|
||||
"party_account_currency",
|
||||
"inter_company_order_reference",
|
||||
"column_break_74",
|
||||
"per_received",
|
||||
"per_billed",
|
||||
"column_break5",
|
||||
"letter_head",
|
||||
"select_print_heading",
|
||||
"column_break_86",
|
||||
"group_same_items",
|
||||
"language",
|
||||
"group_same_items",
|
||||
"subscription_section",
|
||||
"from_date",
|
||||
"to_date",
|
||||
@ -220,7 +222,7 @@
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "schedule_date",
|
||||
"fieldtype": "Date",
|
||||
"label": "Reqd By Date"
|
||||
"label": "Required By"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
@ -432,6 +434,7 @@
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"description": "Sets 'Warehouse' in each row of the Items table.",
|
||||
"fieldname": "set_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"label": "Set Target Warehouse",
|
||||
@ -827,6 +830,7 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "payment_schedule_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Payment Terms"
|
||||
@ -917,7 +921,8 @@
|
||||
"fieldname": "inter_company_order_reference",
|
||||
"fieldtype": "Link",
|
||||
"label": "Inter Company Order Reference",
|
||||
"options": "Sales Order"
|
||||
"options": "Sales Order",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_74",
|
||||
@ -930,8 +935,6 @@
|
||||
"in_list_view": 1,
|
||||
"label": "% Received",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "per_received",
|
||||
"oldfieldtype": "Currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@ -942,8 +945,6 @@
|
||||
"in_list_view": 1,
|
||||
"label": "% Billed",
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "per_billed",
|
||||
"oldfieldtype": "Currency",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
@ -998,6 +999,7 @@
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "subscription_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Subscription Section"
|
||||
@ -1050,13 +1052,23 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Set Reserve Warehouse",
|
||||
"options": "Warehouse"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "tracking_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Tracking"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_75",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-file-text",
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-17 13:04:28.185197",
|
||||
"modified": "2020-04-24 12:13:14.186280",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
|
@ -18,10 +18,6 @@
|
||||
"col_break1",
|
||||
"image",
|
||||
"image_view",
|
||||
"manufacture_details",
|
||||
"manufacturer",
|
||||
"column_break_14",
|
||||
"manufacturer_part_no",
|
||||
"quantity_and_rate",
|
||||
"qty",
|
||||
"stock_uom",
|
||||
@ -44,7 +40,6 @@
|
||||
"base_amount",
|
||||
"pricing_rules",
|
||||
"is_free_item",
|
||||
"is_fixed_asset",
|
||||
"section_break_29",
|
||||
"net_rate",
|
||||
"net_amount",
|
||||
@ -52,11 +47,6 @@
|
||||
"base_net_rate",
|
||||
"base_net_amount",
|
||||
"billed_amt",
|
||||
"item_weight_details",
|
||||
"weight_per_unit",
|
||||
"total_weight",
|
||||
"column_break_40",
|
||||
"weight_uom",
|
||||
"warehouse_and_reference",
|
||||
"warehouse",
|
||||
"delivered_by_supplier",
|
||||
@ -80,20 +70,31 @@
|
||||
"column_break_60",
|
||||
"received_qty",
|
||||
"returned_qty",
|
||||
"manufacture_details",
|
||||
"manufacturer",
|
||||
"column_break_14",
|
||||
"manufacturer_part_no",
|
||||
"more_info_section_break",
|
||||
"is_fixed_asset",
|
||||
"item_tax_rate",
|
||||
"accounting_details",
|
||||
"expense_account",
|
||||
"column_break_68",
|
||||
"item_weight_details",
|
||||
"weight_per_unit",
|
||||
"total_weight",
|
||||
"column_break_40",
|
||||
"weight_uom",
|
||||
"accounting_dimensions_section",
|
||||
"cost_center",
|
||||
"dimension_col_break",
|
||||
"section_break_72",
|
||||
"page_break",
|
||||
"item_tax_rate"
|
||||
"page_break"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"bold": 1,
|
||||
"columns": 3,
|
||||
"columns": 2,
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
@ -133,7 +134,7 @@
|
||||
"fieldname": "schedule_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Reqd By Date",
|
||||
"label": "Required By",
|
||||
"oldfieldname": "schedule_date",
|
||||
"oldfieldtype": "Date",
|
||||
"print_hide": 1,
|
||||
@ -216,15 +217,16 @@
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"columns": 1,
|
||||
"fieldname": "uom",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "UOM",
|
||||
"oldfieldname": "uom",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "UOM",
|
||||
"print_width": "100px",
|
||||
"reqd": 1,
|
||||
"width": "100px"
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "conversion_factor",
|
||||
@ -685,6 +687,7 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "manufacture_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Manufacture"
|
||||
@ -717,12 +720,17 @@
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Fixed Asset",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "more_info_section_break",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "More Information"
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-07 18:35:17.558928",
|
||||
"modified": "2020-04-21 11:55:58.643393",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order Item",
|
||||
|
@ -1,20 +1,26 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2013-02-22 01:27:42",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"main_item_code",
|
||||
"rm_item_code",
|
||||
"required_qty",
|
||||
"supplied_qty",
|
||||
"rate",
|
||||
"amount",
|
||||
"column_break_6",
|
||||
"bom_detail_no",
|
||||
"reference_name",
|
||||
"conversion_factor",
|
||||
"stock_uom",
|
||||
"reserve_warehouse"
|
||||
"conversion_factor",
|
||||
"column_break_6",
|
||||
"rm_item_code",
|
||||
"reference_name",
|
||||
"reserve_warehouse",
|
||||
"section_break2",
|
||||
"rate",
|
||||
"col_break2",
|
||||
"amount",
|
||||
"section_break1",
|
||||
"required_qty",
|
||||
"col_break1",
|
||||
"supplied_qty"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -120,15 +126,34 @@
|
||||
"in_list_view": 1,
|
||||
"label": "Supplied Qty",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break1",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "col_break1",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break2",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "col_break2",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-08-20 13:37:32.702068",
|
||||
"links": [],
|
||||
"modified": "2020-03-12 15:43:53.862897",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order Item Supplied",
|
||||
"owner": "dhanalekshmi@webnotestech.com",
|
||||
"permissions": []
|
||||
"permissions": [],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
@ -23,15 +23,11 @@ def get_data():
|
||||
},
|
||||
{
|
||||
'label': _('Payments'),
|
||||
'items': ['Payment Entry']
|
||||
},
|
||||
{
|
||||
'label': _('Bank'),
|
||||
'items': ['Bank Account']
|
||||
'items': ['Payment Entry', 'Bank Account']
|
||||
},
|
||||
{
|
||||
'label': _('Pricing'),
|
||||
'items': ['Pricing Rule']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -141,19 +141,18 @@ def get_conditions(filters):
|
||||
conditions = ""
|
||||
|
||||
if filters.get("company"):
|
||||
conditions += " AND company=%s"% frappe.db.escape(filters.get('company'))
|
||||
conditions += " AND par.company=%s" % frappe.db.escape(filters.get('company'))
|
||||
|
||||
if filters.get("cost_center") or filters.get("project"):
|
||||
conditions += """
|
||||
AND (cost_center=%s
|
||||
OR project=%s)
|
||||
"""% (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
|
||||
AND (child.`cost_center`=%s OR child.`project`=%s)
|
||||
""" % (frappe.db.escape(filters.get('cost_center')), frappe.db.escape(filters.get('project')))
|
||||
|
||||
if filters.get("from_date"):
|
||||
conditions += " AND transaction_date>=%s"% filters.get('from_date')
|
||||
conditions += " AND par.transaction_date>='%s'" % filters.get('from_date')
|
||||
|
||||
if filters.get("to_date"):
|
||||
conditions += " AND transaction_date<=%s"% filters.get('to_date')
|
||||
conditions += " AND par.transaction_date<='%s'" % filters.get('to_date')
|
||||
return conditions
|
||||
|
||||
def get_data(filters):
|
||||
@ -162,7 +161,6 @@ def get_data(filters):
|
||||
mr_records, procurement_record_against_mr = get_mapped_mr_details(conditions)
|
||||
pr_records = get_mapped_pr_records()
|
||||
pi_records = get_mapped_pi_records()
|
||||
print(pi_records)
|
||||
|
||||
procurement_record=[]
|
||||
if procurement_record_against_mr:
|
||||
@ -198,16 +196,16 @@ def get_mapped_mr_details(conditions):
|
||||
mr_records = {}
|
||||
mr_details = frappe.db.sql("""
|
||||
SELECT
|
||||
mr.transaction_date,
|
||||
mr.per_ordered,
|
||||
mr_item.name,
|
||||
mr_item.parent,
|
||||
mr_item.amount
|
||||
FROM `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
|
||||
par.transaction_date,
|
||||
par.per_ordered,
|
||||
child.name,
|
||||
child.parent,
|
||||
child.amount
|
||||
FROM `tabMaterial Request` par, `tabMaterial Request Item` child
|
||||
WHERE
|
||||
mr.per_ordered>=0
|
||||
AND mr.name=mr_item.parent
|
||||
AND mr.docstatus=1
|
||||
par.per_ordered>=0
|
||||
AND par.name=child.parent
|
||||
AND par.docstatus=1
|
||||
{conditions}
|
||||
""".format(conditions=conditions), as_dict=1) #nosec
|
||||
|
||||
@ -254,29 +252,29 @@ def get_mapped_pr_records():
|
||||
def get_po_entries(conditions):
|
||||
return frappe.db.sql("""
|
||||
SELECT
|
||||
po_item.name,
|
||||
po_item.parent,
|
||||
po_item.cost_center,
|
||||
po_item.project,
|
||||
po_item.warehouse,
|
||||
po_item.material_request,
|
||||
po_item.material_request_item,
|
||||
po_item.description,
|
||||
po_item.stock_uom,
|
||||
po_item.qty,
|
||||
po_item.amount,
|
||||
po_item.base_amount,
|
||||
po_item.schedule_date,
|
||||
po.transaction_date,
|
||||
po.supplier,
|
||||
po.status,
|
||||
po.owner
|
||||
FROM `tabPurchase Order` po, `tabPurchase Order Item` po_item
|
||||
child.name,
|
||||
child.parent,
|
||||
child.cost_center,
|
||||
child.project,
|
||||
child.warehouse,
|
||||
child.material_request,
|
||||
child.material_request_item,
|
||||
child.description,
|
||||
child.stock_uom,
|
||||
child.qty,
|
||||
child.amount,
|
||||
child.base_amount,
|
||||
child.schedule_date,
|
||||
par.transaction_date,
|
||||
par.supplier,
|
||||
par.status,
|
||||
par.owner
|
||||
FROM `tabPurchase Order` par, `tabPurchase Order Item` child
|
||||
WHERE
|
||||
po.docstatus = 1
|
||||
AND po.name = po_item.parent
|
||||
AND po.status not in ("Closed","Completed","Cancelled")
|
||||
par.docstatus = 1
|
||||
AND par.name = child.parent
|
||||
AND par.status not in ("Closed","Completed","Cancelled")
|
||||
{conditions}
|
||||
GROUP BY
|
||||
po.name,po_item.item_code
|
||||
par.name, child.item_code
|
||||
""".format(conditions=conditions), as_dict=1) #nosec
|
@ -214,5 +214,41 @@ def get_data():
|
||||
"label": _("Lab Test Report")
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": _("Rehabilitation"),
|
||||
"icon": "icon-cog",
|
||||
"items": [
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Exercise Type",
|
||||
"label": _("Exercise Type")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Exercise Difficulty Level",
|
||||
"label": _("Exercise Difficulty Level")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Therapy Type",
|
||||
"label": _("Therapy Type")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Therapy Plan",
|
||||
"label": _("Therapy Plan")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Therapy Session",
|
||||
"label": _("Therapy Session")
|
||||
},
|
||||
{
|
||||
"type": "doctype",
|
||||
"name": "Motor Assessment Scale",
|
||||
"label": _("Motor Assessment Scale")
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -819,7 +819,7 @@ class AccountsController(TransactionBase):
|
||||
else:
|
||||
for d in self.get("payment_schedule"):
|
||||
if d.invoice_portion:
|
||||
d.payment_amount = grand_total * flt(d.invoice_portion) / 100
|
||||
d.payment_amount = flt(grand_total * flt(d.invoice_portion) / 100, d.precision('payment_amount'))
|
||||
|
||||
def set_due_date(self):
|
||||
due_dates = [d.due_date for d in self.get("payment_schedule") if d.due_date]
|
||||
|
@ -371,6 +371,19 @@ def get_account_list(doctype, txt, searchfield, start, page_len, filters):
|
||||
fields = ["name", "parent_account"],
|
||||
limit_start=start, limit_page_length=page_len, as_list=True)
|
||||
|
||||
def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
|
||||
return frappe.db.sql("""select distinct bo.name, bo.blanket_order_type, bo.to_date
|
||||
from `tabBlanket Order` bo, `tabBlanket Order Item` boi
|
||||
where
|
||||
boi.parent = bo.name
|
||||
and boi.item_code = {item_code}
|
||||
and bo.blanket_order_type = '{blanket_order_type}'
|
||||
and bo.company = {company}
|
||||
and bo.docstatus = 1"""
|
||||
.format(item_code = frappe.db.escape(filters.get("item")),
|
||||
blanket_order_type = filters.get("blanket_order_type"),
|
||||
company = frappe.db.escape(filters.get("company"))
|
||||
))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_income_account(doctype, txt, searchfield, start, page_len, filters):
|
||||
|
@ -46,6 +46,7 @@ class SellingController(StockController):
|
||||
set_default_income_account_for_item(self)
|
||||
self.set_customer_address()
|
||||
self.validate_for_duplicate_items()
|
||||
self.validate_target_warehouse()
|
||||
|
||||
def set_missing_values(self, for_validate=False):
|
||||
|
||||
@ -403,6 +404,14 @@ class SellingController(StockController):
|
||||
else:
|
||||
chk_dupl_itm.append(f)
|
||||
|
||||
def validate_target_warehouse(self):
|
||||
items = self.get("items") + (self.get("packed_items") or [])
|
||||
|
||||
for d in items:
|
||||
if d.get("target_warehouse") and d.get("warehouse") == d.get("target_warehouse"):
|
||||
warehouse = frappe.bold(d.get("target_warehouse"))
|
||||
frappe.throw(_("Row {0}: Delivery Warehouse ({1}) and Customer Warehouse ({2}) can not be same")
|
||||
.format(d.idx, warehouse, warehouse))
|
||||
|
||||
def validate_items(self):
|
||||
# validate items to see if they have is_sales_item enabled
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
from frappe.utils import cint, flt, cstr
|
||||
from frappe.utils import cint, flt, cstr, get_link_to_form, today, getdate
|
||||
from frappe import _
|
||||
import frappe.defaults
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
@ -55,6 +55,13 @@ class StockController(AccountsController):
|
||||
frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
|
||||
.format(d.idx, serial_no_data.name, d.batch_no))
|
||||
|
||||
if d.qty > 0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
|
||||
expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date")
|
||||
|
||||
if expiry_date and getdate(expiry_date) < getdate(self.posting_date):
|
||||
frappe.throw(_("Row #{0}: The batch {1} has already expired.")
|
||||
.format(d.idx, get_link_to_form("Batch", d.get("batch_no"))))
|
||||
|
||||
def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
|
||||
default_cost_center=None):
|
||||
|
||||
|
@ -13,7 +13,7 @@ class TestMapper(unittest.TestCase):
|
||||
'''Test mapping of multiple source docs on a single target doc'''
|
||||
|
||||
make_test_records("Item")
|
||||
items = frappe.get_all("Item", fields = ["name", "item_code"], filters = {'is_sales_item': 1, 'has_variants': 0})
|
||||
items = frappe.get_all("Item", fields = ["name", "item_code"], filters = {'is_sales_item': 1, 'has_variants': 0, 'disabled': 0})
|
||||
customers = frappe.get_all("Customer")
|
||||
if items and customers:
|
||||
# Make source docs (quotations) and a target doc (sales order)
|
||||
|
@ -12,13 +12,18 @@
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Settings",
|
||||
"links": "[\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Sales Person Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Sales Person\",\n \"link\": \"Tree/Sales Person\",\n \"name\": \"Sales Person\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sales campaigns.\",\n \"label\": \"Campaign\",\n \"name\": \"Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n \"label\": \"Email Campaign\",\n \"name\": \"Email Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Send mass SMS to your contacts\",\n \"label\": \"SMS Center\",\n \"name\": \"SMS Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Logs for maintaining sms delivery status\",\n \"label\": \"SMS Log\",\n \"name\": \"SMS Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup SMS gateway settings\",\n \"label\": \"SMS Settings\",\n \"name\": \"SMS Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n }\n]"
|
||||
"label": "Maintenance",
|
||||
"links": "[\n {\n \"description\": \"Plan for maintenance visits.\",\n \"label\": \"Maintenance Schedule\",\n \"name\": \"Maintenance Schedule\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Visit report for maintenance call.\",\n \"label\": \"Maintenance Visit\",\n \"name\": \"Maintenance Visit\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Warranty Claim against Serial No.\",\n \"label\": \"Warranty Claim\",\n \"name\": \"Warranty Claim\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Maintenance",
|
||||
"links": "[\n {\n \"description\": \"Plan for maintenance visits.\",\n \"label\": \"Maintenance Schedule\",\n \"name\": \"Maintenance Schedule\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Visit report for maintenance call.\",\n \"label\": \"Maintenance Visit\",\n \"name\": \"Maintenance Visit\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Warranty Claim against Serial No.\",\n \"label\": \"Warranty Claim\",\n \"name\": \"Warranty Claim\",\n \"type\": \"doctype\"\n }\n]"
|
||||
"label": "Campaign",
|
||||
"links": "[\n {\n \"description\": \"Sales campaigns.\",\n \"label\": \"Campaign\",\n \"name\": \"Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Sends Mails to lead or contact based on a Campaign schedule\",\n \"label\": \"Email Campaign\",\n \"name\": \"Email Campaign\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Create and Schedule social media posts\",\n \"label\": \"Social Media Post\",\n \"name\": \"Social Media Post\",\n \"type\": \"doctype\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Settings",
|
||||
"links": "[\n {\n \"description\": \"Manage Customer Group Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Customer Group\",\n \"link\": \"Tree/Customer Group\",\n \"name\": \"Customer Group\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Territory Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Territory\",\n \"link\": \"Tree/Territory\",\n \"name\": \"Territory\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Manage Sales Person Tree.\",\n \"icon\": \"fa fa-sitemap\",\n \"label\": \"Sales Person\",\n \"link\": \"Tree/Sales Person\",\n \"name\": \"Sales Person\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Send mass SMS to your contacts\",\n \"label\": \"SMS Center\",\n \"name\": \"SMS Center\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Logs for maintaining sms delivery status\",\n \"label\": \"SMS Log\",\n \"name\": \"SMS Log\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Setup SMS gateway settings\",\n \"label\": \"SMS Settings\",\n \"name\": \"SMS Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Email Group\",\n \"name\": \"Email Group\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Twitter Settings\",\n \"name\": \"Twitter Settings\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"LinkedIn Settings\",\n \"name\": \"LinkedIn Settings\",\n \"type\": \"doctype\"\n }\n]"
|
||||
}
|
||||
],
|
||||
"category": "Modules",
|
||||
@ -33,7 +38,7 @@
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "CRM",
|
||||
"modified": "2020-04-01 11:28:51.219999",
|
||||
"modified": "2020-04-27 22:32:26.682911",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "CRM",
|
||||
@ -42,7 +47,7 @@
|
||||
"pin_to_top": 0,
|
||||
"shortcuts": [
|
||||
{
|
||||
"format": "Open",
|
||||
"format": "{} Open",
|
||||
"label": "Lead",
|
||||
"link_to": "Lead",
|
||||
"stats_filter": "{\"status\":\"Open\"}",
|
||||
|
@ -27,7 +27,7 @@ class EmailCampaign(Document):
|
||||
for entry in campaign.get("campaign_schedules"):
|
||||
send_after_days.append(entry.send_after_days)
|
||||
try:
|
||||
end_date = add_days(getdate(self.start_date), max(send_after_days))
|
||||
self.end_date = add_days(getdate(self.start_date), max(send_after_days))
|
||||
except ValueError:
|
||||
frappe.throw(_("Please set up the Campaign Schedule in the Campaign {0}").format(self.campaign_name))
|
||||
|
||||
|
0
erpnext/crm/doctype/linkedin_settings/__init__.py
Normal file
0
erpnext/crm/doctype/linkedin_settings/__init__.py
Normal file
71
erpnext/crm/doctype/linkedin_settings/linkedin_settings.js
Normal file
71
erpnext/crm/doctype/linkedin_settings/linkedin_settings.js
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LinkedIn Settings', {
|
||||
onload: function(frm){
|
||||
if (frm.doc.session_status == 'Expired' && frm.doc.consumer_key && frm.doc.consumer_secret){
|
||||
frappe.confirm(
|
||||
__('Session not valid, Do you want to login?'),
|
||||
function(){
|
||||
frm.trigger("login");
|
||||
},
|
||||
function(){
|
||||
window.close();
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
refresh: function(frm){
|
||||
if (frm.doc.session_status=="Expired"){
|
||||
let msg = __("Session Not Active. Save doc to login.");
|
||||
frm.dashboard.set_headline_alert(
|
||||
`<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<span class="indicator whitespace-nowrap red"><span class="hidden-xs">${msg}</span></span>
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
|
||||
if (frm.doc.session_status=="Active"){
|
||||
let d = new Date(frm.doc.modified);
|
||||
d.setDate(d.getDate()+60);
|
||||
let dn = new Date();
|
||||
let days = d.getTime() - dn.getTime();
|
||||
days = Math.floor(days/(1000 * 3600 * 24));
|
||||
let msg,color;
|
||||
|
||||
if (days>0){
|
||||
msg = __("Your Session will be expire in ") + days + __(" days.");
|
||||
color = "green";
|
||||
}
|
||||
else {
|
||||
msg = __("Session is expired. Save doc to login.");
|
||||
color = "red";
|
||||
}
|
||||
|
||||
frm.dashboard.set_headline_alert(
|
||||
`<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">${msg}</span></span>
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
},
|
||||
login: function(frm){
|
||||
if (frm.doc.consumer_key && frm.doc.consumer_secret){
|
||||
frappe.dom.freeze();
|
||||
frappe.call({
|
||||
doc: frm.doc,
|
||||
method: "get_authorization_url",
|
||||
callback : function(r) {
|
||||
window.location.href = r.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
after_save: function(frm){
|
||||
frm.trigger("login");
|
||||
}
|
||||
});
|
111
erpnext/crm/doctype/linkedin_settings/linkedin_settings.json
Normal file
111
erpnext/crm/doctype/linkedin_settings/linkedin_settings.json
Normal file
@ -0,0 +1,111 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-01-30 13:36:39.492931",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"account_name",
|
||||
"column_break_2",
|
||||
"company_id",
|
||||
"oauth_details",
|
||||
"consumer_key",
|
||||
"column_break_5",
|
||||
"consumer_secret",
|
||||
"user_details_section",
|
||||
"access_token",
|
||||
"person_urn",
|
||||
"session_status"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "account_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Account Name",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "oauth_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "OAuth Credentials"
|
||||
},
|
||||
{
|
||||
"fieldname": "consumer_key",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Consumer Key",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "consumer_secret",
|
||||
"fieldtype": "Password",
|
||||
"in_list_view": 1,
|
||||
"label": "Consumer Secret",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "access_token",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Access Token",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "person_urn",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Person URN",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "user_details_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "User Details"
|
||||
},
|
||||
{
|
||||
"fieldname": "session_status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"label": "Session Status",
|
||||
"options": "Expired\nActive",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_2",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "company_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Company ID",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-16 23:22:51.966397",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "LinkedIn Settings",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
166
erpnext/crm/doctype/linkedin_settings/linkedin_settings.py
Normal file
166
erpnext/crm/doctype/linkedin_settings/linkedin_settings.py
Normal file
@ -0,0 +1,166 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, requests, json
|
||||
from frappe import _
|
||||
from frappe.utils import get_site_url, get_url_to_form, get_link_to_form
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils.file_manager import get_file, get_file_path
|
||||
from six.moves.urllib.parse import urlencode
|
||||
|
||||
class LinkedInSettings(Document):
|
||||
def get_authorization_url(self):
|
||||
params = urlencode({
|
||||
"response_type":"code",
|
||||
"client_id": self.consumer_key,
|
||||
"redirect_uri": get_site_url(frappe.local.site) + "/?cmd=erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback",
|
||||
"scope": "r_emailaddress w_organization_social r_basicprofile r_liteprofile r_organization_social rw_organization_admin w_member_social"
|
||||
})
|
||||
|
||||
url = "https://www.linkedin.com/oauth/v2/authorization?{}".format(params)
|
||||
|
||||
return url
|
||||
|
||||
def get_access_token(self, code):
|
||||
url = "https://www.linkedin.com/oauth/v2/accessToken"
|
||||
body = {
|
||||
"grant_type": "authorization_code",
|
||||
"code": code,
|
||||
"client_id": self.consumer_key,
|
||||
"client_secret": self.get_password(fieldname="consumer_secret"),
|
||||
"redirect_uri": get_site_url(frappe.local.site) + "/?cmd=erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback",
|
||||
}
|
||||
headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
|
||||
response = self.http_post(url=url, data=body, headers=headers)
|
||||
response = frappe.parse_json(response.content.decode())
|
||||
self.db_set("access_token", response["access_token"])
|
||||
|
||||
def get_member_profile(self):
|
||||
headers = {
|
||||
"Authorization": "Bearer {}".format(self.access_token)
|
||||
}
|
||||
url = "https://api.linkedin.com/v2/me"
|
||||
response = requests.get(url=url, headers=headers)
|
||||
response = frappe.parse_json(response.content.decode())
|
||||
|
||||
frappe.db.set_value(self.doctype, self.name, {
|
||||
"person_urn": response["id"],
|
||||
"account_name": response["vanityName"],
|
||||
"session_status": "Active"
|
||||
})
|
||||
frappe.local.response["type"] = "redirect"
|
||||
frappe.local.response["location"] = get_url_to_form("LinkedIn Settings","LinkedIn Settings")
|
||||
|
||||
def post(self, text, media=None):
|
||||
if not media:
|
||||
return self.post_text(text)
|
||||
else:
|
||||
media_id = self.upload_image(media)
|
||||
|
||||
if media_id:
|
||||
return self.post_text(text, media_id=media_id)
|
||||
else:
|
||||
frappe.log_error("Failed to upload media.","LinkedIn Upload Error")
|
||||
|
||||
|
||||
def upload_image(self, media):
|
||||
media = get_file_path(media)
|
||||
register_url = "https://api.linkedin.com/v2/assets?action=registerUpload"
|
||||
body = {
|
||||
"registerUploadRequest": {
|
||||
"recipes": ["urn:li:digitalmediaRecipe:feedshare-image"],
|
||||
"owner": "urn:li:organization:{0}".format(self.company_id),
|
||||
"serviceRelationships": [{
|
||||
"relationshipType": "OWNER",
|
||||
"identifier": "urn:li:userGeneratedContent"
|
||||
}]
|
||||
}
|
||||
}
|
||||
headers = {
|
||||
"Authorization": "Bearer {}".format(self.access_token)
|
||||
}
|
||||
response = self.http_post(url=register_url, body=body, headers=headers)
|
||||
|
||||
if response.status_code == 200:
|
||||
response = response.json()
|
||||
asset = response["value"]["asset"]
|
||||
upload_url = response["value"]["uploadMechanism"]["com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest"]["uploadUrl"]
|
||||
headers['Content-Type']='image/jpeg'
|
||||
response = self.http_post(upload_url, headers=headers, data=open(media,"rb"))
|
||||
if response.status_code < 200 and response.status_code > 299:
|
||||
frappe.throw(_("Error While Uploading Image"), title="{0} {1}".format(response.status_code, response.reason))
|
||||
return None
|
||||
return asset
|
||||
|
||||
return None
|
||||
|
||||
def post_text(self, text, media_id=None):
|
||||
url = "https://api.linkedin.com/v2/shares"
|
||||
headers = {
|
||||
"X-Restli-Protocol-Version": "2.0.0",
|
||||
"Authorization": "Bearer {}".format(self.access_token),
|
||||
"Content-Type": "application/json; charset=UTF-8"
|
||||
}
|
||||
body = {
|
||||
"distribution": {
|
||||
"linkedInDistributionTarget": {}
|
||||
},
|
||||
"owner":"urn:li:organization:{0}".format(self.company_id),
|
||||
"subject": "Test Share Subject",
|
||||
"text": {
|
||||
"text": text
|
||||
}
|
||||
}
|
||||
|
||||
if media_id:
|
||||
body["content"]= {
|
||||
"contentEntities": [{
|
||||
"entity": media_id
|
||||
}],
|
||||
"shareMediaCategory": "IMAGE"
|
||||
}
|
||||
|
||||
response = self.http_post(url=url, headers=headers, body=body)
|
||||
return response
|
||||
|
||||
def http_post(self, url, headers=None, body=None, data=None):
|
||||
try:
|
||||
response = requests.post(
|
||||
url = url,
|
||||
json = body,
|
||||
data = data,
|
||||
headers = headers
|
||||
)
|
||||
if response.status_code not in [201,200]:
|
||||
raise
|
||||
|
||||
except Exception as e:
|
||||
content = json.loads(response.content)
|
||||
|
||||
if response.status_code == 401:
|
||||
self.db_set("session_status", "Expired")
|
||||
frappe.db.commit()
|
||||
frappe.throw(content["message"], title="LinkedIn Error - Unauthorized")
|
||||
elif response.status_code == 403:
|
||||
frappe.msgprint(_("You Didn't have permission to access this API"))
|
||||
frappe.throw(content["message"], title="LinkedIn Error - Access Denied")
|
||||
else:
|
||||
frappe.throw(response.reason, title=response.status_code)
|
||||
|
||||
return response
|
||||
|
||||
@frappe.whitelist()
|
||||
def callback(code=None, error=None, error_description=None):
|
||||
if not error:
|
||||
linkedin_settings = frappe.get_doc("LinkedIn Settings")
|
||||
linkedin_settings.get_access_token(code)
|
||||
linkedin_settings.get_member_profile()
|
||||
frappe.db.commit()
|
||||
else:
|
||||
frappe.local.response["type"] = "redirect"
|
||||
frappe.local.response["location"] = get_url_to_form("LinkedIn Settings","LinkedIn Settings")
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestLinkedInSettings(unittest.TestCase):
|
||||
pass
|
0
erpnext/crm/doctype/social_media_post/__init__.py
Normal file
0
erpnext/crm/doctype/social_media_post/__init__.py
Normal file
67
erpnext/crm/doctype/social_media_post/social_media_post.js
Normal file
67
erpnext/crm/doctype/social_media_post/social_media_post.js
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
frappe.ui.form.on('Social Media Post', {
|
||||
validate: function(frm){
|
||||
if (frm.doc.twitter === 0 && frm.doc.linkedin === 0){
|
||||
frappe.throw(__("Select atleast one Social Media from Share on."))
|
||||
}
|
||||
if (frm.doc.scheduled_time) {
|
||||
let scheduled_time = new Date(frm.doc.scheduled_time);
|
||||
let date_time = new Date();
|
||||
if (scheduled_time.getTime() < date_time.getTime()){
|
||||
frappe.throw(__("Invalid Scheduled Time"));
|
||||
}
|
||||
}
|
||||
if (frm.doc.text?.length > 280){
|
||||
frappe.throw(__("Length Must be less than 280."))
|
||||
}
|
||||
},
|
||||
refresh: function(frm){
|
||||
if (frm.doc.docstatus === 1){
|
||||
if (frm.doc.post_status != "Posted"){
|
||||
add_post_btn(frm);
|
||||
}
|
||||
else if (frm.doc.post_status == "Posted"){
|
||||
frm.set_df_property('sheduled_time', 'read_only', 1);
|
||||
}
|
||||
|
||||
let html='';
|
||||
if (frm.doc.twitter){
|
||||
let color = frm.doc.twitter_post_id ? "green" : "red";
|
||||
let status = frm.doc.twitter_post_id ? "Posted" : "Not Posted";
|
||||
html += `<div class="col-xs-6">
|
||||
<span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">Twitter : ${status} </span></span>
|
||||
</div>` ;
|
||||
}
|
||||
if (frm.doc.linkedin){
|
||||
let color = frm.doc.linkedin_post_id ? "green" : "red";
|
||||
let status = frm.doc.linkedin_post_id ? "Posted" : "Not Posted";
|
||||
html += `<div class="col-xs-6">
|
||||
<span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">LinkedIn : ${status} </span></span>
|
||||
</div>` ;
|
||||
}
|
||||
html = `<div class="row">${html}</div>`;
|
||||
frm.dashboard.set_headline_alert(html);
|
||||
}
|
||||
}
|
||||
});
|
||||
var add_post_btn = function(frm){
|
||||
frm.add_custom_button(('Post Now'), function(){
|
||||
post(frm);
|
||||
});
|
||||
}
|
||||
var post = function(frm){
|
||||
frappe.dom.freeze();
|
||||
frappe.call({
|
||||
method: "erpnext.crm.doctype.social_media_post.social_media_post.publish",
|
||||
args: {
|
||||
doctype: frm.doc.doctype,
|
||||
name: frm.doc.name
|
||||
},
|
||||
callback: function(r) {
|
||||
frm.reload_doc();
|
||||
frappe.dom.unfreeze();
|
||||
}
|
||||
})
|
||||
|
||||
}
|
166
erpnext/crm/doctype/social_media_post/social_media_post.json
Normal file
166
erpnext/crm/doctype/social_media_post/social_media_post.json
Normal file
@ -0,0 +1,166 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "format: CRM-SMP-{YYYY}-{MM}-{DD}-{###}",
|
||||
"creation": "2020-01-30 11:53:13.872864",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"campaign_name",
|
||||
"scheduled_time",
|
||||
"post_status",
|
||||
"column_break_6",
|
||||
"twitter",
|
||||
"linkedin",
|
||||
"twitter_post_id",
|
||||
"linkedin_post_id",
|
||||
"content",
|
||||
"text",
|
||||
"column_break_14",
|
||||
"tweet_preview",
|
||||
"linkedin_section",
|
||||
"linkedin_post",
|
||||
"column_break_15",
|
||||
"attachments_section",
|
||||
"image",
|
||||
"amended_from"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "text",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Tweet",
|
||||
"mandatory_depends_on": "eval:doc.twitter ==1"
|
||||
},
|
||||
{
|
||||
"fieldname": "image",
|
||||
"fieldtype": "Attach Image",
|
||||
"label": "Image"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "twitter",
|
||||
"fieldtype": "Check",
|
||||
"label": "Twitter"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "linkedin",
|
||||
"fieldtype": "Check",
|
||||
"label": "LinkedIn"
|
||||
},
|
||||
{
|
||||
"fieldname": "amended_from",
|
||||
"fieldtype": "Link",
|
||||
"label": "Amended From",
|
||||
"no_copy": 1,
|
||||
"options": "Social Media Post",
|
||||
"print_hide": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.twitter ==1",
|
||||
"fieldname": "content",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Twitter"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "post_status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Post Status",
|
||||
"options": "\nScheduled\nPosted\nError",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "twitter_post_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "Twitter Post Id",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "linkedin_post_id",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "LinkedIn Post Id",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "campaign_name",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Campaign",
|
||||
"options": "Campaign"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break",
|
||||
"label": "Share On"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_14",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "tweet_preview",
|
||||
"fieldtype": "HTML"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"depends_on": "eval:doc.linkedin==1",
|
||||
"fieldname": "linkedin_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "LinkedIn"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "attachments_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Attachments"
|
||||
},
|
||||
{
|
||||
"fieldname": "linkedin_post",
|
||||
"fieldtype": "Text",
|
||||
"label": "Post",
|
||||
"mandatory_depends_on": "eval:doc.linkedin ==1"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_15",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 1,
|
||||
"fieldname": "scheduled_time",
|
||||
"fieldtype": "Datetime",
|
||||
"label": "Scheduled Time",
|
||||
"read_only_depends_on": "eval:doc.post_status == \"Posted\""
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-21 15:10:04.953713",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Social Media Post",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
56
erpnext/crm/doctype/social_media_post/social_media_post.py
Normal file
56
erpnext/crm/doctype/social_media_post/social_media_post.py
Normal file
@ -0,0 +1,56 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, 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
|
||||
from frappe import _
|
||||
import datetime
|
||||
|
||||
class SocialMediaPost(Document):
|
||||
def validate(self):
|
||||
if self.scheduled_time:
|
||||
current_time = frappe.utils.now_datetime()
|
||||
scheduled_time = frappe.utils.get_datetime(self.scheduled_time)
|
||||
if scheduled_time < current_time:
|
||||
frappe.throw(_("Invalid Scheduled Time"))
|
||||
|
||||
def submit(self):
|
||||
if self.scheduled_time:
|
||||
self.post_status = "Scheduled"
|
||||
super(SocialMediaPost, self).submit()
|
||||
|
||||
def post(self):
|
||||
try:
|
||||
if self.twitter and not self.twitter_post_id:
|
||||
twitter = frappe.get_doc("Twitter Settings")
|
||||
twitter_post = twitter.post(self.text, self.image)
|
||||
self.db_set("twitter_post_id", twitter_post.id)
|
||||
if self.linkedin and not self.linkedin_post_id:
|
||||
linkedin = frappe.get_doc("LinkedIn Settings")
|
||||
linkedin_post = linkedin.post(self.linkedin_post, self.image)
|
||||
self.db_set("linkedin_post_id", linkedin_post.headers['X-RestLi-Id'].split(":")[-1])
|
||||
self.db_set("post_status", "Posted")
|
||||
|
||||
except:
|
||||
self.db_set("post_status", "Error")
|
||||
title = _("Error while POSTING {0}").format(self.name)
|
||||
traceback = frappe.get_traceback()
|
||||
frappe.log_error(message=traceback , title=title)
|
||||
|
||||
def process_scheduled_social_media_posts():
|
||||
posts = frappe.get_list("Social Media Post", filters={"post_status": "Scheduled", "docstatus":1}, fields= ["name", "scheduled_time","post_status"])
|
||||
start = frappe.utils.now_datetime()
|
||||
end = start + datetime.timedelta(minutes=10)
|
||||
for post in posts:
|
||||
if post.scheduled_time:
|
||||
post_time = frappe.utils.get_datetime(post.scheduled_time)
|
||||
if post_time > start and post_time <= end:
|
||||
publish('Social Media Post', post.name)
|
||||
|
||||
@frappe.whitelist()
|
||||
def publish(doctype, name):
|
||||
sm_post = frappe.get_doc(doctype, name)
|
||||
sm_post.post()
|
||||
frappe.db.commit()
|
@ -0,0 +1,10 @@
|
||||
frappe.listview_settings['Social Media Post'] = {
|
||||
add_fields: ["status","post_status"],
|
||||
get_indicator: function(doc) {
|
||||
return [__(doc.post_status), {
|
||||
"Scheduled": "orange",
|
||||
"Posted": "green",
|
||||
"Error": "red"
|
||||
}[doc.post_status]];
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestSocialMediaPost(unittest.TestCase):
|
||||
pass
|
0
erpnext/crm/doctype/twitter_settings/__init__.py
Normal file
0
erpnext/crm/doctype/twitter_settings/__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestTwitterSettings(unittest.TestCase):
|
||||
pass
|
56
erpnext/crm/doctype/twitter_settings/twitter_settings.js
Normal file
56
erpnext/crm/doctype/twitter_settings/twitter_settings.js
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Twitter Settings', {
|
||||
onload: function(frm){
|
||||
if (frm.doc.session_status == 'Expired' && frm.doc.consumer_key && frm.doc.consumer_secret){
|
||||
frappe.confirm(
|
||||
__('Session not valid, Do you want to login?'),
|
||||
function(){
|
||||
frm.trigger("login");
|
||||
},
|
||||
function(){
|
||||
window.close();
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
refresh: function(frm){
|
||||
let msg, color, flag=false;
|
||||
if (frm.doc.session_status == "Active"){
|
||||
msg = __("Session Active");
|
||||
color = 'green';
|
||||
flag = true;
|
||||
}
|
||||
else if(frm.doc.consumer_key && frm.doc.consumer_secret) {
|
||||
msg = __("Session Not Active. Save doc to login.");
|
||||
color = 'red';
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (flag){
|
||||
frm.dashboard.set_headline_alert(
|
||||
`<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<span class="indicator whitespace-nowrap ${color}"><span class="hidden-xs">${msg}</span></span>
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
},
|
||||
login: function(frm){
|
||||
if (frm.doc.consumer_key && frm.doc.consumer_secret){
|
||||
frappe.dom.freeze();
|
||||
frappe.call({
|
||||
doc: frm.doc,
|
||||
method: "get_authorize_url",
|
||||
callback : function(r) {
|
||||
window.location.href = r.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
after_save: function(frm){
|
||||
frm.trigger("login");
|
||||
}
|
||||
});
|
101
erpnext/crm/doctype/twitter_settings/twitter_settings.json
Normal file
101
erpnext/crm/doctype/twitter_settings/twitter_settings.json
Normal file
@ -0,0 +1,101 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-01-30 10:29:08.562108",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"account_name",
|
||||
"profile_pic",
|
||||
"oauth_details",
|
||||
"consumer_key",
|
||||
"column_break_5",
|
||||
"consumer_secret",
|
||||
"oauth_token",
|
||||
"oauth_secret",
|
||||
"session_status"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "account_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Account Name",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "oauth_details",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "OAuth Credentials"
|
||||
},
|
||||
{
|
||||
"fieldname": "consumer_key",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "API Key",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "consumer_secret",
|
||||
"fieldtype": "Password",
|
||||
"in_list_view": 1,
|
||||
"label": "API Secret Key",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "oauth_token",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"label": "OAuth Token",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "oauth_secret",
|
||||
"fieldtype": "Password",
|
||||
"hidden": 1,
|
||||
"label": "OAuth Token Secret",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_5",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "profile_pic",
|
||||
"fieldtype": "Attach Image",
|
||||
"hidden": 1,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "session_status",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 1,
|
||||
"label": "Session Status",
|
||||
"options": "Expired\nActive",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"image_field": "profile_pic",
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-21 22:06:43.726798",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Twitter Settings",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
98
erpnext/crm/doctype/twitter_settings/twitter_settings.py
Normal file
98
erpnext/crm/doctype/twitter_settings/twitter_settings.py
Normal file
@ -0,0 +1,98 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, os, tweepy, json
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils.file_manager import get_file_path
|
||||
from frappe.utils import get_url_to_form, get_link_to_form
|
||||
from tweepy.error import TweepError
|
||||
|
||||
class TwitterSettings(Document):
|
||||
def get_authorize_url(self):
|
||||
callback_url = "{0}/?cmd=erpnext.crm.doctype.twitter_settings.twitter_settings.callback".format(frappe.utils.get_url())
|
||||
auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"), callback_url)
|
||||
|
||||
try:
|
||||
redirect_url = auth.get_authorization_url()
|
||||
return redirect_url
|
||||
except:
|
||||
frappe.msgprint(_("Error! Failed to get request token."))
|
||||
frappe.throw(_('Invalid {0} or {1}').format(frappe.bold("Consumer Key"), frappe.bold("Consumer Secret Key")))
|
||||
|
||||
|
||||
def get_access_token(self, oauth_token, oauth_verifier):
|
||||
auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"))
|
||||
auth.request_token = {
|
||||
'oauth_token' : oauth_token,
|
||||
'oauth_token_secret' : oauth_verifier
|
||||
}
|
||||
|
||||
try:
|
||||
auth.get_access_token(oauth_verifier)
|
||||
api = self.get_api()
|
||||
user = api.me()
|
||||
profile_pic = (user._json["profile_image_url"]).replace("_normal","")
|
||||
|
||||
frappe.db.set_value(self.doctype, self.name, {
|
||||
"oauth_token" : auth.access_token,
|
||||
"oauth_secret" : auth.access_token_secret,
|
||||
"account_name" : user._json["screen_name"],
|
||||
"profile_pic" : profile_pic,
|
||||
"session_status" : "Active"
|
||||
})
|
||||
|
||||
frappe.local.response["type"] = "redirect"
|
||||
frappe.local.response["location"] = get_url_to_form("Twitter Settings","Twitter Settings")
|
||||
except TweepError as e:
|
||||
frappe.msgprint(_("Error! Failed to get access token."))
|
||||
frappe.throw(_('Invalid Consumer Key or Consumer Secret Key'))
|
||||
|
||||
def get_api(self):
|
||||
# authentication of consumer key and secret
|
||||
auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"))
|
||||
# authentication of access token and secret
|
||||
auth.set_access_token(self.oauth_token, self.get_password(fieldname="oauth_secret"))
|
||||
|
||||
return tweepy.API(auth)
|
||||
|
||||
def post(self, text, media=None):
|
||||
if not media:
|
||||
return self.send_tweet(text)
|
||||
|
||||
if media:
|
||||
media_id = self.upload_image(media)
|
||||
return self.send_tweet(text, media_id)
|
||||
|
||||
def upload_image(self, media):
|
||||
media = get_file_path(media)
|
||||
api = self.get_api()
|
||||
media = api.media_upload(media)
|
||||
|
||||
return media.media_id
|
||||
|
||||
def send_tweet(self, text, media_id=None):
|
||||
api = self.get_api()
|
||||
try:
|
||||
if media_id:
|
||||
response = api.update_status(status = text, media_ids = [media_id])
|
||||
else:
|
||||
response = api.update_status(status = text)
|
||||
|
||||
return response
|
||||
|
||||
except TweepError as e:
|
||||
content = json.loads(e.response.content)
|
||||
content = content["errors"][0]
|
||||
if e.response.status_code == 401:
|
||||
self.db_set("session_status", "Expired")
|
||||
frappe.db.commit()
|
||||
frappe.throw(content["message"],title="Twitter Error {0} {1}".format(e.response.status_code, e.response.reason))
|
||||
|
||||
@frappe.whitelist()
|
||||
def callback(oauth_token, oauth_verifier):
|
||||
twitter_settings = frappe.get_single("Twitter Settings")
|
||||
twitter_settings.get_access_token(oauth_token,oauth_verifier)
|
||||
frappe.db.commit()
|
@ -112,6 +112,8 @@ frappe.ui.form.on("Fees", {
|
||||
args: {
|
||||
"dt": frm.doc.doctype,
|
||||
"dn": frm.doc.name,
|
||||
"party_type": "Student",
|
||||
"party": frm.doc.student,
|
||||
"recipient_id": frm.doc.student_email
|
||||
},
|
||||
callback: function(r) {
|
||||
|
@ -75,7 +75,8 @@ class Fees(AccountsController):
|
||||
self.make_gl_entries()
|
||||
|
||||
if self.send_payment_request and self.student_email:
|
||||
pr = make_payment_request(dt="Fees", dn=self.name, recipient_id=self.student_email,
|
||||
pr = make_payment_request(party_type="Student", party=self.student, dt="Fees",
|
||||
dn=self.name, recipient_id=self.student_email,
|
||||
submit_doc=True, use_dummy_message=True)
|
||||
frappe.msgprint(_("Payment request {0} created").format(getlink("Payment Request", pr.name)))
|
||||
|
||||
|
@ -6,6 +6,9 @@ def get_data():
|
||||
'heatmap': True,
|
||||
'heatmap_message': _('This is based on the attendance of this Student'),
|
||||
'fieldname': 'student',
|
||||
'non_standard_fieldnames': {
|
||||
'Bank Account': 'party'
|
||||
},
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Admission'),
|
||||
@ -29,7 +32,7 @@ def get_data():
|
||||
},
|
||||
{
|
||||
'label': _('Fee'),
|
||||
'items': ['Fees']
|
||||
'items': ['Fees', 'Bank Account']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -144,6 +144,10 @@ def create_sales_order(order, woocommerce_settings, customer_name, sys_lang):
|
||||
def set_items_in_sales_order(new_sales_order, woocommerce_settings, order, sys_lang):
|
||||
company_abbr = frappe.db.get_value('Company', woocommerce_settings.company, 'abbr')
|
||||
|
||||
default_warehouse = _("Stores - {0}", sys_lang).format(company_abbr)
|
||||
if not frappe.db.exists("Warehouse", default_warehouse):
|
||||
frappe.throw(_("Please set Warehouse in Woocommerce Settings"))
|
||||
|
||||
for item in order.get("line_items"):
|
||||
woocomm_item_id = item.get("product_id")
|
||||
found_item = frappe.get_doc("Item", {"woocommerce_id": woocomm_item_id})
|
||||
@ -158,7 +162,7 @@ def set_items_in_sales_order(new_sales_order, woocommerce_settings, order, sys_l
|
||||
"uom": woocommerce_settings.uom or _("Nos", sys_lang),
|
||||
"qty": item.get("quantity"),
|
||||
"rate": item.get("price"),
|
||||
"warehouse": woocommerce_settings.warehouse or _("Stores - {0}", sys_lang).format(company_abbr)
|
||||
"warehouse": woocommerce_settings.warehouse or default_warehouse
|
||||
})
|
||||
|
||||
add_tax_details(new_sales_order, ordered_items_tax, "Ordered Item tax", woocommerce_settings.tax_account)
|
||||
|
@ -67,11 +67,11 @@ def add_bank_accounts(response, bank, company):
|
||||
frappe.throw(_("Please setup a default bank account for company {0}").format(company))
|
||||
|
||||
for account in response["accounts"]:
|
||||
acc_type = frappe.db.get_value("Account Type", account["type"])
|
||||
acc_type = frappe.db.get_value("Bank Account Type", account["type"])
|
||||
if not acc_type:
|
||||
add_account_type(account["type"])
|
||||
|
||||
acc_subtype = frappe.db.get_value("Account Subtype", account["subtype"])
|
||||
acc_subtype = frappe.db.get_value("Bank Account Subtype", account["subtype"])
|
||||
if not acc_subtype:
|
||||
add_account_subtype(account["subtype"])
|
||||
|
||||
@ -106,7 +106,7 @@ def add_bank_accounts(response, bank, company):
|
||||
def add_account_type(account_type):
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Account Type",
|
||||
"doctype": "Bank Account Type",
|
||||
"account_type": account_type
|
||||
}).insert()
|
||||
except Exception:
|
||||
@ -116,7 +116,7 @@ def add_account_type(account_type):
|
||||
def add_account_subtype(account_subtype):
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Account Subtype",
|
||||
"doctype": "Bank Account Subtype",
|
||||
"account_subtype": account_subtype
|
||||
}).insert()
|
||||
except Exception:
|
||||
|
@ -23,11 +23,11 @@ class TestPlaidSettings(unittest.TestCase):
|
||||
for ba in frappe.get_all("Bank Account"):
|
||||
frappe.get_doc("Bank Account", ba.name).delete()
|
||||
|
||||
for at in frappe.get_all("Account Type"):
|
||||
frappe.get_doc("Account Type", at.name).delete()
|
||||
for at in frappe.get_all("Bank Account Type"):
|
||||
frappe.get_doc("Bank Account Type", at.name).delete()
|
||||
|
||||
for ast in frappe.get_all("Account Subtype"):
|
||||
frappe.get_doc("Account Subtype", ast.name).delete()
|
||||
for ast in frappe.get_all("Bank Account Subtype"):
|
||||
frappe.get_doc("Bank Account Subtype", ast.name).delete()
|
||||
|
||||
def test_plaid_disabled(self):
|
||||
frappe.db.set_value("Plaid Settings", None, "enabled", 0)
|
||||
@ -35,11 +35,11 @@ class TestPlaidSettings(unittest.TestCase):
|
||||
|
||||
def test_add_account_type(self):
|
||||
add_account_type("brokerage")
|
||||
self.assertEqual(frappe.get_doc("Account Type", "brokerage").name, "brokerage")
|
||||
self.assertEqual(frappe.get_doc("Bank Account Type", "brokerage").name, "brokerage")
|
||||
|
||||
def test_add_account_subtype(self):
|
||||
add_account_subtype("loan")
|
||||
self.assertEqual(frappe.get_doc("Account Subtype", "loan").name, "loan")
|
||||
self.assertEqual(frappe.get_doc("Bank Account Subtype", "loan").name, "loan")
|
||||
|
||||
def test_default_bank_account(self):
|
||||
if not frappe.db.exists("Bank", "Citi"):
|
||||
|
@ -1,48 +1,53 @@
|
||||
{
|
||||
"cards": [
|
||||
{
|
||||
"icon": "",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient\",\n\t\t\"label\": \"Patient\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Practitioner\",\n\t\t\"label\":\"Healthcare Practitioner\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Practitioner Schedule\",\n\t\t\"label\": \"Practitioner Schedule\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Department\",\n\t\t\"label\": \"Medical Department\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit Type\",\n\t\t\"label\": \"Healthcare Service Unit Type\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit\",\n\t\t\"label\": \"Healthcare Service Unit\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code Standard\",\n\t\t\"label\": \"Medical Code Standard\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code\",\n\t\t\"label\": \"Medical Code\"\n\t}\n]",
|
||||
"title": "Masters"
|
||||
"hidden": 0,
|
||||
"label": "Masters",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient\",\n\t\t\"label\": \"Patient\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Practitioner\",\n\t\t\"label\":\"Healthcare Practitioner\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Practitioner Schedule\",\n\t\t\"label\": \"Practitioner Schedule\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Department\",\n\t\t\"label\": \"Medical Department\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit Type\",\n\t\t\"label\": \"Healthcare Service Unit Type\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit\",\n\t\t\"label\": \"Healthcare Service Unit\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code Standard\",\n\t\t\"label\": \"Medical Code Standard\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code\",\n\t\t\"label\": \"Medical Code\"\n\t}\n]"
|
||||
},
|
||||
{
|
||||
"icon": "",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Appointment Type\",\n\t\t\"label\": \"Appointment Type\"\n },\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure Template\",\n\t\t\"label\": \"Clinical Procedure Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Dosage\",\n\t\t\"label\": \"Prescription Dosage\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Duration\",\n\t\t\"label\": \"Prescription Duration\"\n\t},\n\t{\n\t \"type\": \"doctype\",\n\t\t\"name\": \"Antibiotic\",\n\t\t\"label\": \"Antibiotic\"\n\t}\n]",
|
||||
"title": "Consultation Setup"
|
||||
"hidden": 0,
|
||||
"label": "Consultation Setup",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Appointment Type\",\n\t\t\"label\": \"Appointment Type\"\n },\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure Template\",\n\t\t\"label\": \"Clinical Procedure Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Dosage\",\n\t\t\"label\": \"Prescription Dosage\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Duration\",\n\t\t\"label\": \"Prescription Duration\"\n\t},\n\t{\n\t \"type\": \"doctype\",\n\t\t\"name\": \"Antibiotic\",\n\t\t\"label\": \"Antibiotic\"\n\t}\n]"
|
||||
},
|
||||
{
|
||||
"icon": "icon-star",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Appointment\",\n\t\t\"label\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure\",\n\t\t\"label\": \"Clinical Procedure\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Encounter\",\n\t\t\"label\": \"Patient Encounter\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Vital Signs\",\n\t\t\"label\": \"Vital Signs\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Complaint\",\n\t\t\"label\": \"Complaint\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Diagnosis\",\n\t\t\"label\": \"Diagnosis\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Fee Validity\",\n\t\t\"label\": \"Fee Validity\"\n\t}\n]",
|
||||
"title": "Consultation"
|
||||
"hidden": 0,
|
||||
"label": "Consultation",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Appointment\",\n\t\t\"label\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure\",\n\t\t\"label\": \"Clinical Procedure\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Encounter\",\n\t\t\"label\": \"Patient Encounter\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Vital Signs\",\n\t\t\"label\": \"Vital Signs\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Complaint\",\n\t\t\"label\": \"Complaint\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Diagnosis\",\n\t\t\"label\": \"Diagnosis\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Fee Validity\",\n\t\t\"label\": \"Fee Validity\"\n\t}\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Settings\",\n\t\t\"label\": \"Healthcare Settings\",\n\t\t\"onboard\": 1\n\t}\n]",
|
||||
"title": "Settings"
|
||||
"hidden": 0,
|
||||
"label": "Settings",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Settings\",\n\t\t\"label\": \"Healthcare Settings\",\n\t\t\"onboard\": 1\n\t}\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Template\",\n\t\t\"label\": \"Lab Test Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Sample\",\n\t\t\"label\": \"Lab Test Sample\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test UOM\",\n\t\t\"label\": \"Lab Test UOM\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sensitivity\",\n\t\t\"label\": \"Sensitivity\"\n\t}\n]",
|
||||
"title": "Laboratory Setup"
|
||||
"hidden": 0,
|
||||
"label": "Laboratory Setup",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Template\",\n\t\t\"label\": \"Lab Test Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Sample\",\n\t\t\"label\": \"Lab Test Sample\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test UOM\",\n\t\t\"label\": \"Lab Test UOM\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sensitivity\",\n\t\t\"label\": \"Sensitivity\"\n\t}\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test\",\n\t\t\"label\": \"Lab Test\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sample Collection\",\n\t\t\"label\": \"Sample Collection\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Dosage Form\",\n\t\t\"label\": \"Dosage Form\"\n\t}\n]",
|
||||
"title": "Laboratory"
|
||||
"hidden": 0,
|
||||
"label": "Laboratory",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test\",\n\t\t\"label\": \"Lab Test\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sample Collection\",\n\t\t\"label\": \"Sample Collection\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Dosage Form\",\n\t\t\"label\": \"Dosage Form\"\n\t}\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t}\n]",
|
||||
"title": "Records and History"
|
||||
"hidden": 0,
|
||||
"label": "Rehabilitation and Physiotherapy",
|
||||
"links": "[\n {\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Exercise Type\",\n\t\t\"label\": \"Exercise Type\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Type\",\n\t\t\"label\": \"Therapy Type\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Plan\",\n\t\t\"label\": \"Therapy Plan\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Session\",\n\t\t\"label\": \"Therapy Session\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Assessment Template\",\n\t\t\"label\": \"Patient Assessment Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Assessment\",\n\t\t\"label\": \"Patient Assessment\"\n\t}\n]"
|
||||
},
|
||||
{
|
||||
"links": "[\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Patient Appointment Analytics\",\n\t\t\"doctype\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Lab Test Report\",\n\t\t\"doctype\": \"Lab Test\",\n\t\t\"label\": \"Lab Test Report\"\n\t}\n]",
|
||||
"title": "Reports"
|
||||
"hidden": 0,
|
||||
"label": "Records and History",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t}\n]"
|
||||
},
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Reports",
|
||||
"links": "[\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Patient Appointment Analytics\",\n\t\t\"doctype\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Lab Test Report\",\n\t\t\"doctype\": \"Lab Test\",\n\t\t\"label\": \"Lab Test Report\"\n\t}\n]"
|
||||
}
|
||||
],
|
||||
"category": "Domains",
|
||||
"charts": [
|
||||
{
|
||||
"chart_name": "Patient Appointments",
|
||||
"label": "Patient Appointments"
|
||||
}
|
||||
],
|
||||
"charts": [],
|
||||
"charts_label": "",
|
||||
"creation": "2020-03-02 17:23:17.919682",
|
||||
"developer_mode_only": 0,
|
||||
@ -53,7 +58,7 @@
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "Healthcare",
|
||||
"modified": "2020-03-26 16:10:44.629795",
|
||||
"modified": "2020-04-20 11:42:43.889576",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Healthcare",
|
||||
@ -64,32 +69,32 @@
|
||||
"shortcuts": [
|
||||
{
|
||||
"format": "{} Open",
|
||||
"is_query_report": 0,
|
||||
"label": "Patient Appointment",
|
||||
"link_to": "Patient Appointment",
|
||||
"stats_filter": "{\n \"status\": \"Open\"\n}",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"format": "{} Active",
|
||||
"is_query_report": 0,
|
||||
"label": "Patient",
|
||||
"link_to": "Patient",
|
||||
"stats_filter": "{\n \"status\": \"Active\"\n}",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"format": "{} Vacant",
|
||||
"is_query_report": 0,
|
||||
"label": "Healthcare Service Unit",
|
||||
"link_to": "Healthcare Service Unit",
|
||||
"stats_filter": "{\n \"occupancy_status\": \"Vacant\",\n \"is_group\": 0\n}",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"is_query_report": 0,
|
||||
"label": "Healthcare Practitioner",
|
||||
"link_to": "Healthcare Practitioner",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
"is_query_report": 0,
|
||||
"label": "Patient History",
|
||||
"link_to": "patient_history",
|
||||
"type": "Page"
|
||||
}
|
||||
|
0
erpnext/healthcare/doctype/body_part/__init__.py
Normal file
0
erpnext/healthcare/doctype/body_part/__init__.py
Normal file
8
erpnext/healthcare/doctype/body_part/body_part.js
Normal file
8
erpnext/healthcare/doctype/body_part/body_part.js
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Body Part', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
45
erpnext/healthcare/doctype/body_part/body_part.json
Normal file
45
erpnext/healthcare/doctype/body_part/body_part.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "field:body_part",
|
||||
"creation": "2020-04-10 12:21:55.036402",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"body_part"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "body_part",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Body Part",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-04-10 12:26:44.087985",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Body Part",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# Copyright (c) 2020, 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 AccountSubtype(Document):
|
||||
class BodyPart(Document):
|
||||
pass
|
10
erpnext/healthcare/doctype/body_part/test_body_part.py
Normal file
10
erpnext/healthcare/doctype/body_part/test_body_part.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestBodyPart(unittest.TestCase):
|
||||
pass
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-04-10 12:23:15.259816",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"body_part"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "body_part",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Body Part",
|
||||
"options": "Body Part",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-10 12:25:23.101749",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Body Part Link",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
10
erpnext/healthcare/doctype/body_part_link/body_part_link.py
Normal file
10
erpnext/healthcare/doctype/body_part_link/body_part_link.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, 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 BodyPartLink(Document):
|
||||
pass
|
0
erpnext/healthcare/doctype/exercise/__init__.py
Normal file
0
erpnext/healthcare/doctype/exercise/__init__.py
Normal file
61
erpnext/healthcare/doctype/exercise/exercise.json
Normal file
61
erpnext/healthcare/doctype/exercise/exercise.json
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-03-11 09:25:00.968572",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"exercise_type",
|
||||
"difficulty_level",
|
||||
"counts_target",
|
||||
"counts_completed",
|
||||
"assistance_level"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "exercise_type",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Exercise Type",
|
||||
"options": "Exercise Type",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "exercise_type.difficulty_level",
|
||||
"fieldname": "difficulty_level",
|
||||
"fieldtype": "Link",
|
||||
"label": "Difficulty Level",
|
||||
"options": "Exercise Difficulty Level"
|
||||
},
|
||||
{
|
||||
"fieldname": "counts_target",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Counts Target"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.parenttype==\"Therapy\";",
|
||||
"fieldname": "counts_completed",
|
||||
"fieldtype": "Int",
|
||||
"label": "Counts Completed"
|
||||
},
|
||||
{
|
||||
"fieldname": "assistance_level",
|
||||
"fieldtype": "Select",
|
||||
"label": "Assistance Level",
|
||||
"options": "\nPassive\nActive Assist\nActive"
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-10 13:41:06.662351",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Exercise",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
10
erpnext/healthcare/doctype/exercise/exercise.py
Normal file
10
erpnext/healthcare/doctype/exercise/exercise.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, 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 Exercise(Document):
|
||||
pass
|
@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Exercise Difficulty Level', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -0,0 +1,45 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "field:difficulty_level",
|
||||
"creation": "2020-03-29 21:12:55.835941",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"difficulty_level"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "difficulty_level",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Difficulty Level",
|
||||
"reqd": 1,
|
||||
"unique": 1
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-03-31 23:14:33.554066",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Exercise Difficulty Level",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, 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 ExerciseDifficultyLevel(Document):
|
||||
pass
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user