diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index e4b96ae67e9..8ca8b71ef8d 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -19,7 +19,6 @@ "unlink_payment_on_cancellation_of_invoice", "unlink_advance_payment_on_cancelation_of_order", "book_asset_depreciation_entry_automatically", - "allow_cost_center_in_entry_of_bs_account", "add_taxes_from_item_tax_template", "automatically_fetch_payment_terms", "deferred_accounting_settings_section", @@ -113,12 +112,6 @@ "fieldtype": "Check", "label": "Book Asset Depreciation Entry Automatically" }, - { - "default": "0", - "fieldname": "allow_cost_center_in_entry_of_bs_account", - "fieldtype": "Check", - "label": "Allow Cost Center In Entry of Balance Sheet Account" - }, { "default": "1", "fieldname": "add_taxes_from_item_tax_template", diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py index 2473d715d0d..5593466fc2b 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py @@ -20,7 +20,6 @@ class AccountsSettings(Document): self.validate_stale_days() self.enable_payment_schedule_in_print() - self.enable_fields_for_cost_center_settings() def validate_stale_days(self): if not self.allow_stale and cint(self.stale_days) <= 0: @@ -33,8 +32,3 @@ class AccountsSettings(Document): for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"): make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check") make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check") - - def enable_fields_for_cost_center_settings(self): - show_field = 0 if cint(self.allow_cost_center_in_entry_of_bs_account) else 1 - for doctype in ("Sales Invoice", "Purchase Invoice", "Payment Entry"): - make_property_setter(doctype, "cost_center", "hidden", show_field, "Check") diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index 645da341a3e..def9ed6803e 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -72,12 +72,6 @@ class GLEntry(Document): if not self.cost_center and self.voucher_type != 'Period Closing Voucher': frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.") .format(self.voucher_type, self.voucher_no, self.account)) - else: - from erpnext.accounts.utils import get_allow_cost_center_in_entry_of_bs_account - if not get_allow_cost_center_in_entry_of_bs_account() and self.cost_center: - self.cost_center = None - if self.project: - self.project = None def validate_dimensions_for_pl_and_bs(self): diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py index 594b4d4a223..8083b21f759 100644 --- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py +++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py @@ -3,7 +3,7 @@ # For license information, please see license.txt from __future__ import unicode_literals -import frappe, json +import frappe, json, erpnext from frappe import _ from frappe.utils import flt, getdate, nowdate, add_days from erpnext.controllers.accounts_controller import AccountsController @@ -134,16 +134,19 @@ class InvoiceDiscounting(AccountsController): je.append("accounts", { "account": self.bank_account, "debit_in_account_currency": flt(self.total_amount) - flt(self.bank_charges), + "cost_center": erpnext.get_default_cost_center(self.company) }) je.append("accounts", { "account": self.bank_charges_account, - "debit_in_account_currency": flt(self.bank_charges) + "debit_in_account_currency": flt(self.bank_charges), + "cost_center": erpnext.get_default_cost_center(self.company) }) je.append("accounts", { "account": self.short_term_loan, "credit_in_account_currency": flt(self.total_amount), + "cost_center": erpnext.get_default_cost_center(self.company), "reference_type": "Invoice Discounting", "reference_name": self.name }) @@ -151,6 +154,7 @@ class InvoiceDiscounting(AccountsController): je.append("accounts", { "account": self.accounts_receivable_discounted, "debit_in_account_currency": flt(d.outstanding_amount), + "cost_center": erpnext.get_default_cost_center(self.company), "reference_type": "Invoice Discounting", "reference_name": self.name, "party_type": "Customer", @@ -160,6 +164,7 @@ class InvoiceDiscounting(AccountsController): je.append("accounts", { "account": self.accounts_receivable_credit, "credit_in_account_currency": flt(d.outstanding_amount), + "cost_center": erpnext.get_default_cost_center(self.company), "reference_type": "Invoice Discounting", "reference_name": self.name, "party_type": "Customer", @@ -177,13 +182,15 @@ class InvoiceDiscounting(AccountsController): je.append("accounts", { "account": self.short_term_loan, "debit_in_account_currency": flt(self.total_amount), + "cost_center": erpnext.get_default_cost_center(self.company), "reference_type": "Invoice Discounting", "reference_name": self.name, }) je.append("accounts", { "account": self.bank_account, - "credit_in_account_currency": flt(self.total_amount) + "credit_in_account_currency": flt(self.total_amount), + "cost_center": erpnext.get_default_cost_center(self.company) }) if getdate(self.loan_end_date) > getdate(nowdate()): @@ -193,6 +200,7 @@ class InvoiceDiscounting(AccountsController): je.append("accounts", { "account": self.accounts_receivable_discounted, "credit_in_account_currency": flt(outstanding_amount), + "cost_center": erpnext.get_default_cost_center(self.company), "reference_type": "Invoice Discounting", "reference_name": self.name, "party_type": "Customer", @@ -202,6 +210,7 @@ class InvoiceDiscounting(AccountsController): je.append("accounts", { "account": self.accounts_receivable_unpaid, "debit_in_account_currency": flt(outstanding_amount), + "cost_center": erpnext.get_default_cost_center(self.company), "reference_type": "Invoice Discounting", "reference_name": self.name, "party_type": "Customer", diff --git a/erpnext/accounts/doctype/item_tax_template/item_tax_template.js b/erpnext/accounts/doctype/item_tax_template/item_tax_template.js index 42abdb809ba..e921a0d949d 100644 --- a/erpnext/accounts/doctype/item_tax_template/item_tax_template.js +++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template.js @@ -6,6 +6,18 @@ frappe.ui.form.on('Item Tax Template', { frm.set_query("tax_type", "taxes", function(doc) { return { filters: [ + ['Account', 'company', '=', frm.doc.company], + ['Account', 'is_group', '=', 0], + ['Account', 'account_type', 'in', ['Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation']] + ] + } + }); + }, + company: function (frm) { + frm.set_query("tax_type", "taxes", function(doc) { + return { + filters: [ + ['Account', 'company', '=', frm.doc.company], ['Account', 'is_group', '=', 0], ['Account', 'account_type', 'in', ['Tax', 'Chargeable', 'Income Account', 'Expense Account', 'Expenses Included In Valuation']] ] diff --git a/erpnext/accounts/doctype/item_tax_template/item_tax_template.json b/erpnext/accounts/doctype/item_tax_template/item_tax_template.json index f713cfc0bac..856c371ecfa 100644 --- a/erpnext/accounts/doctype/item_tax_template/item_tax_template.json +++ b/erpnext/accounts/doctype/item_tax_template/item_tax_template.json @@ -1,168 +1,85 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:title", - "beta": 0, - "creation": "2018-11-22 22:45:00.370913", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:title", + "creation": "2018-11-22 22:45:00.370913", + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "company", + "taxes" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "title", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Title", - "length": 0, - "no_copy": 1, - "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, + "fieldname": "title", + "fieldtype": "Data", + "in_filter": 1, + "in_list_view": 1, + "label": "Title", + "no_copy": 1, + "reqd": 1, "unique": 1 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "taxes", - "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": "Tax Rates", - "length": 0, - "no_copy": 0, - "options": "Item Tax 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, - "translatable": 0, - "unique": 0 + "fieldname": "taxes", + "fieldtype": "Table", + "label": "Tax Rates", + "options": "Item Tax Template Detail", + "reqd": 1 + }, + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "reqd": 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-12-21 23:51:16.328340", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Item Tax Template", - "name_case": "", - "owner": "Administrator", + ], + "modified": "2020-06-18 20:27:42.615842", + "modified_by": "ahmad@havenir.com", + "module": "Accounts", + "name": "Item Tax Template", + "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, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, "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, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "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": 0 + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "share": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/accounts/doctype/item_tax_template/test_records.json b/erpnext/accounts/doctype/item_tax_template/test_records.json index db540e86aac..4d9537d4b89 100644 --- a/erpnext/accounts/doctype/item_tax_template/test_records.json +++ b/erpnext/accounts/doctype/item_tax_template/test_records.json @@ -2,6 +2,7 @@ { "doctype": "Item Tax Template", "title": "_Test Account Excise Duty @ 10", + "company": "_Test Company", "taxes": [ { "doctype": "Item Tax Template Detail", @@ -14,6 +15,7 @@ { "doctype": "Item Tax Template", "title": "_Test Account Excise Duty @ 12", + "company": "_Test Company", "taxes": [ { "doctype": "Item Tax Template Detail", @@ -26,6 +28,7 @@ { "doctype": "Item Tax Template", "title": "_Test Account Excise Duty @ 15", + "company": "_Test Company", "taxes": [ { "doctype": "Item Tax Template Detail", @@ -38,6 +41,7 @@ { "doctype": "Item Tax Template", "title": "_Test Account Excise Duty @ 20", + "company": "_Test Company", "taxes": [ { "doctype": "Item Tax Template Detail", @@ -50,6 +54,7 @@ { "doctype": "Item Tax Template", "title": "_Test Item Tax Template 1", + "company": "_Test Company", "taxes": [ { "doctype": "Item Tax Template Detail", diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 7360b399425..cfdae936a48 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -840,6 +840,7 @@ def get_opening_accounts(company): return [{"account": a, "balance": get_balance_on(a)} for a in accounts] +@frappe.whitelist() def get_against_jv(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark from `tabJournal Entry` jv, `tabJournal Entry Account` jv_detail diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py index 6996c775b32..23ad1eef14c 100644 --- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py @@ -204,11 +204,8 @@ class TestJournalEntry(unittest.TestCase): self.assertEqual(jv.inter_company_journal_entry_reference, "") self.assertEqual(jv1.inter_company_journal_entry_reference, "") - def test_jv_for_enable_allow_cost_center_in_entry_of_bs_account(self): + def test_jv_with_cost_centre(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - _TC" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, cost_center = cost_center, save=False) @@ -237,15 +234,45 @@ class TestJournalEntry(unittest.TestCase): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() + def test_jv_with_project(self): + from erpnext.projects.doctype.project.test_project import make_project + project = make_project({ + 'project_name': 'Journal Entry Project', + 'project_template_name': 'Test Project Template', + 'start_date': '2020-01-01' + }) - def test_jv_account_and_party_balance_for_enable_allow_cost_center_in_entry_of_bs_account(self): + jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, save=False) + for d in jv.accounts: + d.project = project.project_name + jv.voucher_type = "Bank Entry" + jv.multi_currency = 0 + jv.cheque_no = "112233" + jv.cheque_date = nowdate() + jv.insert() + jv.submit() + + expected_values = { + "_Test Cash - _TC": { + "project": project.project_name + }, + "_Test Bank - _TC": { + "project": project.project_name + } + } + + gl_entries = frappe.db.sql("""select account, project, debit, credit + from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s + order by account asc""", jv.name, as_dict=1) + + self.assertTrue(gl_entries) + + for gle in gl_entries: + self.assertEqual(expected_values[gle.account]["project"], gle.project) + + def test_jv_account_and_party_balance_with_cost_centre(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.utils import get_balance_on - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - _TC" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, cost_center = cost_center, save=False) @@ -261,9 +288,6 @@ class TestJournalEntry(unittest.TestCase): account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=cost_center) self.assertEqual(expected_account_balance, account_balance) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - def make_journal_entry(account1, account2, amount, cost_center=None, posting_date=None, exchange_rate=1, save=True, submit=False, project=None): if not cost_center: cost_center = "_Test Cost Center - _TC" diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py index 54464e71c4e..a53417eedf9 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py @@ -68,6 +68,9 @@ class OpeningInvoiceCreationTool(Document): if not self.company: frappe.throw(_("Please select the Company")) + company_details = frappe.get_cached_value('Company', self.company, + ["default_currency", "default_letter_head"], as_dict=1) or {} + for row in self.invoices: if not row.qty: row.qty = 1.0 @@ -99,6 +102,12 @@ class OpeningInvoiceCreationTool(Document): if not args: continue + if company_details: + args.update({ + "currency": company_details.get("default_currency"), + "letter_head": company_details.get("default_letter_head") + }) + doc = frappe.get_doc(args).insert() doc.submit() names.append(doc.name) @@ -172,8 +181,7 @@ class OpeningInvoiceCreationTool(Document): "due_date": row.due_date, "posting_date": row.posting_date, frappe.scrub(party_type): row.party, - "doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice", - "currency": frappe.get_cached_value('Company', self.company, "default_currency") + "doctype": "Sales Invoice" if self.invoice_type == "Sales" else "Purchase Invoice" }) accounting_dimension = get_accounting_dimensions() diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 59611bc74c2..1cecab74ef3 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe, erpnext, json from frappe import _, scrub, ValidationError from frappe.utils import flt, comma_or, nowdate, getdate -from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on, get_allow_cost_center_in_entry_of_bs_account +from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on from erpnext.accounts.party import get_party_account from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.setup.utils import get_exchange_rate @@ -658,7 +658,7 @@ def get_outstanding_reference_documents(args): .format(frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"])) # Add cost center condition - if args.get("cost_center") and get_allow_cost_center_in_entry_of_bs_account(): + if args.get("cost_center"): condition += " and cost_center='%s'" % args.get("cost_center") date_fields_dict = { @@ -1029,14 +1029,14 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount= if bank_amount: received_amount = bank_amount else: - received_amount = paid_amount * doc.conversion_rate + received_amount = paid_amount * doc.get('conversion_rate', 1) else: received_amount = abs(outstanding_amount) if bank_amount: paid_amount = bank_amount else: # if party account currency and bank currency is different then populate paid amount as well - paid_amount = received_amount * doc.conversion_rate + paid_amount = received_amount * doc.get('conversion_rate', 1) pe = frappe.new_doc("Payment Entry") pe.payment_type = payment_type diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 8bb741f0b25..772fc1a2521 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -460,11 +460,8 @@ class TestPaymentEntry(unittest.TestCase): outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount")) self.assertEqual(outstanding_amount, 0) - def test_payment_entry_against_sales_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self): + def test_payment_entry_against_sales_invoice_with_cost_centre(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - _TC" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") @@ -499,39 +496,8 @@ class TestPaymentEntry(unittest.TestCase): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - - def test_payment_entry_against_sales_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self): - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - si = create_sales_invoice(debit_to="Debtors - _TC") - - pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC") - - pe.reference_no = "112211-2" - pe.reference_date = nowdate() - pe.paid_to = "_Test Bank - _TC" - pe.paid_amount = si.grand_total - pe.insert() - pe.submit() - - gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit, - debit_in_account_currency, credit_in_account_currency - from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s - order by account asc""", pe.name, as_dict=1) - - self.assertTrue(gl_entries) - - for gle in gl_entries: - self.assertEqual(gle.cost_center, None) - - def test_payment_entry_against_purchase_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self): + def test_payment_entry_against_purchase_invoice_with_cost_center(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - _TC" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") @@ -566,40 +532,9 @@ class TestPaymentEntry(unittest.TestCase): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - - def test_payment_entry_against_purchase_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self): - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - pi = make_purchase_invoice(credit_to="Creditors - _TC") - - pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC") - - pe.reference_no = "112222-2" - pe.reference_date = nowdate() - pe.paid_from = "_Test Bank - _TC" - pe.paid_amount = pi.grand_total - pe.insert() - pe.submit() - - gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit, - debit_in_account_currency, credit_in_account_currency - from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s - order by account asc""", pe.name, as_dict=1) - - self.assertTrue(gl_entries) - - for gle in gl_entries: - self.assertEqual(gle.cost_center, None) - - def test_payment_entry_account_and_party_balance_for_enable_allow_cost_center_in_entry_of_bs_account(self): + def test_payment_entry_account_and_party_balance_with_cost_center(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center from erpnext.accounts.utils import get_balance_on - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - _TC" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") @@ -630,9 +565,6 @@ class TestPaymentEntry(unittest.TestCase): self.assertEqual(expected_party_balance, party_balance) self.assertEqual(expected_party_account_balance, party_account_balance) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - def create_payment_terms_template(): create_payment_term('Basic Amount Receivable') @@ -665,4 +597,4 @@ def create_payment_term(name): frappe.get_doc({ 'doctype': 'Payment Term', 'payment_term_name': name - }).insert() \ No newline at end of file + }).insert() diff --git a/erpnext/accounts/doctype/payment_order/payment_order.py b/erpnext/accounts/doctype/payment_order/payment_order.py index 7ecdc41d034..4702e58cef1 100644 --- a/erpnext/accounts/doctype/payment_order/payment_order.py +++ b/erpnext/accounts/doctype/payment_order/payment_order.py @@ -26,6 +26,7 @@ class PaymentOrder(Document): for d in self.references: frappe.db.set_value(self.payment_order_type, d.get(frappe.scrub(self.payment_order_type)), ref_field, status) +@frappe.whitelist() def get_mop_query(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql(""" select mode_of_payment from `tabPayment Order Reference` where parent = %(parent)s and mode_of_payment like %(txt)s @@ -36,6 +37,7 @@ def get_mop_query(doctype, txt, searchfield, start, page_len, filters): 'txt': "%%%s%%" % txt }) +@frappe.whitelist() def get_supplier_query(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql(""" select supplier from `tabPayment Order Reference` where parent = %(parent)s and supplier like %(txt)s and @@ -86,4 +88,4 @@ def make_journal_entry(doc, supplier, mode_of_payment=None): je.flags.ignore_mandatory = True je.save() - frappe.msgprint(_("{0} {1} created").format(je.doctype, je.name)) \ No newline at end of file + frappe.msgprint(_("{0} {1} created").format(je.doctype, je.name)) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 30804961861..35d8d34c518 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -101,10 +101,10 @@ class PaymentReconciliation(Document): Having amount > 0 """.format( - doc=voucher_type, - dr_or_cr=dr_or_cr, - reconciled_dr_or_cr=reconciled_dr_or_cr, - party_type_field=frappe.scrub(self.party_type)), + doc=voucher_type, + dr_or_cr=dr_or_cr, + reconciled_dr_or_cr=reconciled_dr_or_cr, + party_type_field=frappe.scrub(self.party_type)), { 'party': self.party, 'party_type': self.party_type, @@ -170,7 +170,7 @@ class PaymentReconciliation(Document): reconcile_against_document(lst) if dr_or_cr_notes: - reconcile_dr_cr_note(dr_or_cr_notes) + reconcile_dr_cr_note(dr_or_cr_notes, self.company) msgprint(_("Successfully Reconciled")) self.get_unreconciled_entries() @@ -261,7 +261,7 @@ class PaymentReconciliation(Document): return cond -def reconcile_dr_cr_note(dr_cr_notes): +def reconcile_dr_cr_note(dr_cr_notes, company): for d in dr_cr_notes: voucher_type = ('Credit Note' if d.voucher_type == 'Sales Invoice' else 'Debit Note') @@ -273,6 +273,7 @@ def reconcile_dr_cr_note(dr_cr_notes): "doctype": "Journal Entry", "voucher_type": voucher_type, "posting_date": today(), + "company": company, "accounts": [ { 'account': d.account, @@ -280,7 +281,8 @@ def reconcile_dr_cr_note(dr_cr_notes): 'party_type': d.party_type, d.dr_or_cr: abs(d.allocated_amount), 'reference_type': d.against_voucher_type, - 'reference_name': d.against_voucher + 'reference_name': d.against_voucher, + 'cost_center': erpnext.get_default_cost_center(company) }, { 'account': d.account, @@ -289,7 +291,8 @@ def reconcile_dr_cr_note(dr_cr_notes): reconcile_dr_or_cr: (abs(d.allocated_amount) if abs(d.unadjusted_amount) > abs(d.allocated_amount) else abs(d.unadjusted_amount)), 'reference_type': d.voucher_type, - 'reference_name': d.voucher_no + 'reference_name': d.voucher_no, + 'cost_center': erpnext.get_default_cost_center(company) } ] }) diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py index 4f17e9f9954..f1869671ae9 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py @@ -115,6 +115,7 @@ def get_item_groups(pos_profile): def get_series(): return frappe.get_meta("Sales Invoice").get_field("naming_series").options or "" +@frappe.whitelist() def pos_profile_query(doctype, txt, searchfield, start, page_len, filters): user = frappe.session['user'] company = filters.get('company') or frappe.defaults.get_user_default('company') diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index ead300e3bb4..d4d83af1ede 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -432,6 +432,7 @@ def make_pricing_rule(doctype, docname): return doc +@frappe.whitelist() def get_item_uoms(doctype, txt, searchfield, start, page_len, filters): items = [filters.get('value')] if filters.get('apply_on') != 'Item Code': @@ -442,4 +443,4 @@ def get_item_uoms(doctype, txt, searchfield, start, page_len, filters): return frappe.get_all('UOM Conversion Detail', filters = {'parent': ('in', items), 'uom': ("like", "{0}%".format(txt))}, - fields = ["distinct uom"], as_list=1) \ No newline at end of file + fields = ["distinct uom"], as_list=1) diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py index 53115f92d01..ad983830f3b 100644 --- a/erpnext/accounts/doctype/pricing_rule/utils.py +++ b/erpnext/accounts/doctype/pricing_rule/utils.py @@ -319,7 +319,9 @@ def apply_internal_priority(pricing_rules, field_set, args): filtered_rules = [] for field in field_set: if args.get(field): - filtered_rules = filter(lambda x: x[field]==args[field], pricing_rules) + # filter function always returns a filter object even if empty + # list conversion is necessary to check for an empty result + filtered_rules = list(filter(lambda x: x.get(field)==args.get(field), pricing_rules)) if filtered_rules: break return filtered_rules or pricing_rules diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 829c34da67c..eb1ccd95afb 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -26,6 +26,7 @@ "accounting_dimensions_section", "cost_center", "dimension_col_break", + "project", "supplier_invoice_details", "bill_no", "column_break_15", @@ -1598,6 +1599,12 @@ "show_days": 1, "show_seconds": 1 }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + }, { "fieldname": "tax_withholding_category", "fieldtype": "Link", diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 3cd57d403a2..7b1062f6545 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -438,6 +438,8 @@ class PurchaseInvoice(BuyingController): self.make_tax_gl_entries(gl_entries) + gl_entries = make_regional_gl_entries(gl_entries, self) + gl_entries = merge_similar_entries(gl_entries) self.make_payment_gl_entries(gl_entries) @@ -476,6 +478,7 @@ class PurchaseInvoice(BuyingController): if self.party_account_currency==self.company_currency else grand_total, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher_type": self.doctype, + "project": self.project, "cost_center": self.cost_center }, self.party_account_currency, item=self) ) @@ -516,6 +519,7 @@ class PurchaseInvoice(BuyingController): "account": warehouse_account[item.warehouse]['account'], "against": warehouse_account[item.from_warehouse]["account"], "cost_center": item.cost_center, + "project": item.project or self.project, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "debit": warehouse_debit_amount, }, warehouse_account[item.warehouse]["account_currency"], item=item)) @@ -525,6 +529,7 @@ class PurchaseInvoice(BuyingController): "account": warehouse_account[item.from_warehouse]['account'], "against": warehouse_account[item.warehouse]["account"], "cost_center": item.cost_center, + "project": item.project or self.project, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "debit": -1 * flt(item.base_net_amount, item.precision("base_net_amount")), }, warehouse_account[item.from_warehouse]["account_currency"], item=item)) @@ -548,7 +553,7 @@ class PurchaseInvoice(BuyingController): "debit": warehouse_debit_amount, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "cost_center": item.cost_center, - "project": item.project + "project": item.project or self.project }, account_currency, item=item) ) @@ -561,7 +566,7 @@ class PurchaseInvoice(BuyingController): "cost_center": item.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(amount), - "project": item.project + "project": item.project or self.project }, item=item)) # sub-contracting warehouse @@ -574,6 +579,7 @@ class PurchaseInvoice(BuyingController): "account": supplier_warehouse_account, "against": item.expense_account, "cost_center": item.cost_center, + "project": item.project or self.project, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(item.rm_supp_cost) }, warehouse_account[self.supplier_warehouse]["account_currency"], item=item)) @@ -606,7 +612,7 @@ class PurchaseInvoice(BuyingController): "against": self.supplier, "debit": amount, "cost_center": item.cost_center, - "project": item.project + "project": item.project or self.project }, account_currency, item=item)) # If asset is bought through this document and not linked to PR @@ -619,7 +625,7 @@ class PurchaseInvoice(BuyingController): "cost_center": item.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(item.landed_cost_voucher_amount), - "project": item.project + "project": item.project or self.project }, item=item)) gl_entries.append(self.get_gl_dict({ @@ -628,7 +634,7 @@ class PurchaseInvoice(BuyingController): "cost_center": item.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "debit": flt(item.landed_cost_voucher_amount), - "project": item.project + "project": item.project or self.project }, item=item)) # update gross amount of asset bought through this document @@ -654,7 +660,8 @@ class PurchaseInvoice(BuyingController): "against": self.supplier, "debit": flt(item.item_tax_amount, item.precision("item_tax_amount")), "remarks": self.remarks or "Accounting Entry for Stock", - "cost_center": self.cost_center + "cost_center": self.cost_center, + "project": item.project or self.project }, item=item) ) @@ -683,7 +690,8 @@ class PurchaseInvoice(BuyingController): "debit": base_asset_amount, "debit_in_account_currency": (base_asset_amount if arbnb_currency == self.company_currency else asset_amount), - "cost_center": item.cost_center + "cost_center": item.cost_center, + "project": item.project or self.project }, item=item)) if item.item_tax_amount: @@ -693,6 +701,7 @@ class PurchaseInvoice(BuyingController): "against": self.supplier, "remarks": self.get("remarks") or _("Accounting Entry for Asset"), "cost_center": item.cost_center, + "project": item.project or self.project, "credit": item.item_tax_amount, "credit_in_account_currency": (item.item_tax_amount if asset_eiiav_currency == self.company_currency else @@ -709,7 +718,8 @@ class PurchaseInvoice(BuyingController): "debit": base_asset_amount, "debit_in_account_currency": (base_asset_amount if cwip_account_currency == self.company_currency else asset_amount), - "cost_center": self.cost_center + "cost_center": self.cost_center, + "project": item.project or self.project }, item=item)) if item.item_tax_amount and not cint(erpnext.is_perpetual_inventory_enabled(self.company)): @@ -720,6 +730,7 @@ class PurchaseInvoice(BuyingController): "remarks": self.get("remarks") or _("Accounting Entry for Asset"), "cost_center": item.cost_center, "credit": item.item_tax_amount, + "project": item.project or self.project, "credit_in_account_currency": (item.item_tax_amount if asset_eiiav_currency == self.company_currency else item.item_tax_amount / self.conversion_rate) @@ -735,7 +746,7 @@ class PurchaseInvoice(BuyingController): "cost_center": item.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "credit": flt(item.landed_cost_voucher_amount), - "project": item.project + "project": item.project or self.project }, item=item)) gl_entries.append(self.get_gl_dict({ @@ -744,7 +755,7 @@ class PurchaseInvoice(BuyingController): "cost_center": item.cost_center, "remarks": self.get("remarks") or _("Accounting Entry for Stock"), "debit": flt(item.landed_cost_voucher_amount), - "project": item.project + "project": item.project or self.project }, item=item)) # update gross amount of assets bought through this document @@ -779,7 +790,7 @@ class PurchaseInvoice(BuyingController): "debit": stock_adjustment_amt, "remarks": self.get("remarks") or _("Stock Adjustment"), "cost_center": item.cost_center, - "project": item.project + "project": item.project or self.project }, account_currency, item=item) ) @@ -871,7 +882,8 @@ class PurchaseInvoice(BuyingController): if self.party_account_currency==self.company_currency else self.paid_amount, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher_type": self.doctype, - "cost_center": self.cost_center + "cost_center": self.cost_center, + "project": self.project }, self.party_account_currency, item=self) ) @@ -903,7 +915,8 @@ class PurchaseInvoice(BuyingController): if self.party_account_currency==self.company_currency else self.write_off_amount, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher_type": self.doctype, - "cost_center": self.cost_center + "cost_center": self.cost_center, + "project": self.project }, self.party_account_currency, item=self) ) gl_entries.append( @@ -1097,6 +1110,10 @@ def get_list_context(context=None): }) return list_context +@erpnext.allow_regional +def make_regional_gl_entries(gl_entries, doc): + return gl_entries + @frappe.whitelist() def make_debit_note(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index b5955ca2581..9a666bf9f8d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -14,6 +14,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per from erpnext.controllers.accounts_controller import get_payment_terms from erpnext.exceptions import InvalidCurrency from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction +from erpnext.projects.doctype.project.test_project import make_project from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account from erpnext.stock.doctype.item.test_item import create_item @@ -435,6 +436,8 @@ class TestPurchaseInvoice(unittest.TestCase): ) def test_total_purchase_cost_for_project(self): + make_project({'project_name':'_Test Project'}) + existing_purchase_cost = frappe.db.sql("""select sum(base_net_amount) from `tabPurchase Invoice Item` where project = '_Test Project' and docstatus=1""") existing_purchase_cost = existing_purchase_cost and existing_purchase_cost[0][0] or 0 @@ -808,11 +811,8 @@ class TestPurchaseInvoice(unittest.TestCase): pi_doc = frappe.get_doc('Purchase Invoice', pi.name) self.assertEqual(pi_doc.outstanding_amount, 0) - def test_purchase_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self): + def test_purchase_invoice_with_cost_center(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - _TC" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") @@ -838,13 +838,7 @@ class TestPurchaseInvoice(unittest.TestCase): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - - def test_purchase_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self): - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() + def test_purchase_invoice_without_cost_center(self): cost_center = "_Test Cost Center - _TC" pi = make_purchase_invoice(credit_to="Creditors - _TC") @@ -867,6 +861,43 @@ class TestPurchaseInvoice(unittest.TestCase): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) + def test_purchase_invoice_with_project_link(self): + project = make_project({ + 'project_name': 'Purchase Invoice Project', + 'project_template_name': 'Test Project Template', + 'start_date': '2020-01-01' + }) + item_project = make_project({ + 'project_name': 'Purchase Invoice Item Project', + 'project_template_name': 'Test Project Template', + 'start_date': '2019-06-01' + }) + + pi = make_purchase_invoice(credit_to="Creditors - _TC" ,do_not_save=1) + pi.items[0].project = item_project.project_name + pi.project = project.project_name + + pi.submit() + + expected_values = { + "Creditors - _TC": { + "project": project.project_name + }, + "_Test Account Cost for Goods Sold - _TC": { + "project": item_project.project_name + } + } + + gl_entries = frappe.db.sql("""select account, cost_center, project, account_currency, debit, credit, + debit_in_account_currency, credit_in_account_currency + from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s + order by account asc""", pi.name, as_dict=1) + + self.assertTrue(gl_entries) + + for gle in gl_entries: + self.assertEqual(expected_values[gle.account]["project"], gle.project) + def test_deferred_expense_via_journal_entry(self): deferred_account = create_account(account_name="Deferred Expense", parent_account="Current Assets - _TC", company="_Test Company") diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 63c34ed2056..02b42065449 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -189,6 +189,8 @@ { "fieldname": "customer_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "options": "fa fa-user" }, { @@ -197,6 +199,8 @@ "fieldname": "title", "fieldtype": "Data", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Title", "no_copy": 1, "print_hide": 1 @@ -205,6 +209,8 @@ "bold": 1, "fieldname": "naming_series", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "label": "Series", "no_copy": 1, "oldfieldname": "naming_series", @@ -218,6 +224,8 @@ "bold": 1, "fieldname": "customer", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "in_standard_filter": 1, "label": "Customer", "oldfieldname": "customer", @@ -232,6 +240,8 @@ "fetch_from": "customer.customer_name", "fieldname": "customer_name", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "in_global_search": 1, "label": "Customer Name", "oldfieldname": "customer_name", @@ -241,6 +251,8 @@ { "fieldname": "tax_id", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "Tax Id", "print_hide": 1, "read_only": 1 @@ -248,6 +260,8 @@ { "fieldname": "project", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "in_global_search": 1, "label": "Project", "oldfieldname": "project_name", @@ -259,6 +273,8 @@ "default": "0", "fieldname": "is_pos", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Include Payment (POS)", "oldfieldname": "is_pos", "oldfieldtype": "Check", @@ -268,6 +284,8 @@ "depends_on": "is_pos", "fieldname": "pos_profile", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "POS Profile", "options": "POS Profile", "print_hide": 1 @@ -276,6 +294,8 @@ "fieldname": "offline_pos_name", "fieldtype": "Data", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Offline POS Name", "print_hide": 1, "read_only": 1 @@ -284,6 +304,8 @@ "default": "0", "fieldname": "is_return", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Is Return (Credit Note)", "no_copy": 1, "print_hide": 1 @@ -291,11 +313,15 @@ { "fieldname": "column_break1", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Column Break" }, { "fieldname": "company", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "in_standard_filter": 1, "label": "Company", "oldfieldname": "company", @@ -308,6 +334,8 @@ { "fieldname": "cost_center", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Cost Center", "options": "Cost Center" }, @@ -316,6 +344,8 @@ "default": "Today", "fieldname": "posting_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "label": "Date", "no_copy": 1, "oldfieldname": "posting_date", @@ -326,6 +356,8 @@ { "fieldname": "posting_time", "fieldtype": "Time", + "hide_days": 1, + "hide_seconds": 1, "label": "Posting Time", "no_copy": 1, "oldfieldname": "posting_time", @@ -337,12 +369,16 @@ "depends_on": "eval:doc.docstatus==0", "fieldname": "set_posting_time", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Edit Posting Date and Time", "print_hide": 1 }, { "fieldname": "due_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "label": "Payment Due Date", "no_copy": 1, "oldfieldname": "due_date", @@ -351,6 +387,8 @@ { "fieldname": "amended_from", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "ignore_user_permissions": 1, "label": "Amended From", "no_copy": 1, @@ -364,12 +402,16 @@ "depends_on": "return_against", "fieldname": "returns", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Returns" }, { "depends_on": "return_against", "fieldname": "return_against", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Return Against Sales Invoice", "no_copy": 1, "options": "Sales Invoice", @@ -379,13 +421,17 @@ }, { "fieldname": "column_break_21", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "default": "0", "depends_on": "eval: doc.is_return && doc.return_against", "fieldname": "update_billed_amount_in_sales_order", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Update Billed Amount in Sales Order" }, { @@ -393,35 +439,47 @@ "collapsible_depends_on": "po_no", "fieldname": "customer_po_details", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Customer PO Details" }, { "allow_on_submit": 1, "fieldname": "po_no", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Customer's Purchase Order", "no_copy": 1, "print_hide": 1 }, { "fieldname": "column_break_23", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "allow_on_submit": 1, "fieldname": "po_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "label": "Customer's Purchase Order Date" }, { "collapsible": 1, "fieldname": "address_and_contact", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Address and Contact" }, { "fieldname": "customer_address", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Customer Address", "options": "Address", "print_hide": 1 @@ -429,12 +487,16 @@ { "fieldname": "address_display", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Address", "read_only": 1 }, { "fieldname": "contact_person", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "in_global_search": 1, "label": "Contact Person", "options": "Contact", @@ -443,6 +505,8 @@ { "fieldname": "contact_display", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Contact", "read_only": 1 }, @@ -450,6 +514,8 @@ "fieldname": "contact_mobile", "fieldtype": "Small Text", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Mobile No", "read_only": 1 }, @@ -457,6 +523,8 @@ "fieldname": "contact_email", "fieldtype": "Data", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Contact Email", "options": "Email", "print_hide": 1, @@ -465,17 +533,23 @@ { "fieldname": "territory", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Territory", "options": "Territory", "print_hide": 1 }, { "fieldname": "col_break4", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "shipping_address_name", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Shipping Address Name", "options": "Address", "print_hide": 1 @@ -483,6 +557,8 @@ { "fieldname": "shipping_address", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Shipping Address", "print_hide": 1, "read_only": 1 @@ -490,6 +566,8 @@ { "fieldname": "company_address", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Company Address Name", "options": "Address", "print_hide": 1 @@ -498,6 +576,8 @@ "fieldname": "company_address_display", "fieldtype": "Small Text", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Company Address", "print_hide": 1, "read_only": 1 @@ -507,11 +587,15 @@ "depends_on": "customer", "fieldname": "currency_and_price_list", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Currency and Price List" }, { "fieldname": "currency", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Currency", "oldfieldname": "currency", "oldfieldtype": "Select", @@ -523,6 +607,8 @@ "description": "Rate at which Customer Currency is converted to customer's base currency", "fieldname": "conversion_rate", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Exchange Rate", "oldfieldname": "conversion_rate", "oldfieldtype": "Currency", @@ -533,11 +619,15 @@ { "fieldname": "column_break2", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "width": "50%" }, { "fieldname": "selling_price_list", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Price List", "oldfieldname": "price_list_name", "oldfieldtype": "Select", @@ -548,6 +638,8 @@ { "fieldname": "price_list_currency", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Price List Currency", "options": "Currency", "print_hide": 1, @@ -558,6 +650,8 @@ "description": "Rate at which Price list currency is converted to customer's base currency", "fieldname": "plc_conversion_rate", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Price List Exchange Rate", "precision": "9", "print_hide": 1, @@ -567,6 +661,8 @@ "default": "0", "fieldname": "ignore_pricing_rule", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Ignore Pricing Rule", "no_copy": 1, "permlevel": 1, @@ -574,12 +670,16 @@ }, { "fieldname": "sec_warehouse", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "depends_on": "update_stock", "fieldname": "set_warehouse", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Set Source Warehouse", "options": "Warehouse", "print_hide": 1 @@ -587,6 +687,8 @@ { "fieldname": "items_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Section Break", "options": "fa fa-shopping-cart" }, @@ -594,6 +696,8 @@ "default": "0", "fieldname": "update_stock", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Update Stock", "oldfieldname": "update_stock", "oldfieldtype": "Check", @@ -602,12 +706,16 @@ { "fieldname": "scan_barcode", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "Scan Barcode" }, { "allow_bulk_edit": 1, "fieldname": "items", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Items", "oldfieldname": "entries", "oldfieldtype": "Table", @@ -617,11 +725,15 @@ { "fieldname": "pricing_rule_details", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Pricing Rules" }, { "fieldname": "pricing_rules", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Pricing Rule Detail", "options": "Pricing Rule Detail", "read_only": 1 @@ -629,6 +741,8 @@ { "fieldname": "packing_list", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Packing List", "options": "fa fa-suitcase", "print_hide": 1 @@ -636,6 +750,8 @@ { "fieldname": "packed_items", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Packed Items", "options": "Packed Item", "print_hide": 1 @@ -643,6 +759,8 @@ { "fieldname": "product_bundle_help", "fieldtype": "HTML", + "hide_days": 1, + "hide_seconds": 1, "label": "Product Bundle Help", "print_hide": 1 }, @@ -651,11 +769,15 @@ "collapsible_depends_on": "eval:doc.total_billing_amount > 0", "fieldname": "time_sheet_list", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Time Sheet List" }, { "fieldname": "timesheets", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Time Sheets", "options": "Sales Invoice Timesheet", "print_hide": 1 @@ -664,23 +786,31 @@ "default": "0", "fieldname": "total_billing_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Billing Amount", "print_hide": 1, "read_only": 1 }, { "fieldname": "section_break_30", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "total_qty", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Quantity", "read_only": 1 }, { "fieldname": "base_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, @@ -689,6 +819,8 @@ { "fieldname": "base_net_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Net Total (Company Currency)", "oldfieldname": "net_total", "oldfieldtype": "Currency", @@ -699,11 +831,15 @@ }, { "fieldname": "column_break_32", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total", "options": "currency", "read_only": 1 @@ -711,6 +847,8 @@ { "fieldname": "net_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Net Total", "options": "currency", "print_hide": 1, @@ -719,6 +857,8 @@ { "fieldname": "total_net_weight", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Net Weight", "print_hide": 1, "read_only": 1 @@ -726,12 +866,16 @@ { "fieldname": "taxes_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Section Break", "options": "fa fa-money" }, { "fieldname": "taxes_and_charges", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Taxes and Charges Template", "oldfieldname": "charge", "oldfieldtype": "Link", @@ -740,11 +884,15 @@ }, { "fieldname": "column_break_38", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "shipping_rule", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Shipping Rule", "oldfieldtype": "Button", "options": "Shipping Rule", @@ -753,17 +901,23 @@ { "fieldname": "tax_category", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Tax Category", "options": "Tax Category", "print_hide": 1 }, { "fieldname": "section_break_40", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "taxes", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Taxes and Charges", "oldfieldname": "other_charges", "oldfieldtype": "Table", @@ -773,11 +927,15 @@ "collapsible": 1, "fieldname": "sec_tax_breakup", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Tax Breakup" }, { "fieldname": "other_charges_calculation", "fieldtype": "Long Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Taxes and Charges Calculation", "no_copy": 1, "oldfieldtype": "HTML", @@ -786,11 +944,15 @@ }, { "fieldname": "section_break_43", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "base_total_taxes_and_charges", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Taxes and Charges (Company Currency)", "oldfieldname": "other_charges_total", "oldfieldtype": "Currency", @@ -800,11 +962,15 @@ }, { "fieldname": "column_break_47", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "total_taxes_and_charges", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Taxes and Charges", "options": "currency", "print_hide": 1, @@ -814,12 +980,16 @@ "collapsible": 1, "fieldname": "loyalty_points_redemption", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Loyalty Points Redemption" }, { "depends_on": "redeem_loyalty_points", "fieldname": "loyalty_points", "fieldtype": "Int", + "hide_days": 1, + "hide_seconds": 1, "label": "Loyalty Points", "no_copy": 1, "print_hide": 1 @@ -828,6 +998,8 @@ "depends_on": "redeem_loyalty_points", "fieldname": "loyalty_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Loyalty Amount", "no_copy": 1, "options": "Company:company:default_currency", @@ -838,18 +1010,24 @@ "default": "0", "fieldname": "redeem_loyalty_points", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Redeem Loyalty Points", "no_copy": 1, "print_hide": 1 }, { "fieldname": "column_break_77", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fetch_from": "customer.loyalty_program", "fieldname": "loyalty_program", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Loyalty Program", "no_copy": 1, "options": "Loyalty Program", @@ -860,6 +1038,8 @@ "depends_on": "redeem_loyalty_points", "fieldname": "loyalty_redemption_account", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Redemption Account", "no_copy": 1, "options": "Account" @@ -868,6 +1048,8 @@ "depends_on": "redeem_loyalty_points", "fieldname": "loyalty_redemption_cost_center", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Redemption Cost Center", "no_copy": 1, "options": "Cost Center" @@ -877,12 +1059,16 @@ "collapsible_depends_on": "discount_amount", "fieldname": "section_break_49", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Additional Discount" }, { "default": "Grand Total", "fieldname": "apply_discount_on", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "label": "Apply Additional Discount On", "options": "\nGrand Total\nNet Total", "print_hide": 1 @@ -890,6 +1076,8 @@ { "fieldname": "base_discount_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Additional Discount Amount (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, @@ -897,17 +1085,23 @@ }, { "fieldname": "column_break_51", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "additional_discount_percentage", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Additional Discount Percentage", "print_hide": 1 }, { "fieldname": "discount_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Additional Discount Amount", "options": "currency", "print_hide": 1 @@ -915,6 +1109,8 @@ { "fieldname": "totals", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Section Break", "options": "fa fa-money", "print_hide": 1 @@ -922,6 +1118,8 @@ { "fieldname": "base_grand_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Grand Total (Company Currency)", "oldfieldname": "grand_total", "oldfieldtype": "Currency", @@ -933,6 +1131,8 @@ { "fieldname": "base_rounding_adjustment", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Rounding Adjustment (Company Currency)", "no_copy": 1, "options": "Company:company:default_currency", @@ -942,6 +1142,8 @@ { "fieldname": "base_rounded_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Rounded Total (Company Currency)", "oldfieldname": "rounded_total", "oldfieldtype": "Currency", @@ -953,6 +1155,8 @@ "description": "In Words will be visible once you save the Sales Invoice.", "fieldname": "base_in_words", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "In Words (Company Currency)", "oldfieldname": "in_words", "oldfieldtype": "Data", @@ -962,6 +1166,8 @@ { "fieldname": "column_break5", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Column Break", "print_hide": 1, "width": "50%" @@ -970,6 +1176,8 @@ "bold": 1, "fieldname": "grand_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "in_list_view": 1, "label": "Grand Total", "oldfieldname": "grand_total_export", @@ -981,6 +1189,8 @@ { "fieldname": "rounding_adjustment", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Rounding Adjustment", "no_copy": 1, "options": "currency", @@ -991,6 +1201,8 @@ "bold": 1, "fieldname": "rounded_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Rounded Total", "oldfieldname": "rounded_total_export", "oldfieldtype": "Currency", @@ -1000,6 +1212,8 @@ { "fieldname": "in_words", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "In Words", "oldfieldname": "in_words_export", "oldfieldtype": "Data", @@ -1009,6 +1223,8 @@ { "fieldname": "total_advance", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Advance", "oldfieldname": "total_advance", "oldfieldtype": "Currency", @@ -1019,6 +1235,8 @@ { "fieldname": "outstanding_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Outstanding Amount", "no_copy": 1, "oldfieldname": "outstanding_amount", @@ -1032,6 +1250,8 @@ "collapsible_depends_on": "advances", "fieldname": "advances_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Advance Payments", "oldfieldtype": "Section Break", "options": "fa fa-money", @@ -1041,18 +1261,24 @@ "default": "0", "fieldname": "allocate_advances_automatically", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Allocate Advances Automatically (FIFO)" }, { "depends_on": "eval:!doc.allocate_advances_automatically", "fieldname": "get_advances", "fieldtype": "Button", + "hide_days": 1, + "hide_seconds": 1, "label": "Get Advances Received", "options": "set_advances" }, { "fieldname": "advances", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Advances", "oldfieldname": "advance_adjustment_details", "oldfieldtype": "Table", @@ -1064,12 +1290,16 @@ "collapsible_depends_on": "eval:(!doc.is_pos && !doc.is_return)", "fieldname": "payment_schedule_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Payment Terms" }, { "depends_on": "eval:(!doc.is_pos && !doc.is_return)", "fieldname": "payment_terms_template", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Payment Terms Template", "no_copy": 1, "options": "Payment Terms Template", @@ -1079,6 +1309,8 @@ "depends_on": "eval:(!doc.is_pos && !doc.is_return)", "fieldname": "payment_schedule", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Payment Schedule", "no_copy": 1, "options": "Payment Schedule", @@ -1088,6 +1320,8 @@ "depends_on": "eval:doc.is_pos===1||(doc.advances && doc.advances.length>0)", "fieldname": "payments_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Payments", "options": "fa fa-money" }, @@ -1096,6 +1330,8 @@ "fieldname": "cash_bank_account", "fieldtype": "Link", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Cash/Bank Account", "oldfieldname": "cash_bank_account", "oldfieldtype": "Link", @@ -1106,17 +1342,23 @@ "depends_on": "eval:doc.is_pos===1", "fieldname": "payments", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Invoice Payment", "options": "Sales Invoice Payment", "print_hide": 1 }, { "fieldname": "section_break_84", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "base_paid_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Paid Amount (Company Currency)", "no_copy": 1, "options": "Company:company:default_currency", @@ -1125,12 +1367,16 @@ }, { "fieldname": "column_break_86", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "depends_on": "eval: doc.is_pos || doc.redeem_loyalty_points", "fieldname": "paid_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Paid Amount", "no_copy": 1, "oldfieldname": "paid_amount", @@ -1141,12 +1387,16 @@ }, { "fieldname": "section_break_88", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "depends_on": "is_pos", "fieldname": "base_change_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Base Change Amount (Company Currency)", "no_copy": 1, "options": "Company:company:default_currency", @@ -1155,12 +1405,16 @@ }, { "fieldname": "column_break_90", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "depends_on": "is_pos", "fieldname": "change_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Change Amount", "no_copy": 1, "options": "currency", @@ -1170,6 +1424,8 @@ "depends_on": "is_pos", "fieldname": "account_for_change_amount", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Account for Change Amount", "options": "Account", "print_hide": 1 @@ -1180,12 +1436,16 @@ "depends_on": "grand_total", "fieldname": "column_break4", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Write Off", "width": "50%" }, { "fieldname": "write_off_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Write Off Amount", "no_copy": 1, "options": "currency", @@ -1194,6 +1454,8 @@ { "fieldname": "base_write_off_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Write Off Amount (Company Currency)", "no_copy": 1, "options": "Company:company:default_currency", @@ -1205,16 +1467,22 @@ "depends_on": "is_pos", "fieldname": "write_off_outstanding_amount_automatically", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Write Off Outstanding Amount", "print_hide": 1 }, { "fieldname": "column_break_74", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "write_off_account", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Write Off Account", "options": "Account", "print_hide": 1 @@ -1222,6 +1490,8 @@ { "fieldname": "write_off_cost_center", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Write Off Cost Center", "options": "Cost Center", "print_hide": 1 @@ -1231,12 +1501,16 @@ "collapsible_depends_on": "terms", "fieldname": "terms_section_break", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Terms and Conditions", "oldfieldtype": "Section Break" }, { "fieldname": "tc_name", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Terms", "oldfieldname": "tc_name", "oldfieldtype": "Link", @@ -1246,6 +1520,8 @@ { "fieldname": "terms", "fieldtype": "Text Editor", + "hide_days": 1, + "hide_seconds": 1, "label": "Terms and Conditions Details", "oldfieldname": "terms", "oldfieldtype": "Text Editor" @@ -1254,12 +1530,16 @@ "collapsible": 1, "fieldname": "edit_printing_settings", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Printing Settings" }, { "allow_on_submit": 1, "fieldname": "letter_head", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Letter Head", "oldfieldname": "letter_head", "oldfieldtype": "Select", @@ -1271,24 +1551,32 @@ "default": "0", "fieldname": "group_same_items", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Group same items", "print_hide": 1 }, { "fieldname": "language", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "Print Language", "print_hide": 1, "read_only": 1 }, { "fieldname": "column_break_84", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "allow_on_submit": 1, "fieldname": "select_print_heading", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Print Heading", "no_copy": 1, "oldfieldname": "select_print_heading", @@ -1302,11 +1590,15 @@ "depends_on": "customer", "fieldname": "more_information", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "More Information" }, { "fieldname": "inter_company_invoice_reference", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Inter Company Invoice Reference", "options": "Purchase Invoice", "read_only": 1 @@ -1315,6 +1607,8 @@ "fieldname": "customer_group", "fieldtype": "Link", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Customer Group", "options": "Customer Group", "print_hide": 1 @@ -1322,6 +1616,8 @@ { "fieldname": "campaign", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Campaign", "oldfieldname": "campaign", "oldfieldtype": "Link", @@ -1332,6 +1628,8 @@ "default": "0", "fieldname": "is_discounted", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Is Discounted", "no_copy": 1, "read_only": 1 @@ -1339,12 +1637,16 @@ { "fieldname": "col_break23", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "width": "50%" }, { "default": "Draft", "fieldname": "status", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "in_standard_filter": 1, "label": "Status", "no_copy": 1, @@ -1355,6 +1657,8 @@ { "fieldname": "source", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Source", "oldfieldname": "source", "oldfieldtype": "Select", @@ -1365,6 +1669,8 @@ "collapsible": 1, "fieldname": "more_info", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Accounting Details", "oldfieldtype": "Section Break", "options": "fa fa-file-text", @@ -1373,6 +1679,8 @@ { "fieldname": "debit_to", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Debit To", "oldfieldname": "debit_to", "oldfieldtype": "Link", @@ -1385,6 +1693,8 @@ "fieldname": "party_account_currency", "fieldtype": "Link", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Party Account Currency", "no_copy": 1, "options": "Currency", @@ -1395,6 +1705,8 @@ "default": "No", "fieldname": "is_opening", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "label": "Is Opening Entry", "oldfieldname": "is_opening", "oldfieldtype": "Select", @@ -1404,6 +1716,8 @@ { "fieldname": "c_form_applicable", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "label": "C-Form Applicable", "no_copy": 1, "options": "No\nYes", @@ -1412,6 +1726,8 @@ { "fieldname": "c_form_no", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "C-Form No", "no_copy": 1, "options": "C-Form", @@ -1421,12 +1737,16 @@ { "fieldname": "column_break8", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Column Break", "print_hide": 1 }, { "fieldname": "remarks", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Remarks", "no_copy": 1, "oldfieldname": "remarks", @@ -1438,6 +1758,8 @@ "collapsible_depends_on": "sales_partner", "fieldname": "sales_team_section_break", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Commission", "oldfieldtype": "Section Break", "options": "fa fa-group", @@ -1446,6 +1768,8 @@ { "fieldname": "sales_partner", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Partner", "oldfieldname": "sales_partner", "oldfieldtype": "Link", @@ -1455,6 +1779,8 @@ { "fieldname": "column_break10", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Column Break", "print_hide": 1, "width": "50%" @@ -1462,6 +1788,8 @@ { "fieldname": "commission_rate", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Commission Rate (%)", "oldfieldname": "commission_rate", "oldfieldtype": "Currency", @@ -1470,6 +1798,8 @@ { "fieldname": "total_commission", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Commission", "oldfieldname": "total_commission", "oldfieldtype": "Currency", @@ -1481,6 +1811,8 @@ "collapsible_depends_on": "sales_team", "fieldname": "section_break2", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Team", "print_hide": 1 }, @@ -1488,6 +1820,8 @@ "allow_on_submit": 1, "fieldname": "sales_team", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Team1", "oldfieldname": "sales_team", "oldfieldtype": "Table", @@ -1495,14 +1829,19 @@ "print_hide": 1 }, { + "collapsible": 1, "fieldname": "subscription_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Subscription Section" }, { "allow_on_submit": 1, "fieldname": "from_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "label": "From Date", "no_copy": 1, "print_hide": 1 @@ -1511,18 +1850,24 @@ "allow_on_submit": 1, "fieldname": "to_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "label": "To Date", "no_copy": 1, "print_hide": 1 }, { "fieldname": "column_break_140", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "allow_on_submit": 1, "fieldname": "auto_repeat", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Auto Repeat", "no_copy": 1, "options": "Auto Repeat", @@ -1534,12 +1879,16 @@ "depends_on": "eval: doc.auto_repeat", "fieldname": "update_auto_repeat_reference", "fieldtype": "Button", + "hide_days": 1, + "hide_seconds": 1, "label": "Update Auto Repeat Reference" }, { "fieldname": "against_income_account", "fieldtype": "Small Text", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Against Income Account", "no_copy": 1, "oldfieldname": "against_income_account", @@ -1551,6 +1900,8 @@ "fieldname": "pos_total_qty", "fieldtype": "Float", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Total Qty", "print_hide": 1, "print_hide_if_no_value": 1, @@ -1560,17 +1911,23 @@ "collapsible": 1, "fieldname": "accounting_dimensions_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Accounting Dimensions" }, { "fieldname": "dimension_col_break", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "default": "0", "fetch_from": "customer.is_internal_customer", "fieldname": "is_internal_customer", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Is Internal Customer", "read_only": 1 } @@ -1579,7 +1936,7 @@ "idx": 181, "is_submittable": 1, "links": [], - "modified": "2020-05-19 17:00:57.208696", + "modified": "2020-06-30 12:00:03.890180", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 5e8279bb08d..bab5208370d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -790,7 +790,8 @@ class SalesInvoice(SellingController): if self.party_account_currency==self.company_currency else grand_total, "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher_type": self.doctype, - "cost_center": self.cost_center + "cost_center": self.cost_center, + "project": self.project }, self.party_account_currency, item=self) ) @@ -845,7 +846,8 @@ class SalesInvoice(SellingController): "credit_in_account_currency": (flt(item.base_net_amount, item.precision("base_net_amount")) if account_currency==self.company_currency else flt(item.net_amount, item.precision("net_amount"))), - "cost_center": item.cost_center + "cost_center": item.cost_center, + "project": item.project or self.project }, account_currency, item=item) ) @@ -926,7 +928,8 @@ class SalesInvoice(SellingController): if self.party_account_currency==self.company_currency else flt(self.change_amount), "against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name, "against_voucher_type": self.doctype, - "cost_center": self.cost_center + "cost_center": self.cost_center, + "project": self.project }, self.party_account_currency, item=self) ) @@ -959,7 +962,8 @@ class SalesInvoice(SellingController): else flt(self.write_off_amount, self.precision("write_off_amount"))), "against_voucher": self.return_against if cint(self.is_return) else self.name, "against_voucher_type": self.doctype, - "cost_center": self.cost_center + "cost_center": self.cost_center, + "project": self.project }, self.party_account_currency, item=self) ) gl_entries.append( @@ -1109,7 +1113,10 @@ class SalesInvoice(SellingController): expiry_date=self.posting_date, include_expired_entry=True) if lp_details and getdate(lp_details.from_date) <= getdate(self.posting_date) and \ (not lp_details.to_date or getdate(lp_details.to_date) >= getdate(self.posting_date)): - points_earned = cint(eligible_amount/lp_details.collection_factor) + + collection_factor = lp_details.collection_factor if lp_details.collection_factor else 1.0 + points_earned = cint(eligible_amount/collection_factor) + doc = frappe.get_doc({ "doctype": "Loyalty Point Entry", "company": self.company, diff --git a/erpnext/accounts/doctype/sales_invoice/test_records.json b/erpnext/accounts/doctype/sales_invoice/test_records.json index ebe6e3da8df..11ebe6a573a 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_records.json +++ b/erpnext/accounts/doctype/sales_invoice/test_records.json @@ -3,6 +3,7 @@ "company": "_Test Company", "conversion_rate": 1.0, "currency": "INR", + "cost_center": "_Test Cost Center - _TC", "customer": "_Test Customer", "customer_name": "_Test Customer", "debit_to": "_Test Receivable - _TC", @@ -37,7 +38,8 @@ "charge_type": "On Net Total", "description": "VAT", "doctype": "Sales Taxes and Charges", - "parentfield": "taxes", + "parentfield": "taxes", + "cost_center": "_Test Cost Center - _TC", "rate": 6 }, { @@ -45,7 +47,8 @@ "charge_type": "On Net Total", "description": "Service Tax", "doctype": "Sales Taxes and Charges", - "parentfield": "taxes", + "parentfield": "taxes", + "cost_center": "_Test Cost Center - _TC", "rate": 6.36 } ], @@ -76,6 +79,7 @@ "customer_name": "_Test Customer", "debit_to": "_Test Receivable - _TC", "doctype": "Sales Invoice", + "cost_center": "_Test Cost Center - _TC", "items": [ { "amount": 500.0, @@ -107,7 +111,8 @@ "charge_type": "On Net Total", "description": "VAT", "doctype": "Sales Taxes and Charges", - "parentfield": "taxes", + "parentfield": "taxes", + "cost_center": "_Test Cost Center - _TC", "rate": 16 }, { @@ -115,7 +120,8 @@ "charge_type": "On Net Total", "description": "Service Tax", "doctype": "Sales Taxes and Charges", - "parentfield": "taxes", + "parentfield": "taxes", + "cost_center": "_Test Cost Center - _TC", "rate": 10 } ], @@ -132,6 +138,7 @@ "customer_name": "_Test Customer", "debit_to": "_Test Receivable - _TC", "doctype": "Sales Invoice", + "cost_center": "_Test Cost Center - _TC", "items": [ { "cost_center": "_Test Cost Center - _TC", @@ -259,6 +266,7 @@ "customer_name": "_Test Customer", "debit_to": "_Test Receivable - _TC", "doctype": "Sales Invoice", + "cost_center": "_Test Cost Center - _TC", "items": [ { "cost_center": "_Test Cost Center - _TC", diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 311cc12dd8d..ff4d6136e9f 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1640,11 +1640,8 @@ class TestSalesInvoice(unittest.TestCase): si_doc = frappe.get_doc('Sales Invoice', si.name) self.assertEqual(si_doc.outstanding_amount, 0) - def test_sales_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self): + def test_sales_invoice_with_cost_center(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - _TC" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company") @@ -1669,14 +1666,47 @@ class TestSalesInvoice(unittest.TestCase): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) + + def test_sales_invoice_with_project_link(self): + from erpnext.projects.doctype.project.test_project import make_project - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() + project = make_project({ + 'project_name': 'Sales Invoice Project', + 'project_template_name': 'Test Project Template', + 'start_date': '2020-01-01' + }) + item_project = make_project({ + 'project_name': 'Sales Invoice Item Project', + 'project_template_name': 'Test Project Template', + 'start_date': '2019-06-01' + }) - def test_sales_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self): - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() + sales_invoice = create_sales_invoice(do_not_save=1) + sales_invoice.items[0].project = item_project.project_name + sales_invoice.project = project.project_name + + sales_invoice.submit() + + expected_values = { + "Debtors - _TC": { + "project": project.project_name + }, + "Sales - _TC": { + "project": item_project.project_name + } + } + + gl_entries = frappe.db.sql("""select account, cost_center, project, account_currency, debit, credit, + debit_in_account_currency, credit_in_account_currency + from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s + order by account asc""", sales_invoice.name, as_dict=1) + + self.assertTrue(gl_entries) + + for gle in gl_entries: + self.assertEqual(expected_values[gle.account]["project"], gle.project) + + def test_sales_invoice_without_cost_center(self): cost_center = "_Test Cost Center - _TC" si = create_sales_invoice(debit_to="Debtors - _TC") @@ -1699,9 +1729,6 @@ class TestSalesInvoice(unittest.TestCase): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - def test_deferred_revenue(self): deferred_account = create_account(account_name="Deferred Revenue", parent_account="Current Liabilities - _TC", company="_Test Company") diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index b2294e4318f..9bc24664d10 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -94,6 +94,7 @@ "accounting_dimensions_section", "cost_center", "dimension_col_break", + "project", "section_break_54", "page_break" ], @@ -783,12 +784,18 @@ "fieldtype": "Link", "label": "Finance Book", "options": "Finance Book" + }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2019-12-04 12:22:38.517710", + "modified": "2020-03-11 12:24:41.749986", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index bfe35ab0068..a245d63f52b 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -140,10 +140,8 @@ def make_entry(args, adv_adj, update_outstanding): gle = frappe.new_doc("GL Entry") gle.update(args) gle.flags.ignore_permissions = 1 - gle.validate() - gle.db_insert() + gle.insert() gle.run_method("on_update_with_args", adv_adj, update_outstanding) - gle.flags.ignore_validate = True gle.submit() # check against budget diff --git a/erpnext/accounts/module_onboarding/accounts/accounts.json b/erpnext/accounts/module_onboarding/accounts/accounts.json index 12da4400284..ba1a779b4c1 100644 --- a/erpnext/accounts/module_onboarding/accounts/accounts.json +++ b/erpnext/accounts/module_onboarding/accounts/accounts.json @@ -13,7 +13,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/accounts", "idx": 0, "is_complete": 0, - "modified": "2020-05-14 22:11:06.475938", + "modified": "2020-07-08 14:06:09.033880", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts", @@ -44,8 +44,7 @@ "step": "Configure Account Settings" } ], - "subtitle": "Accounts, invoices and taxation.", - "success_message": "The Accounts module is now set up!", - "title": "Let's Setup Your Accounts and Taxes.", - "user_can_dismiss": 1 + "subtitle": "Accounts, Invoices, Taxation, and more.", + "success_message": "The Accounts Module is all set up!", + "title": "Let's Set Up Your Accounts and Taxes." } \ No newline at end of file diff --git a/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json b/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json index bb396d268ae..5a403b06cf0 100644 --- a/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json +++ b/erpnext/accounts/onboarding_step/create_a_customer/create_a_customer.json @@ -8,7 +8,7 @@ "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-14 17:46:41.831517", + "modified": "2020-06-01 13:16:19.731719", "modified_by": "Administrator", "name": "Create a Customer", "owner": "Administrator", diff --git a/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json b/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json index 450bee1f40b..d2068e167b7 100644 --- a/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json +++ b/erpnext/accounts/onboarding_step/create_a_product/create_a_product.json @@ -1,6 +1,6 @@ { "action": "Create Entry", - "creation": "2020-05-14 17:45:28.554605", + "creation": "2020-05-12 18:16:06.624554", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, @@ -8,7 +8,7 @@ "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-14 17:45:28.554605", + "modified": "2020-05-12 18:30:02.489949", "modified_by": "Administrator", "name": "Create a Product", "owner": "Administrator", diff --git a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py index 69f9907a8d8..7df090bf62e 100644 --- a/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py +++ b/erpnext/accounts/page/bank_reconciliation/bank_reconciliation.py @@ -21,7 +21,7 @@ def reconcile(bank_transaction, payment_doctype, payment_name): if payment_doctype == "Payment Entry" and payment_entry.unallocated_amount > transaction.unallocated_amount: frappe.throw(_("The unallocated amount of Payment Entry {0} \ is greater than the Bank Transaction's unallocated amount").format(payment_name)) - + if transaction.unallocated_amount == 0: frappe.throw(_("This bank transaction is already fully reconciled")) @@ -289,6 +289,7 @@ def get_matching_transactions_payments(description_matching): else: return [] +@frappe.whitelist() def payment_entry_query(doctype, txt, searchfield, start, page_len, filters): account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account") if not account: @@ -317,6 +318,7 @@ def payment_entry_query(doctype, txt, searchfield, start, page_len, filters): } ) +@frappe.whitelist() def journal_entry_query(doctype, txt, searchfield, start, page_len, filters): account = frappe.db.get_value("Bank Account", filters.get("bank_account"), "account") @@ -352,6 +354,7 @@ def journal_entry_query(doctype, txt, searchfield, start, page_len, filters): } ) +@frappe.whitelist() def sales_invoices_query(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql(""" SELECT diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index db91b6696eb..b764eff12c1 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -388,7 +388,7 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details args = { party_type.lower(): party, - "company": company + "company": company } if tax_category: diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js index 2aa9618e559..6abd6e5cf77 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.js +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js @@ -17,41 +17,6 @@ frappe.query_reports["Accounts Payable"] = { "fieldtype": "Date", "default": frappe.datetime.get_today() }, - { - "fieldname":"ageing_based_on", - "label": __("Ageing Based On"), - "fieldtype": "Select", - "options": 'Posting Date\nDue Date\nSupplier Invoice Date', - "default": "Due Date" - }, - { - "fieldname":"range1", - "label": __("Ageing Range 1"), - "fieldtype": "Int", - "default": "30", - "reqd": 1 - }, - { - "fieldname":"range2", - "label": __("Ageing Range 2"), - "fieldtype": "Int", - "default": "60", - "reqd": 1 - }, - { - "fieldname":"range3", - "label": __("Ageing Range 3"), - "fieldtype": "Int", - "default": "90", - "reqd": 1 - }, - { - "fieldname":"range4", - "label": __("Ageing Range 4"), - "fieldtype": "Int", - "default": "120", - "reqd": 1 - }, { "fieldname":"finance_book", "label": __("Finance Book"), @@ -88,6 +53,41 @@ frappe.query_reports["Accounts Payable"] = { } } }, + { + "fieldname":"ageing_based_on", + "label": __("Ageing Based On"), + "fieldtype": "Select", + "options": 'Posting Date\nDue Date\nSupplier Invoice Date', + "default": "Due Date" + }, + { + "fieldname":"range1", + "label": __("Ageing Range 1"), + "fieldtype": "Int", + "default": "30", + "reqd": 1 + }, + { + "fieldname":"range2", + "label": __("Ageing Range 2"), + "fieldtype": "Int", + "default": "60", + "reqd": 1 + }, + { + "fieldname":"range3", + "label": __("Ageing Range 3"), + "fieldtype": "Int", + "default": "90", + "reqd": 1 + }, + { + "fieldname":"range4", + "label": __("Ageing Range 4"), + "fieldtype": "Int", + "default": "120", + "reqd": 1 + }, { "fieldname":"payment_terms_template", "label": __("Payment Terms Template"), diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js index 8dc558a611d..c999eb9b8e9 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js @@ -17,41 +17,6 @@ frappe.query_reports["Accounts Receivable"] = { "fieldtype": "Date", "default": frappe.datetime.get_today() }, - { - "fieldname":"ageing_based_on", - "label": __("Ageing Based On"), - "fieldtype": "Select", - "options": 'Posting Date\nDue Date', - "default": "Due Date" - }, - { - "fieldname":"range1", - "label": __("Ageing Range 1"), - "fieldtype": "Int", - "default": "30", - "reqd": 1 - }, - { - "fieldname":"range2", - "label": __("Ageing Range 2"), - "fieldtype": "Int", - "default": "60", - "reqd": 1 - }, - { - "fieldname":"range3", - "label": __("Ageing Range 3"), - "fieldtype": "Int", - "default": "90", - "reqd": 1 - }, - { - "fieldname":"range4", - "label": __("Ageing Range 4"), - "fieldtype": "Int", - "default": "120", - "reqd": 1 - }, { "fieldname":"finance_book", "label": __("Finance Book"), @@ -101,6 +66,41 @@ frappe.query_reports["Accounts Receivable"] = { } } }, + { + "fieldname":"ageing_based_on", + "label": __("Ageing Based On"), + "fieldtype": "Select", + "options": 'Posting Date\nDue Date', + "default": "Due Date" + }, + { + "fieldname":"range1", + "label": __("Ageing Range 1"), + "fieldtype": "Int", + "default": "30", + "reqd": 1 + }, + { + "fieldname":"range2", + "label": __("Ageing Range 2"), + "fieldtype": "Int", + "default": "60", + "reqd": 1 + }, + { + "fieldname":"range3", + "label": __("Ageing Range 3"), + "fieldtype": "Int", + "default": "90", + "reqd": 1 + }, + { + "fieldname":"range4", + "label": __("Ageing Range 4"), + "fieldtype": "Int", + "default": "120", + "reqd": 1 + }, { "fieldname":"customer_group", "label": __("Customer Group"), @@ -113,12 +113,6 @@ frappe.query_reports["Accounts Receivable"] = { "fieldtype": "Link", "options": "Payment Terms Template" }, - { - "fieldname":"territory", - "label": __("Territory"), - "fieldtype": "Link", - "options": "Territory" - }, { "fieldname":"sales_partner", "label": __("Sales Partner"), @@ -131,6 +125,12 @@ frappe.query_reports["Accounts Receivable"] = { "fieldtype": "Link", "options": "Sales Person" }, + { + "fieldname":"territory", + "label": __("Territory"), + "fieldtype": "Link", + "options": "Territory" + }, { "fieldname": "group_by_party", "label": __("Group By Customer"), diff --git a/erpnext/accounts/report/financial_statements.html b/erpnext/accounts/report/financial_statements.html index 50947ecf5ef..2bb09cf0dc5 100644 --- a/erpnext/accounts/report/financial_statements.html +++ b/erpnext/accounts/report/financial_statements.html @@ -44,7 +44,7 @@ - {% for(let j=0, k=data.length-1; j getdate(nowdate()): # if fiscal year not found and the date is greater than today @@ -144,14 +144,12 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, company # hence, assuming balance as 0.0 return 0.0 - allow_cost_center_in_entry_of_bs_account = get_allow_cost_center_in_entry_of_bs_account() - if account: report_type = acc.report_type else: report_type = "" - if cost_center and (allow_cost_center_in_entry_of_bs_account or report_type =='Profit and Loss'): + if cost_center and report_type == 'Profit and Loss': cc = frappe.get_doc("Cost Center", cost_center) if cc.is_group: cond.append(""" exists ( @@ -787,10 +785,10 @@ def get_children(doctype, parent, company, is_root=False): company_currency = frappe.get_cached_value('Company', company, "default_currency") for each in acc: each["company_currency"] = company_currency - each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False)) + each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False, company=company)) if each.account_currency != company_currency: - each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"))) + each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"), company=company)) return acc @@ -897,11 +895,6 @@ def get_coa(doctype, parent, is_root, chart=None): return accounts -def get_allow_cost_center_in_entry_of_bs_account(): - def generator(): - return cint(frappe.db.get_value('Accounts Settings', None, 'allow_cost_center_in_entry_of_bs_account')) - return frappe.local_cache("get_allow_cost_center_in_entry_of_bs_account", (), generator, regenerate_if_none=True) - def get_stock_accounts(company): return frappe.get_all("Account", filters = { "account_type": "Stock", diff --git a/erpnext/assets/desk_page/assets/assets.json b/erpnext/assets/desk_page/assets/assets.json index 94939fdd2a2..449a5facb08 100644 --- a/erpnext/assets/desk_page/assets/assets.json +++ b/erpnext/assets/desk_page/assets/assets.json @@ -58,7 +58,7 @@ "type": "Report" }, { - "label": "Assets Dashboard", + "label": "Dashboard", "link_to": "Asset", "type": "Dashboard" } diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 9ae5a87e6bc..0bd03a8dbe2 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -35,11 +35,9 @@ class Asset(AccountsController): if not self.booked_fixed_asset and self.validate_make_gl_entry(): self.make_gl_entries() - def before_cancel(self): - self.cancel_auto_gen_movement() - def on_cancel(self): self.validate_cancellation() + self.cancel_movement_entries() self.delete_depreciation_entries() self.set_status() self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry') @@ -134,19 +132,6 @@ class Asset(AccountsController): Please do not book expense of multiple assets against one single Asset.") .format(frappe.bold("equal"), "
"), title=_("Invalid Gross Purchase Amount")) - def cancel_auto_gen_movement(self): - movements = frappe.db.sql( - """SELECT asm.name, asm.docstatus - FROM `tabAsset Movement` asm, `tabAsset Movement Item` asm_item - WHERE asm_item.parent=asm.name and asm_item.asset=%s and asm.docstatus=1""", self.name, as_dict=1) - if len(movements) > 1: - frappe.throw(_('Asset has multiple Asset Movement Entries which has to be \ - cancelled manually to cancel this asset.')) - if movements: - movement = frappe.get_doc('Asset Movement', movements[0].get('name')) - movement.flags.ignore_validate = True - movement.cancel() - def make_asset_movement(self): reference_doctype = 'Purchase Receipt' if self.purchase_receipt else 'Purchase Invoice' reference_docname = self.purchase_receipt or self.purchase_invoice @@ -413,6 +398,16 @@ class Asset(AccountsController): if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"): frappe.throw(_("Asset cannot be cancelled, as it is already {0}").format(self.status)) + def cancel_movement_entries(self): + movements = frappe.db.sql( + """SELECT asm.name, asm.docstatus + FROM `tabAsset Movement` asm, `tabAsset Movement Item` asm_item + WHERE asm_item.parent=asm.name and asm_item.asset=%s and asm.docstatus=1""", self.name, as_dict=1) + + for movement in movements: + movement = frappe.get_doc('Asset Movement', movement.get('name')) + movement.cancel() + def delete_depreciation_entries(self): for d in self.get("schedules"): if d.journal_entry: diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 522c1fef679..8f0afb42b2c 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -10,7 +10,7 @@ from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import g def post_depreciation_entries(date=None): # Return if automatic booking of asset depreciation is disabled - if not cint(frappe.db.get_single_value("Accounts Settings", "book_asset_depreciation_entry_automatically")): + if not cint(frappe.db.get_value("Accounts Settings", None, "book_asset_depreciation_entry_automatically")): return if not date: @@ -58,7 +58,8 @@ def make_depreciation_entry(asset_name, date=None): "account": accumulated_depreciation_account, "credit_in_account_currency": d.depreciation_amount, "reference_type": "Asset", - "reference_name": asset.name + "reference_name": asset.name, + "cost_center": "" } debit_entry = { @@ -196,12 +197,14 @@ def get_gl_entries_on_asset_disposal(asset, selling_amount=0, finance_book=None) { "account": fixed_asset_account, "credit_in_account_currency": asset.gross_purchase_amount, - "credit": asset.gross_purchase_amount + "credit": asset.gross_purchase_amount, + "cost_center": depreciation_cost_center }, { "account": accumulated_depr_account, "debit_in_account_currency": accumulated_depr_amount, - "debit": accumulated_depr_amount + "debit": accumulated_depr_amount, + "cost_center": depreciation_cost_center } ] diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index 3da355e2b99..b2de250b168 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -87,33 +87,9 @@ class AssetMovement(Document): def on_submit(self): self.set_latest_location_in_asset() - - def before_cancel(self): - self.validate_last_movement() def on_cancel(self): self.set_latest_location_in_asset() - - def validate_last_movement(self): - for d in self.assets: - auto_gen_movement_entry = frappe.db.sql( - """ - SELECT asm.name - FROM `tabAsset Movement Item` asm_item, `tabAsset Movement` asm - WHERE - asm.docstatus=1 and - asm_item.parent=asm.name and - asm_item.asset=%s and - asm.company=%s and - asm_item.source_location is NULL and - asm.purpose=%s - ORDER BY - asm.transaction_date asc - """, (d.asset, self.company, 'Receipt'), as_dict=1) - - if auto_gen_movement_entry and auto_gen_movement_entry[0].get('name') == self.name: - frappe.throw(_('{0} will be cancelled automatically on asset cancellation as it was \ - auto generated for Asset {1}').format(self.name, d.asset)) def set_latest_location_in_asset(self): current_location, current_employee = '', '' diff --git a/erpnext/assets/module_onboarding/assets/assets.json b/erpnext/assets/module_onboarding/assets/assets.json index 66dd60ae81f..1086ab4bcdb 100644 --- a/erpnext/assets/module_onboarding/assets/assets.json +++ b/erpnext/assets/module_onboarding/assets/assets.json @@ -13,7 +13,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/asset", "idx": 0, "is_complete": 0, - "modified": "2020-05-08 16:17:31.685943", + "modified": "2020-07-08 14:05:51.828497", "modified_by": "Administrator", "module": "Assets", "name": "Assets", @@ -27,7 +27,7 @@ }, { "step": "Create an Asset Category" - }, + }, { "step": "Purchase an Asset Item" }, @@ -35,8 +35,7 @@ "step": "Create an Asset" } ], - "subtitle": "Assets, Depreciations, Repairs and more", - "success_message": "The Asset Module is all set up!", - "title": "Let's Setup Asset Management", - "user_can_dismiss": 1 + "subtitle": "Assets, Depreciations, Repairs, and more.", + "success_message": "The Assets Module is all set up!", + "title": "Let's Set Up the Assets Module." } \ No newline at end of file diff --git a/erpnext/assets/onboarding_step/create_a_fixed_asset_item/create_a_fixed_asset_item.json b/erpnext/assets/onboarding_step/create_a_fixed_asset_item/create_a_fixed_asset_item.json index f5818c091f1..51702d9cb52 100644 --- a/erpnext/assets/onboarding_step/create_a_fixed_asset_item/create_a_fixed_asset_item.json +++ b/erpnext/assets/onboarding_step/create_a_fixed_asset_item/create_a_fixed_asset_item.json @@ -6,11 +6,14 @@ "idx": 0, "is_complete": 0, "is_mandatory": 0, + "is_single": 0, "is_skipped": 0, "modified": "2020-05-08 13:20:00.259985", "modified_by": "Administrator", "name": "Create a Fixed Asset Item", "owner": "Administrator", "reference_document": "Item", - "title": "Create a Fixed Asset Item" + "show_full_form": 0, + "title": "Create a Fixed Asset Item", + "validate_action": 0 } \ No newline at end of file diff --git a/erpnext/assets/onboarding_step/create_an_asset/create_an_asset.json b/erpnext/assets/onboarding_step/create_an_asset/create_an_asset.json index 5488b1d7b4e..b4f8a05e378 100644 --- a/erpnext/assets/onboarding_step/create_an_asset/create_an_asset.json +++ b/erpnext/assets/onboarding_step/create_an_asset/create_an_asset.json @@ -6,11 +6,14 @@ "idx": 0, "is_complete": 0, "is_mandatory": 0, + "is_single": 0, "is_skipped": 0, "modified": "2020-05-08 13:21:53.332538", "modified_by": "Administrator", "name": "Create an Asset", "owner": "Administrator", "reference_document": "Asset", - "title": "Create an Asset" + "show_full_form": 0, + "title": "Create an Asset", + "validate_action": 0 } \ No newline at end of file diff --git a/erpnext/assets/onboarding_step/create_an_asset_category/create_an_asset_category.json b/erpnext/assets/onboarding_step/create_an_asset_category/create_an_asset_category.json index 3bf54af348a..ffdb954b951 100644 --- a/erpnext/assets/onboarding_step/create_an_asset_category/create_an_asset_category.json +++ b/erpnext/assets/onboarding_step/create_an_asset_category/create_an_asset_category.json @@ -1,16 +1,19 @@ { - "action": "Create Entry", - "creation": "2020-05-08 13:21:53.332538", - "docstatus": 0, - "doctype": "Onboarding Step", - "idx": 0, - "is_complete": 0, - "is_mandatory": 0, - "is_skipped": 0, - "modified": "2020-05-08 13:21:53.332538", - "modified_by": "Administrator", - "name": "Create an Asset Category", - "owner": "Administrator", - "reference_document": "Asset Category", - "title": "Create an Asset Category" - } \ No newline at end of file + "action": "Create Entry", + "creation": "2020-05-08 13:21:53.332538", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_mandatory": 0, + "is_single": 0, + "is_skipped": 0, + "modified": "2020-05-08 13:21:53.332538", + "modified_by": "Administrator", + "name": "Create an Asset Category", + "owner": "Administrator", + "reference_document": "Asset Category", + "show_full_form": 0, + "title": "Create an Asset Category", + "validate_action": 0 +} \ No newline at end of file diff --git a/erpnext/assets/onboarding_step/introduction_to_assets/introduction_to_assets.json b/erpnext/assets/onboarding_step/introduction_to_assets/introduction_to_assets.json index d48dd1cd3d2..d89da271971 100644 --- a/erpnext/assets/onboarding_step/introduction_to_assets/introduction_to_assets.json +++ b/erpnext/assets/onboarding_step/introduction_to_assets/introduction_to_assets.json @@ -6,11 +6,14 @@ "idx": 0, "is_complete": 0, "is_mandatory": 0, + "is_single": 0, "is_skipped": 0, "modified": "2020-05-08 16:06:16.625646", "modified_by": "Administrator", "name": "Introduction to Assets", "owner": "Administrator", + "show_full_form": 0, "title": "Introduction to Assets", + "validate_action": 0, "video_url": "https://www.youtube.com/watch?v=I-K8pLRmvSo" } \ No newline at end of file diff --git a/erpnext/assets/onboarding_step/purchase_an_asset_item/purchase_an_asset_item.json b/erpnext/assets/onboarding_step/purchase_an_asset_item/purchase_an_asset_item.json index 732ff7f733b..ce3185ef449 100644 --- a/erpnext/assets/onboarding_step/purchase_an_asset_item/purchase_an_asset_item.json +++ b/erpnext/assets/onboarding_step/purchase_an_asset_item/purchase_an_asset_item.json @@ -6,11 +6,14 @@ "idx": 0, "is_complete": 0, "is_mandatory": 0, + "is_single": 0, "is_skipped": 0, "modified": "2020-05-08 13:21:28.208059", "modified_by": "Administrator", "name": "Purchase an Asset Item", "owner": "Administrator", "reference_document": "Purchase Receipt", - "title": "Purchase an Asset Item" + "show_full_form": 0, + "title": "Purchase an Asset Item", + "validate_action": 0 } \ No newline at end of file diff --git a/erpnext/buying/desk_page/buying/buying.json b/erpnext/buying/desk_page/buying/buying.json index bddb9573ad5..565d39c3c83 100644 --- a/erpnext/buying/desk_page/buying/buying.json +++ b/erpnext/buying/desk_page/buying/buying.json @@ -33,7 +33,7 @@ { "hidden": 0, "label": "Other Reports", - "links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Items To Be Requested\",\n \"name\": \"Items To Be Requested\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase History\",\n \"name\": \"Item-wise Purchase History\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Subcontracted Raw Materials To Be Transferred\",\n \"name\": \"Subcontracted Raw Materials To Be Transferred\",\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Subcontracted Item To Be Received\",\n \"name\": \"Subcontracted Item To Be Received\",\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Quoted Item Comparison\",\n \"name\": \"Quoted Item Comparison\",\n \"onboard\": 1,\n \"reference_doctype\": \"Supplier Quotation\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Material Requests for which Supplier Quotations are not created\",\n \"name\": \"Material Requests for which Supplier Quotations are not created\",\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"reference_doctype\": \"Address\",\n \"route_options\": {\n \"party_type\": \"Supplier\"\n },\n \"type\": \"report\"\n }\n]" + "links": "[\n {\n \"is_query_report\": true,\n \"label\": \"Items To Be Requested\",\n \"name\": \"Items To Be Requested\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Item-wise Purchase History\",\n \"name\": \"Item-wise Purchase History\",\n \"onboard\": 1,\n \"reference_doctype\": \"Item\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Receipt Trends\",\n \"name\": \"Purchase Receipt Trends\",\n \"reference_doctype\": \"Purchase Receipt\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Purchase Invoice Trends\",\n \"name\": \"Purchase Invoice Trends\",\n \"reference_doctype\": \"Purchase Invoice\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Subcontracted Raw Materials To Be Transferred\",\n \"name\": \"Subcontracted Raw Materials To Be Transferred\",\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Subcontracted Item To Be Received\",\n \"name\": \"Subcontracted Item To Be Received\",\n \"reference_doctype\": \"Purchase Order\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Quoted Item Comparison\",\n \"name\": \"Quoted Item Comparison\",\n \"onboard\": 1,\n \"reference_doctype\": \"Supplier Quotation\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Material Requests for which Supplier Quotations are not created\",\n \"name\": \"Material Requests for which Supplier Quotations are not created\",\n \"reference_doctype\": \"Material Request\",\n \"type\": \"report\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Supplier Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"reference_doctype\": \"Address\",\n \"route_options\": {\n \"party_type\": \"Supplier\"\n },\n \"type\": \"report\"\n }\n]" }, { "hidden": 0, @@ -60,7 +60,7 @@ "idx": 0, "is_standard": 1, "label": "Buying", - "modified": "2020-05-28 13:32:49.960574", + "modified": "2020-06-29 19:30:24.983050", "modified_by": "Administrator", "module": "Buying", "name": "Buying", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index 4a8146a797a..84e3a31904d 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -123,14 +123,14 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( } if(doc.status != "Closed") { if (doc.status != "On Hold") { - if(flt(doc.per_received, 2) < 100 && allow_receipt) { + if(flt(doc.per_received) < 100 && allow_receipt) { cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create')); if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) { cur_frm.add_custom_button(__('Material to Supplier'), function() { me.make_stock_entry(); }, __("Transfer")); } } - if(flt(doc.per_billed, 2) < 100) + if(flt(doc.per_billed) < 100) cur_frm.add_custom_button(__('Invoice'), this.make_purchase_invoice, __('Create')); diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js index 455bd68ecff..4a937f7f0d3 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js @@ -166,7 +166,8 @@ frappe.ui.form.on("Request for Quotation",{ { "fieldtype": "Select", "label": __("Supplier"), "fieldname": "supplier", "options": doc.suppliers.map(d => d.supplier), - "reqd": 1 }, + "reqd": 1, + "default": doc.suppliers.length === 1 ? doc.suppliers[0].supplier_name : "" }, { "fieldtype": "Button", "label": __('Create Supplier Quotation'), "fieldname": "make_supplier_quotation", "cssClass": "btn-primary" }, ] diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json index 97aa9221e2f..5cd8e6f4fa8 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json @@ -1,4 +1,5 @@ { + "actions": "", "allow_import": 1, "autoname": "naming_series:", "creation": "2016-02-25 01:24:07.224790", @@ -28,7 +29,6 @@ "letter_head", "more_info", "status", - "fiscal_year", "column_break3", "amended_from" ], @@ -218,17 +218,6 @@ "reqd": 1, "search_index": 1 }, - { - "fieldname": "fiscal_year", - "fieldtype": "Link", - "label": "Fiscal Year", - "oldfieldname": "fiscal_year", - "oldfieldtype": "Select", - "options": "Fiscal Year", - "print_hide": 1, - "reqd": 1, - "search_index": 1 - }, { "fieldname": "column_break3", "fieldtype": "Column Break" @@ -245,7 +234,8 @@ ], "icon": "fa fa-shopping-cart", "is_submittable": 1, - "modified": "2019-09-24 15:08:32.750661", + "links": [], + "modified": "2020-06-25 14:37:21.140194", "modified_by": "Administrator", "module": "Buying", "name": "Request for Quotation", diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index 56af4d90279..4b852300e5f 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -206,6 +206,7 @@ def get_list_context(context=None): }) return list_context +@frappe.whitelist() def get_supplier_contacts(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select `tabContact`.name from `tabContact`, `tabDynamic Link` where `tabDynamic Link`.link_doctype = 'Supplier' and (`tabDynamic Link`.link_name=%(name)s diff --git a/erpnext/buying/module_onboarding/buying/buying.json b/erpnext/buying/module_onboarding/buying/buying.json index 6e4bbc95a24..887f85b82d1 100644 --- a/erpnext/buying/module_onboarding/buying/buying.json +++ b/erpnext/buying/module_onboarding/buying/buying.json @@ -19,7 +19,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/buying", "idx": 0, "is_complete": 0, - "modified": "2020-06-01 12:55:09.234944", + "modified": "2020-07-08 14:05:28.273641", "modified_by": "Administrator", "module": "Buying", "name": "Buying", @@ -47,8 +47,7 @@ "step": "Buying Settings" } ], - "subtitle": "Products, Purchases, Analysis and more.", + "subtitle": "Products, Purchases, Analysis, and more.", "success_message": "The Buying Module is all set up!", - "title": "Let's Set Up the Buying Module.", - "user_can_dismiss": 1 + "title": "Let's Set Up the Buying Module." } \ No newline at end of file diff --git a/erpnext/buying/onboarding_step/buying_settings/buying_settings.json b/erpnext/buying/onboarding_step/buying_settings/buying_settings.json index 6d765af1373..a788ccd4cc9 100644 --- a/erpnext/buying/onboarding_step/buying_settings/buying_settings.json +++ b/erpnext/buying/onboarding_step/buying_settings/buying_settings.json @@ -1,19 +1,19 @@ { - "action": "Show Form Tour", + "action": "Update Settings", "creation": "2020-05-06 15:53:44.667414", "docstatus": 0, "doctype": "Onboarding Step", "idx": 0, "is_complete": 0, - "is_mandatory": 1, - "is_single": 1, + "is_mandatory": 0, + "is_single": 0, "is_skipped": 0, - "modified": "2020-06-01 12:52:57.668870", + "modified": "2020-05-12 18:30:06.323797", "modified_by": "Administrator", "name": "Buying Settings", "owner": "Administrator", "reference_document": "Buying Settings", "show_full_form": 0, "title": "Configure Buying Settings.", - "validate_action": 0 + "validate_action": 1 } \ No newline at end of file diff --git a/erpnext/buying/onboarding_step/setup_your_warehouse/setup_your_warehouse.json b/erpnext/buying/onboarding_step/setup_your_warehouse/setup_your_warehouse.json index 557c905bd6c..9457deee262 100644 --- a/erpnext/buying/onboarding_step/setup_your_warehouse/setup_your_warehouse.json +++ b/erpnext/buying/onboarding_step/setup_your_warehouse/setup_your_warehouse.json @@ -8,13 +8,13 @@ "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-19 18:54:19.383397", + "modified": "2020-07-04 12:33:16.970031", "modified_by": "Administrator", "name": "Setup your Warehouse", "owner": "Administrator", "path": "Tree/Warehouse", "reference_document": "Warehouse", "show_full_form": 0, - "title": "Setup your Warehouse", + "title": "Set up your Warehouse", "validate_action": 1 } \ No newline at end of file diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py index c7204a1f341..44ab767c0a9 100644 --- a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py +++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py @@ -67,4 +67,5 @@ class TestProcurementTracker(unittest.TestCase): "expected_delivery_date": date_obj, "actual_delivery_date": date_obj } + return expected_data \ No newline at end of file diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index f6a8d27d440..31e34987be8 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -10,7 +10,8 @@ from collections import defaultdict from erpnext.stock.get_item_details import _get_item_tax_template from frappe.utils import unique - # searches for active employees +# searches for active employees +@frappe.whitelist() def employee_query(doctype, txt, searchfield, start, page_len, filters): conditions = [] fields = get_fields("Employee", ["name", "employee_name"]) @@ -40,6 +41,7 @@ def employee_query(doctype, txt, searchfield, start, page_len, filters): # searches for leads which are not converted +@frappe.whitelist() def lead_query(doctype, txt, searchfield, start, page_len, filters): fields = get_fields("Lead", ["name", "lead_name", "company_name"]) @@ -69,6 +71,7 @@ def lead_query(doctype, txt, searchfield, start, page_len, filters): # searches for customer +@frappe.whitelist() def customer_query(doctype, txt, searchfield, start, page_len, filters): conditions = [] cust_master_name = frappe.defaults.get_user_default("cust_master_name") @@ -106,6 +109,7 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters): # searches for supplier +@frappe.whitelist() def supplier_query(doctype, txt, searchfield, start, page_len, filters): supp_master_name = frappe.defaults.get_user_default("supp_master_name") if supp_master_name == "Supplier Name": @@ -137,6 +141,7 @@ def supplier_query(doctype, txt, searchfield, start, page_len, filters): }) +@frappe.whitelist() def tax_account_query(doctype, txt, searchfield, start, page_len, filters): company_currency = erpnext.get_company_currency(filters.get('company')) @@ -162,6 +167,7 @@ def tax_account_query(doctype, txt, searchfield, start, page_len, filters): return tax_accounts +@frappe.whitelist() def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False): conditions = [] @@ -224,6 +230,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals }, as_dict=as_dict) +@frappe.whitelist() def bom(doctype, txt, searchfield, start, page_len, filters): conditions = [] fields = get_fields("BOM", ["name", "item"]) @@ -250,6 +257,7 @@ def bom(doctype, txt, searchfield, start, page_len, filters): }) +@frappe.whitelist() def get_project_name(doctype, txt, searchfield, start, page_len, filters): cond = '' if filters.get('customer'): @@ -276,6 +284,7 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters): }) +@frappe.whitelist() def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters, as_dict): fields = get_fields("Delivery Note", ["name", "customer", "posting_date"]) @@ -305,6 +314,7 @@ def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, }, {"txt": ("%%%s%%" % txt)}, as_dict=as_dict) +@frappe.whitelist() def get_batch_no(doctype, txt, searchfield, start, page_len, filters): cond = "" if filters.get("posting_date"): @@ -362,6 +372,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters): limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args) +@frappe.whitelist() def get_account_list(doctype, txt, searchfield, start, page_len, filters): filter_list = [] @@ -385,6 +396,7 @@ def get_account_list(doctype, txt, searchfield, start, page_len, filters): limit_start=start, limit_page_length=page_len, as_list=True) +@frappe.whitelist() 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 @@ -570,7 +582,8 @@ def get_tax_template(doctype, txt, searchfield, start, page_len, filters): args = { 'item_code': filters.get('item_code'), 'posting_date': filters.get('valid_from'), - 'tax_category': filters.get('tax_category') + 'tax_category': filters.get('tax_category'), + 'company': filters.get('company') } taxes = _get_item_tax_template(args, taxes, for_validate=True) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 759c6cd73eb..e8483da5441 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -96,6 +96,7 @@ class StockController(AccountsController): "account": warehouse_account[sle.warehouse]["account"], "against": item_row.expense_account, "cost_center": item_row.cost_center, + "project": item_row.project or self.get('project'), "remarks": self.get("remarks") or "Accounting Entry for Stock", "debit": flt(sle.stock_value_difference, precision), "is_opening": item_row.get("is_opening") or self.get("is_opening") or "No", @@ -106,6 +107,7 @@ class StockController(AccountsController): "account": item_row.expense_account, "against": warehouse_account[sle.warehouse]["account"], "cost_center": item_row.cost_center, + "project": item_row.project or self.get('project'), "remarks": self.get("remarks") or "Accounting Entry for Stock", "credit": flt(sle.stock_value_difference, precision), "project": item_row.get("project") or self.get("project"), diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 4e568e2795a..a9eb9963bfe 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -53,7 +53,8 @@ class calculate_taxes_and_totals(object): 'tax_category': self.doc.get('tax_category'), 'posting_date': self.doc.get('posting_date'), 'bill_date': self.doc.get('bill_date'), - 'transaction_date': self.doc.get('transaction_date') + 'transaction_date': self.doc.get('transaction_date'), + 'company': self.doc.get('company') } item_group = item_doc.item_group diff --git a/erpnext/controllers/tests/test_mapper.py b/erpnext/controllers/tests/test_mapper.py index 8839e002a4c..66459fdbf8a 100644 --- a/erpnext/controllers/tests/test_mapper.py +++ b/erpnext/controllers/tests/test_mapper.py @@ -13,14 +13,12 @@ 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, 'disabled': 0}) - customers = frappe.get_all("Customer") - if items and customers: - # Make source docs (quotations) and a target doc (sales order) - customer = random.choice(customers).name - qtn1, item_list_1 = self.make_quotation(items, customer) - qtn2, item_list_2 = self.make_quotation(items, customer) - so, item_list_3 = self.make_sales_order() + items = ['_Test Item', '_Test Item 2', '_Test FG Item'] + + # Make source docs (quotations) and a target doc (sales order) + qtn1, item_list_1 = self.make_quotation(items, '_Test Customer') + qtn2, item_list_2 = self.make_quotation(items, '_Test Customer') + so, item_list_3 = self.make_sales_order() # Map source docs to target with corresponding mapper method method = "erpnext.selling.doctype.quotation.quotation.make_sales_order" @@ -28,18 +26,12 @@ class TestMapper(unittest.TestCase): # Assert that all inserted items are present in updated sales order src_items = item_list_1 + item_list_2 + item_list_3 - self.assertEqual(set([d.item_code for d in src_items]), + self.assertEqual(set([d for d in src_items]), set([d.item_code for d in updated_so.items])) - def get_random_items(self, items, limit): - '''Get a number of random items from a list of given items''' - random_items = [] - for i in range(0, limit): - random_items.append(random.choice(items)) - return random_items - def make_quotation(self, items, customer): - item_list = self.get_random_items(items, 3) + def make_quotation(self, item_list, customer): + qtn = frappe.get_doc({ "doctype": "Quotation", "quotation_to": "Customer", @@ -49,7 +41,7 @@ class TestMapper(unittest.TestCase): "valid_till" : add_months(nowdate(), 1) }) for item in item_list: - qtn.append("items", {"qty": "2", "item_code": item.item_code}) + qtn.append("items", {"qty": "2", "item_code": item}) qtn.submit() return qtn, item_list @@ -60,7 +52,7 @@ class TestMapper(unittest.TestCase): "base_rate": 100.0, "description": "CPU", "doctype": "Sales Order Item", - "item_code": "_Test Item Home Desktop 100", + "item_code": "_Test Item", "item_name": "CPU", "parentfield": "items", "qty": 10.0, @@ -72,4 +64,4 @@ class TestMapper(unittest.TestCase): }) so = frappe.get_doc(frappe.get_test_records('Sales Order')[0]) so.insert(ignore_permissions=True) - return so, [item] + return so, [item.item_code] diff --git a/erpnext/controllers/tests/test_qty_based_taxes.py b/erpnext/controllers/tests/test_qty_based_taxes.py index fd9936bae99..aaeac5d9399 100644 --- a/erpnext/controllers/tests/test_qty_based_taxes.py +++ b/erpnext/controllers/tests/test_qty_based_taxes.py @@ -30,6 +30,7 @@ class TestTaxes(unittest.TestCase): self.item_tax_template = frappe.get_doc({ 'doctype': 'Item Tax Template', 'title': uuid4(), + 'company': self.company.name, 'taxes': [ { 'tax_type': self.account.name, diff --git a/erpnext/crm/dashboard_fixtures.py b/erpnext/crm/dashboard_fixtures.py index 0535cbbcc95..901c0581f4c 100644 --- a/erpnext/crm/dashboard_fixtures.py +++ b/erpnext/crm/dashboard_fixtures.py @@ -172,7 +172,9 @@ def get_number_cards(): "doctype": "Number Card", "document_type": "Lead", "name": "New Lead (Last 1 Month)", - "filters_json": json.dumps([["Lead","creation","Previous","1 month",False]]), + "filters_json": json.dumps([ + ["Lead", "creation", "Timespan", "last month"] + ]), "function": "Count", "is_public": 1, "label": _("New Lead (Last 1 Month)"), @@ -183,7 +185,9 @@ def get_number_cards(): "doctype": "Number Card", "document_type": "Opportunity", "name": "New Opportunity (Last 1 Month)", - "filters_json": json.dumps([["Opportunity","creation","Previous","1 month",False]]), + "filters_json": json.dumps([ + ["Opportunity", "creation", "Timespan", "last month"] + ]), "function": "Count", "is_public": 1, "label": _("New Opportunity (Last 1 Month)"), @@ -194,7 +198,10 @@ def get_number_cards(): "doctype": "Number Card", "document_type": "Opportunity", "name": "Won Opportunity (Last 1 Month)", - "filters_json": json.dumps([["Opportunity","creation","Previous","1 month",False]]), + "filters_json": json.dumps([ + ["Opportunity", "status", "=", "Converted",False], + ["Opportunity", "creation", "Timespan", "last month"] + ]), "function": "Count", "is_public": 1, "label": _("Won Opportunity (Last 1 Month)"), diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index ec7d14d6ae3..315d298eb43 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -114,10 +114,12 @@ class Lead(SellingController): def set_lead_name(self): if not self.lead_name: # Check for leads being created through data import - if not self.company_name and not self.flags.ignore_mandatory: + if not self.company_name and not self.email_id and not self.flags.ignore_mandatory: frappe.throw(_("A Lead requires either a person's name or an organization's name")) - - self.lead_name = self.company_name + elif self.company_name: + self.lead_name = self.company_name + else: + self.lead_name = self.email_id.split("@")[0] def set_title(self): if self.organization_lead: diff --git a/erpnext/crm/module_onboarding/crm/crm.json b/erpnext/crm/module_onboarding/crm/crm.json index 44d672a7b59..8315218c842 100644 --- a/erpnext/crm/module_onboarding/crm/crm.json +++ b/erpnext/crm/module_onboarding/crm/crm.json @@ -16,7 +16,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/CRM", "idx": 0, "is_complete": 0, - "modified": "2020-05-28 21:07:41.278784", + "modified": "2020-07-08 14:05:42.644448", "modified_by": "Administrator", "module": "CRM", "name": "CRM", @@ -35,8 +35,7 @@ "step": "Create and Send Quotation" } ], - "subtitle": "Lead, Opportunity, Customer and more.", - "success_message": "CRM Module is all Set Up!", - "title": "Let's Set Up Your CRM.", - "user_can_dismiss": 1 + "subtitle": "Lead, Opportunity, Customer, and more.", + "success_message": "The CRM Module is all set up!", + "title": "Let's Set Up Your CRM." } \ No newline at end of file diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/__init__.py b/erpnext/erpnext_integrations/doctype/taxjar_settings/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.js b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.js new file mode 100644 index 00000000000..62d5709f51f --- /dev/null +++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.js @@ -0,0 +1,9 @@ +// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('TaxJar Settings', { + is_sandbox: (frm) => { + frm.toggle_reqd("api_key", !frm.doc.is_sandbox); + frm.toggle_reqd("sandbox_api_key", frm.doc.is_sandbox); + } +}); diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json new file mode 100644 index 00000000000..c0d60f7a317 --- /dev/null +++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json @@ -0,0 +1,110 @@ +{ + "actions": [], + "creation": "2017-06-15 08:21:24.624315", + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "is_sandbox", + "taxjar_calculate_tax", + "taxjar_create_transactions", + "credentials", + "api_key", + "cb_keys", + "sandbox_api_key", + "configuration", + "tax_account_head", + "configuration_cb", + "shipping_account_head" + ], + "fields": [ + { + "fieldname": "credentials", + "fieldtype": "Section Break", + "label": "Credentials" + }, + { + "fieldname": "api_key", + "fieldtype": "Password", + "in_list_view": 1, + "label": "Live API Key", + "reqd": 1 + }, + { + "fieldname": "configuration", + "fieldtype": "Section Break", + "label": "Configuration" + }, + { + "fieldname": "tax_account_head", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Tax Account Head", + "options": "Account", + "reqd": 1 + }, + { + "fieldname": "shipping_account_head", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Shipping Account Head", + "options": "Account", + "reqd": 1 + }, + { + "default": "0", + "fieldname": "is_sandbox", + "fieldtype": "Check", + "label": "Sandbox Mode" + }, + { + "fieldname": "sandbox_api_key", + "fieldtype": "Password", + "label": "Sandbox API Key" + }, + { + "fieldname": "configuration_cb", + "fieldtype": "Column Break" + }, + { + "default": "0", + "fieldname": "taxjar_create_transactions", + "fieldtype": "Check", + "label": "Create TaxJar Transaction" + }, + { + "default": "0", + "fieldname": "taxjar_calculate_tax", + "fieldtype": "Check", + "label": "Enable Tax Calculation" + }, + { + "fieldname": "cb_keys", + "fieldtype": "Column Break" + } + ], + "issingle": 1, + "links": [], + "modified": "2020-04-30 04:38:03.311089", + "modified_by": "Administrator", + "module": "ERPNext Integrations", + "name": "TaxJar 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 +} \ No newline at end of file diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py new file mode 100644 index 00000000000..7f5f0f0e7a8 --- /dev/null +++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py @@ -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 TaxJarSettings(Document): + pass diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py b/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py new file mode 100644 index 00000000000..7cdfd009561 --- /dev/null +++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/test_taxjar_settings.py @@ -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 TestTaxJarSettings(unittest.TestCase): + pass diff --git a/erpnext/erpnext_integrations/taxjar_integration.py b/erpnext/erpnext_integrations/taxjar_integration.py new file mode 100644 index 00000000000..633692dd24b --- /dev/null +++ b/erpnext/erpnext_integrations/taxjar_integration.py @@ -0,0 +1,251 @@ +import traceback + +import pycountry +import taxjar + +import frappe +from erpnext import get_default_company +from frappe import _ +from frappe.contacts.doctype.address.address import get_company_address + +TAX_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "tax_account_head") +SHIP_ACCOUNT_HEAD = frappe.db.get_single_value("TaxJar Settings", "shipping_account_head") +TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions") +TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax") +SUPPORTED_COUNTRY_CODES = ["AT", "AU", "BE", "BG", "CA", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", + "FR", "GB", "GR", "HR", "HU", "IE", "IT", "LT", "LU", "LV", "MT", "NL", "PL", "PT", "RO", + "SE", "SI", "SK", "US"] + + +def get_client(): + taxjar_settings = frappe.get_single("TaxJar Settings") + + if not taxjar_settings.is_sandbox: + api_key = taxjar_settings.api_key and taxjar_settings.get_password("api_key") + api_url = taxjar.DEFAULT_API_URL + else: + api_key = taxjar_settings.sandbox_api_key and taxjar_settings.get_password("sandbox_api_key") + api_url = taxjar.SANDBOX_API_URL + + if api_key and api_url: + return taxjar.Client(api_key=api_key, api_url=api_url) + + +def create_transaction(doc, method): + """Create an order transaction in TaxJar""" + + if not TAXJAR_CREATE_TRANSACTIONS: + return + + client = get_client() + + if not client: + return + + sales_tax = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == TAX_ACCOUNT_HEAD]) + + if not sales_tax: + return + + tax_dict = get_tax_data(doc) + + if not tax_dict: + return + + tax_dict['transaction_id'] = doc.name + tax_dict['transaction_date'] = frappe.utils.today() + tax_dict['sales_tax'] = sales_tax + tax_dict['amount'] = doc.total + tax_dict['shipping'] + + try: + client.create_order(tax_dict) + except taxjar.exceptions.TaxJarResponseError as err: + frappe.throw(_(sanitize_error_response(err))) + except Exception as ex: + print(traceback.format_exc(ex)) + + +def delete_transaction(doc, method): + """Delete an existing TaxJar order transaction""" + + if not TAXJAR_CREATE_TRANSACTIONS: + return + + client = get_client() + + if not client: + return + + client.delete_order(doc.name) + + +def get_tax_data(doc): + from_address = get_company_address_details(doc) + from_shipping_state = from_address.get("state") + from_country_code = frappe.db.get_value("Country", from_address.country, "code") + from_country_code = from_country_code.upper() + + to_address = get_shipping_address_details(doc) + to_shipping_state = to_address.get("state") + to_country_code = frappe.db.get_value("Country", to_address.country, "code") + to_country_code = to_country_code.upper() + + if to_country_code not in SUPPORTED_COUNTRY_CODES: + return + + shipping = sum([tax.tax_amount for tax in doc.taxes if tax.account_head == SHIP_ACCOUNT_HEAD]) + + if to_shipping_state is not None: + to_shipping_state = get_iso_3166_2_state_code(to_address) + + tax_dict = { + 'from_country': from_country_code, + 'from_zip': from_address.pincode, + 'from_state': from_shipping_state, + 'from_city': from_address.city, + 'from_street': from_address.address_line1, + 'to_country': to_country_code, + 'to_zip': to_address.pincode, + 'to_city': to_address.city, + 'to_street': to_address.address_line1, + 'to_state': to_shipping_state, + 'shipping': shipping, + 'amount': doc.net_total + } + + return tax_dict + + +def set_sales_tax(doc, method): + if not TAXJAR_CALCULATE_TAX: + return + + if not doc.items: + return + + # if the party is exempt from sales tax, then set all tax account heads to zero + sales_tax_exempted = hasattr(doc, "exempt_from_sales_tax") and doc.exempt_from_sales_tax \ + or frappe.db.has_column("Customer", "exempt_from_sales_tax") and frappe.db.get_value("Customer", doc.customer, "exempt_from_sales_tax") + + if sales_tax_exempted: + for tax in doc.taxes: + if tax.account_head == TAX_ACCOUNT_HEAD: + tax.tax_amount = 0 + break + + doc.run_method("calculate_taxes_and_totals") + return + + tax_dict = get_tax_data(doc) + + if not tax_dict: + # Remove existing tax rows if address is changed from a taxable state/country + setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD]) + return + + tax_data = validate_tax_request(tax_dict) + + if tax_data is not None: + if not tax_data.amount_to_collect: + setattr(doc, "taxes", [tax for tax in doc.taxes if tax.account_head != TAX_ACCOUNT_HEAD]) + elif tax_data.amount_to_collect > 0: + # Loop through tax rows for existing Sales Tax entry + # If none are found, add a row with the tax amount + for tax in doc.taxes: + if tax.account_head == TAX_ACCOUNT_HEAD: + tax.tax_amount = tax_data.amount_to_collect + + doc.run_method("calculate_taxes_and_totals") + break + else: + doc.append("taxes", { + "charge_type": "Actual", + "description": "Sales Tax", + "account_head": TAX_ACCOUNT_HEAD, + "tax_amount": tax_data.amount_to_collect + }) + + doc.run_method("calculate_taxes_and_totals") + + +def validate_tax_request(tax_dict): + """Return the sales tax that should be collected for a given order.""" + + client = get_client() + + if not client: + return + + try: + tax_data = client.tax_for_order(tax_dict) + except taxjar.exceptions.TaxJarResponseError as err: + frappe.throw(_(sanitize_error_response(err))) + else: + return tax_data + + +def get_company_address_details(doc): + """Return default company address details""" + + company_address = get_company_address(get_default_company()).company_address + + if not company_address: + frappe.throw(_("Please set a default company address")) + + company_address = frappe.get_doc("Address", company_address) + return company_address + + +def get_shipping_address_details(doc): + """Return customer shipping address details""" + + if doc.shipping_address_name: + shipping_address = frappe.get_doc("Address", doc.shipping_address_name) + else: + shipping_address = get_company_address_details(doc) + + return shipping_address + + +def get_iso_3166_2_state_code(address): + country_code = frappe.db.get_value("Country", address.get("country"), "code") + + error_message = _("""{0} is not a valid state! Check for typos or enter the ISO code for your state.""").format(address.get("state")) + state = address.get("state").upper().strip() + + # The max length for ISO state codes is 3, excluding the country code + if len(state) <= 3: + # PyCountry returns state code as {country_code}-{state-code} (e.g. US-FL) + address_state = (country_code + "-" + state).upper() + + states = pycountry.subdivisions.get(country_code=country_code.upper()) + states = [pystate.code for pystate in states] + + if address_state in states: + return state + + frappe.throw(_(error_message)) + else: + try: + lookup_state = pycountry.subdivisions.lookup(state) + except LookupError: + frappe.throw(_(error_message)) + else: + return lookup_state.code.split('-')[1] + + +def sanitize_error_response(response): + response = response.full_response.get("detail") + response = response.replace("_", " ") + + sanitized_responses = { + "to zip": "Zipcode", + "to city": "City", + "to state": "State", + "to country": "Country" + } + + for k, v in sanitized_responses.items(): + response = response.replace(k, v) + + return response diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json index eaf8d80ba8c..b1d62da0325 100644 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json +++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json @@ -11,6 +11,7 @@ "title", "appointment", "procedure_template", + "medical_code", "column_break_30", "company", "invoiced", @@ -290,11 +291,19 @@ "no_copy": 1, "print_hide": 1, "read_only": 1 + }, + { + "fetch_from": "procedure_template.medical_code", + "fieldname": "medical_code", + "fieldtype": "Link", + "label": "Medical Code", + "options": "Medical Code", + "read_only": 1 } ], "is_submittable": 1, "links": [], - "modified": "2020-04-27 21:36:23.796924", + "modified": "2020-06-29 14:28:11.779815", "modified_by": "Administrator", "module": "Healthcare", "name": "Clinical Procedure", diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js index 16d4540c7c5..1ef110dc6f4 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js @@ -30,6 +30,16 @@ frappe.ui.form.on('Clinical Procedure Template', { mark_change_in_item(frm); }, + medical_code: function(frm) { + frm.set_query("medical_code", function() { + return { + filters: { + medical_code_standard: frm.doc.medical_code_standard + } + }; + }); + }, + refresh: function(frm) { frm.fields_dict['items'].grid.set_column_disp('barcode', false); frm.fields_dict['items'].grid.set_column_disp('batch_no', false); diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json index 9cfd682f1d2..17ac7eb1f95 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json @@ -21,6 +21,9 @@ "is_billable", "rate", "medical_department", + "medical_coding_section", + "medical_code_standard", + "medical_code", "consumables", "consume_stock", "items", @@ -46,7 +49,6 @@ "fieldname": "item_code", "fieldtype": "Data", "label": "Item Code", - "options": "Item", "read_only_depends_on": "eval: !doc.__islocal ", "reqd": 1 }, @@ -173,10 +175,29 @@ "no_copy": 1, "options": "Item", "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "medical_coding_section", + "fieldtype": "Section Break", + "label": "Medical Coding" + }, + { + "fieldname": "medical_code_standard", + "fieldtype": "Link", + "label": "Medical Code Standard", + "options": "Medical Code Standard" + }, + { + "depends_on": "medical_code_standard", + "fieldname": "medical_code", + "fieldtype": "Link", + "label": "Medical Code", + "options": "Medical Code" } ], "links": [], - "modified": "2020-02-28 14:16:13.184981", + "modified": "2020-06-29 14:12:27.158130", "modified_by": "Administrator", "module": "Healthcare", "name": "Clinical Procedure Template", diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.json b/erpnext/healthcare/doctype/lab_test/lab_test.json index 17dc1edd8c1..88eeb46a242 100644 --- a/erpnext/healthcare/doctype/lab_test/lab_test.json +++ b/erpnext/healthcare/doctype/lab_test/lab_test.json @@ -33,9 +33,10 @@ "user", "invoiced", "sb_first", + "template", "lab_test_name", "column_break_26", - "template", + "medical_code", "lab_test_group", "sb_normal", "normal_test_items", @@ -424,11 +425,19 @@ "print_hide": 1, "read_only": 1, "report_hide": 1 + }, + { + "fetch_from": "template.medical_code", + "fieldname": "medical_code", + "fieldtype": "Link", + "label": "Medical Code", + "options": "Medical Code", + "read_only": 1 } ], "is_submittable": 1, "links": [], - "modified": "2020-04-04 19:16:29.131168", + "modified": "2020-06-29 14:24:26.509721", "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Test", diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.js b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.js index 5c9bf49e608..c3eedbbdf1f 100644 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.js +++ b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.js @@ -8,7 +8,7 @@ frappe.ui.form.on("Lab Test Template",{ if (!frm.doc.lab_test_description) frm.set_value("lab_test_description", frm.doc.lab_test_name); }, - refresh : function(frm) { + refresh: function(frm) { // Restrict Special, Grouped type templates in Child TestGroups frm.set_query("lab_test_template", "lab_test_groups", function() { return { @@ -17,6 +17,15 @@ frappe.ui.form.on("Lab Test Template",{ } }; }); + }, + medical_code: function(frm) { + frm.set_query("medical_code", function() { + return { + filters: { + medical_code_standard: frm.doc.medical_code_standard + } + }; + }); } }); diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json index a606bc4b1d0..ebd2ec0246f 100644 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json +++ b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json @@ -19,6 +19,9 @@ "disabled", "is_billable", "lab_test_rate", + "medical_coding_section", + "medical_code_standard", + "medical_code", "section_break_normal", "lab_test_uom", "lab_test_normal_range", @@ -237,10 +240,29 @@ "fieldtype": "Text", "ignore_xss_filter": 1, "label": "Collection Details" + }, + { + "collapsible": 1, + "fieldname": "medical_coding_section", + "fieldtype": "Section Break", + "label": "Medical Coding" + }, + { + "depends_on": "medical_code_standard", + "fieldname": "medical_code", + "fieldtype": "Link", + "label": "Medical Code", + "options": "Medical Code" + }, + { + "fieldname": "medical_code_standard", + "fieldtype": "Link", + "label": "Medical Code Standard", + "options": "Medical Code Standard" } ], "links": [], - "modified": "2020-03-25 16:53:01.740103", + "modified": "2020-06-29 14:07:20.772219", "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Test Template", diff --git a/erpnext/healthcare/doctype/medical_code/medical_code.json b/erpnext/healthcare/doctype/medical_code/medical_code.json index a2e72475179..5d698309076 100644 --- a/erpnext/healthcare/doctype/medical_code/medical_code.json +++ b/erpnext/healthcare/doctype/medical_code/medical_code.json @@ -1,156 +1,69 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "beta": 1, - "creation": "2017-06-21 13:02:56.122897", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_copy": 1, + "allow_import": 1, + "allow_rename": 1, + "beta": 1, + "creation": "2017-06-21 13:02:56.122897", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "medical_code_standard", + "code", + "description" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "medical_code_standard", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Medical Code Standard", - "length": 0, - "no_copy": 0, - "options": "Medical Code Standard", - "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": "medical_code_standard", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Medical Code Standard", + "options": "Medical Code Standard", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "code", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Code", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "code", + "fieldtype": "Data", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Code", + "reqd": 1, + "unique": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Description", - "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 + "bold": 1, + "fieldname": "description", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Description" } - ], - "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": "2017-10-04 17:08:11.053418", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Medical Code", - "name_case": "", - "owner": "Administrator", + ], + "links": [], + "modified": "2020-06-29 14:02:30.980032", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Medical Code", + "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": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "share": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "code, description", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "", - "track_changes": 1, - "track_seen": 0 + ], + "quick_entry": 1, + "restrict_to_domain": "Healthcare", + "search_fields": "code, description", + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py index 56401a3e742..262fc4650af 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py @@ -73,7 +73,7 @@ def update_encounter_medical_record(encounter): insert_encounter_to_medical_record(encounter) def delete_medical_record(encounter): - frappe.db.delete_doc_if_exists('Patient Medical Record', 'reference_name', encounter.name) + frappe.delete_doc_if_exists('Patient Medical Record', 'reference_name', encounter.name) def set_subject_field(encounter): subject = frappe.bold(_('Healthcare Practitioner: ')) + encounter.practitioner + '
' diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.json b/erpnext/healthcare/doctype/therapy_session/therapy_session.json index 00d74a09495..c75d9342ef1 100644 --- a/erpnext/healthcare/doctype/therapy_session/therapy_session.json +++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.json @@ -19,6 +19,7 @@ "practitioner", "department", "details_section", + "medical_code", "duration", "rate", "location", @@ -206,11 +207,19 @@ "fieldtype": "Data", "label": "Patient Name", "read_only": 1 + }, + { + "fetch_from": "therapy_type.medical_code", + "fieldname": "medical_code", + "fieldtype": "Link", + "label": "Medical Code", + "options": "Medical Code", + "read_only": 1 } ], "is_submittable": 1, "links": [], - "modified": "2020-04-29 16:49:16.286006", + "modified": "2020-06-29 14:33:34.836594", "modified_by": "Administrator", "module": "Healthcare", "name": "Therapy Session", diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.js b/erpnext/healthcare/doctype/therapy_type/therapy_type.js index 7a61b0def03..6e155dc21f9 100644 --- a/erpnext/healthcare/doctype/therapy_type/therapy_type.js +++ b/erpnext/healthcare/doctype/therapy_type/therapy_type.js @@ -45,6 +45,16 @@ frappe.ui.form.on('Therapy Type', { medical_department: function(frm) { mark_change_in_item(frm); + }, + + medical_code: function(frm) { + frm.set_query("medical_code", function() { + return { + filters: { + medical_code_standard: frm.doc.medical_code_standard + } + }; + }); } }); diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.json b/erpnext/healthcare/doctype/therapy_type/therapy_type.json index 0b3c3caeaab..f365b1df032 100644 --- a/erpnext/healthcare/doctype/therapy_type/therapy_type.json +++ b/erpnext/healthcare/doctype/therapy_type/therapy_type.json @@ -22,6 +22,9 @@ "item_group", "column_break_12", "description", + "medical_coding_section", + "medical_code_standard", + "medical_code", "section_break_18", "therapy_for", "add_exercises", @@ -160,10 +163,30 @@ { "fieldname": "section_break_18", "fieldtype": "Section Break" + }, + { + "collapsible": 1, + "fieldname": "medical_coding_section", + "fieldtype": "Section Break", + "label": "Medical Coding", + "options": "Medical Coding" + }, + { + "fieldname": "medical_code_standard", + "fieldtype": "Link", + "label": "Medical Code Standard", + "options": "Medical Code Standard" + }, + { + "depends_on": "medical_code_standard", + "fieldname": "medical_code", + "fieldtype": "Link", + "label": "Medical Code", + "options": "Medical Code" } ], "links": [], - "modified": "2020-04-21 13:09:04.006289", + "modified": "2020-06-29 14:18:50.669951", "modified_by": "Administrator", "module": "Healthcare", "name": "Therapy Type", diff --git a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json index 3e50726060a..56c3c135599 100644 --- a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json +++ b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json @@ -10,7 +10,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/healthcare", "idx": 0, "is_complete": 0, - "modified": "2020-05-26 23:16:37.603361", + "modified": "2020-07-08 14:06:19.512946", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare", @@ -35,8 +35,7 @@ "step": "Explore Clinical Procedure Templates" } ], - "subtitle": "Patients, Practitioner Schedules, Settings and more.", - "success_message": "Yayy! The Healthcare Module is all set up!", - "title": "Let's Setup the Healthcare Module", - "user_can_dismiss": 1 + "subtitle": "Patients, Practitioner Schedules, Settings, and more.", + "success_message": "The Healthcare Module is all set up!", + "title": "Let's Set Up the Healthcare Module." } \ No newline at end of file diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 2a695896ed0..e8dda207eca 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -13,7 +13,7 @@ source_link = "https://github.com/frappe/erpnext" app_logo_url = '/assets/erpnext/images/erp-icon.svg' -develop_version = '12.x.x-develop' +develop_version = '13.x.x-develop' app_include_js = "assets/js/erpnext.min.js" app_include_css = "assets/css/erpnext.css" @@ -234,12 +234,19 @@ doc_events = { "validate": "erpnext.portal.doctype.products_settings.products_settings.home_page_is_products" }, "Sales Invoice": { - "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.regional.italy.utils.sales_invoice_on_submit"], - "on_cancel": "erpnext.regional.italy.utils.sales_invoice_on_cancel", + "on_submit": [ + "erpnext.regional.create_transaction_log", + "erpnext.regional.italy.utils.sales_invoice_on_submit", + "erpnext.erpnext_integrations.taxjar_integration.create_transaction" + ], + "on_cancel": [ + "erpnext.regional.italy.utils.sales_invoice_on_cancel", + "erpnext.erpnext_integrations.taxjar_integration.delete_transaction" + ], "on_trash": "erpnext.regional.check_deletion_permission" }, "Purchase Invoice": { - "on_submit": "erpnext.regional.india.utils.make_reverse_charge_entries" + "validate": "erpnext.regional.india.utils.update_grand_total_for_rcm" }, "Payment Entry": { "on_submit": ["erpnext.regional.create_transaction_log", "erpnext.accounts.doctype.payment_request.payment_request.update_payment_req_status"], @@ -261,6 +268,9 @@ doc_events = { }, "Email Unsubscribe": { "after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient" + }, + ('Quotation', 'Sales Order', 'Sales Invoice'): { + 'validate': ["erpnext.erpnext_integrations.taxjar_integration.set_sales_tax"] } } @@ -364,7 +374,8 @@ regional_overrides = { 'erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data': 'erpnext.regional.india.utils.get_itemised_tax_breakup_data', 'erpnext.accounts.party.get_regional_address_details': 'erpnext.regional.india.utils.get_regional_address_details', 'erpnext.hr.utils.calculate_annual_eligible_hra_exemption': 'erpnext.regional.india.utils.calculate_annual_eligible_hra_exemption', - 'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period' + 'erpnext.hr.utils.calculate_hra_exemption_for_period': 'erpnext.regional.india.utils.calculate_hra_exemption_for_period', + 'erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_regional_gl_entries': 'erpnext.regional.india.utils.make_regional_gl_entries' }, 'United Arab Emirates': { 'erpnext.controllers.taxes_and_totals.update_itemised_tax_data': 'erpnext.regional.united_arab_emirates.utils.update_itemised_tax_data' diff --git a/erpnext/hr/dashboard_fixtures.py b/erpnext/hr/dashboard_fixtures.py index 6d8091be647..1e9b4f3c93a 100644 --- a/erpnext/hr/dashboard_fixtures.py +++ b/erpnext/hr/dashboard_fixtures.py @@ -123,7 +123,7 @@ def get_number_cards(): number_cards.append( get_number_cards_doc("Employee", "New Joinees (Last year)", filters_json = json.dumps([ - ["Employee","date_of_joining","Previous","1 year"], + ["Employee","date_of_joining","Timespan","last year"], ["Employee","status","=","Active"] ]) ) @@ -131,7 +131,7 @@ def get_number_cards(): number_cards.append( get_number_cards_doc("Employee", "Employees Left (Last year)", filters_json = json.dumps([ - ["Employee", "relieving_date", "Previous", "1 year"], + ["Employee", "relieving_date", "Timespan", "last year"], ["Employee", "status", "=", "Left"] ]) ) @@ -139,7 +139,7 @@ def get_number_cards(): number_cards.append( get_number_cards_doc("Job Applicant", "Total Applicants (Last month)", filters_json = json.dumps([ - ["Job Applicant", "creation", "Previous", "1 month"] + ["Job Applicant", "creation", "Timespan", "last month"] ]) ) ) diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json index 7dacacf12b0..f2afe065d1e 100644 --- a/erpnext/hr/doctype/employee/employee.json +++ b/erpnext/hr/doctype/employee/employee.json @@ -410,6 +410,8 @@ "options": "Branch" }, { + "fetch_from": "grade.default_leave_policy", + "fetch_if_empty": 1, "fieldname": "leave_policy", "fieldtype": "Link", "label": "Leave Policy", @@ -804,16 +806,14 @@ "fieldname": "expense_approver", "fieldtype": "Link", "label": "Expense Approver", - "options": "User", - "show_days": 1, - "show_seconds": 1 + "options": "User" } ], "icon": "fa fa-user", "idx": 24, "image_field": "image", "links": [], - "modified": "2020-06-18 18:01:27.223535", + "modified": "2020-07-03 21:28:04.109189", "modified_by": "Administrator", "module": "HR", "name": "Employee", diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py index 4d49503d2dc..7338cbb6c85 100755 --- a/erpnext/hr/doctype/employee/employee.py +++ b/erpnext/hr/doctype/employee/employee.py @@ -413,7 +413,11 @@ def get_employee_emails(employee_list): @frappe.whitelist() def get_children(doctype, parent=None, company=None, is_root=False, is_tree=False): - filters = [['company', '=', company]] + + filters = [] + if company and company != 'All Companies': + filters = [['company', '=', company]] + fields = ['name as value', 'employee_name as title'] if is_root: diff --git a/erpnext/hr/doctype/employee/employee_tree.js b/erpnext/hr/doctype/employee/employee_tree.js index 0a2da63058a..9ab091a1eb6 100644 --- a/erpnext/hr/doctype/employee/employee_tree.js +++ b/erpnext/hr/doctype/employee/employee_tree.js @@ -4,7 +4,7 @@ frappe.treeview_settings['Employee'] = { { fieldname: "company", fieldtype:"Select", - options: erpnext.utils.get_tree_options("company"), + options: ['All Companies'].concat(erpnext.utils.get_tree_options("company")), label: __("Company"), default: erpnext.utils.get_tree_default("company") } diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py index 76195812c80..3c435b8cc3b 100644 --- a/erpnext/hr/doctype/employee_advance/employee_advance.py +++ b/erpnext/hr/doctype/employee_advance/employee_advance.py @@ -120,12 +120,14 @@ def make_bank_entry(dt, dn): "reference_type": "Employee Advance", "reference_name": doc.name, "party_type": "Employee", + "cost_center": erpnext.get_default_cost_center(doc.company), "party": doc.employee, "is_advance": "Yes" }) je.append("accounts", { "account": payment_account.account, + "cost_center": erpnext.get_default_cost_center(doc.company), "credit_in_account_currency": flt(doc.advance_amount), "account_currency": payment_account.account_currency, "account_type": payment_account.account_type diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js index fa63ec2834a..221300b519a 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.js +++ b/erpnext/hr/doctype/expense_claim/expense_claim.js @@ -113,6 +113,14 @@ cur_frm.cscript.calculate_total_amount = function(doc,cdt,cdn){ cur_frm.cscript.calculate_total(doc,cdt,cdn); }; +cur_frm.fields_dict['cost_center'].get_query = function(doc) { + return { + filters: { + "company": doc.company + } + } +}; + erpnext.expense_claim = { set_title: function(frm) { if (!frm.doc.task) { @@ -300,6 +308,11 @@ frappe.ui.form.on("Expense Claim", { cost_center: function(frm) { frm.events.set_child_cost_center(frm); }, + + validate: function(frm) { + frm.events.set_child_cost_center(frm); + }, + set_child_cost_center: function(frm){ (frm.doc.expenses || []).forEach(function(d) { if (!d.cost_center){ @@ -349,9 +362,6 @@ frappe.ui.form.on("Expense Claim", { }); frappe.ui.form.on("Expense Claim Detail", { - expenses_add: function(frm, cdt, cdn) { - frm.events.set_child_cost_center(frm); - }, amount: function(frm, cdt, cdn) { var child = locals[cdt][cdn]; frappe.model.set_value(cdt, cdn, 'sanctioned_amount', child.amount); diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index ea469b82c98..bf893d5fab3 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -129,7 +129,7 @@ class ExpenseClaim(AccountsController): "debit": data.sanctioned_amount, "debit_in_account_currency": data.sanctioned_amount, "against": self.employee, - "cost_center": data.cost_center + "cost_center": data.cost_center or self.cost_center }, item=data) ) @@ -295,7 +295,7 @@ def make_bank_entry(dt, dn): je = frappe.new_doc("Journal Entry") je.voucher_type = 'Bank Entry' je.company = expense_claim.company - je.remark = 'Payment against Expense Claim: ' + dn; + je.remark = 'Payment against Expense Claim: ' + dn je.append("accounts", { "account": expense_claim.payable_account, @@ -303,6 +303,7 @@ def make_bank_entry(dt, dn): "reference_type": "Expense Claim", "party_type": "Employee", "party": expense_claim.employee, + "cost_center": erpnext.get_default_cost_center(expense_claim.company), "reference_name": expense_claim.name }) @@ -313,6 +314,7 @@ def make_bank_entry(dt, dn): "reference_name": expense_claim.name, "balance": default_bank_cash_account.balance, "account_currency": default_bank_cash_account.account_currency, + "cost_center": erpnext.get_default_cost_center(expense_claim.company), "account_type": default_bank_cash_account.account_type }) diff --git a/erpnext/hr/doctype/job_applicant/job_applicant_list.js b/erpnext/hr/doctype/job_applicant/job_applicant_list.js new file mode 100644 index 00000000000..3b9141ba79c --- /dev/null +++ b/erpnext/hr/doctype/job_applicant/job_applicant_list.js @@ -0,0 +1,15 @@ +// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +// MIT License. See license.txt + +frappe.listview_settings['Job Applicant'] = { + add_fields: ["company", "designation", "job_applicant", "status"], + get_indicator: function (doc) { + if (doc.status == "Accepted") { + return [__(doc.status), "green", "status,=," + doc.status]; + } else if (["Open", "Replied"].includes(doc.status)) { + return [__(doc.status), "orange", "status,=," + doc.status]; + } else if (["Hold", "Rejected"].includes(doc.status)) { + return [__(doc.status), "red", "status,=," + doc.status]; + } + } +}; diff --git a/erpnext/hr/doctype/job_offer/job_offer.json b/erpnext/hr/doctype/job_offer/job_offer.json index ccbfdc53830..c0b7f69e1bb 100644 --- a/erpnext/hr/doctype/job_offer/job_offer.json +++ b/erpnext/hr/doctype/job_offer/job_offer.json @@ -30,7 +30,6 @@ { "fieldname": "job_applicant", "fieldtype": "Link", - "in_list_view": 1, "label": "Job Applicant", "options": "Job Applicant", "print_hide": 1, @@ -161,7 +160,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2019-12-31 02:40:33.650728", + "modified": "2020-06-25 00:56:24.756395", "modified_by": "Administrator", "module": "HR", "name": "Job Offer", diff --git a/erpnext/hr/doctype/job_offer/job_offer.py b/erpnext/hr/doctype/job_offer/job_offer.py index 9a2c4c64ebb..f9ee44a4de5 100644 --- a/erpnext/hr/doctype/job_offer/job_offer.py +++ b/erpnext/hr/doctype/job_offer/job_offer.py @@ -32,7 +32,8 @@ class JobOffer(Document): return frappe.get_all("Job Offer", filters={ "offer_date": ['between', (from_date, to_date)], "designation": self.designation, - "company": self.company + "company": self.company, + "docstatus": 1 }, fields=['name']) def update_job_applicant(status, job_applicant): diff --git a/erpnext/hr/doctype/job_offer/job_offer_list.js b/erpnext/hr/doctype/job_offer/job_offer_list.js new file mode 100644 index 00000000000..4fa5be7cc84 --- /dev/null +++ b/erpnext/hr/doctype/job_offer/job_offer_list.js @@ -0,0 +1,15 @@ +// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +// MIT License. See license.txt + +frappe.listview_settings['Job Offer'] = { + add_fields: ["company", "designation", "job_applicant", "status"], + get_indicator: function (doc) { + if (doc.status == "Accepted") { + return [__(doc.status), "green", "status,=," + doc.status]; + } else if (doc.status == "Awaiting Response") { + return [__(doc.status), "orange", "status,=," + doc.status]; + } else if (doc.status == "Rejected") { + return [__(doc.status), "red", "status,=," + doc.status]; + } + } +}; diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js index fb1f2c00b13..4001a455075 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.js +++ b/erpnext/hr/doctype/leave_application/leave_application.js @@ -40,6 +40,8 @@ frappe.ui.form.on("Leave Application", { validate: function(frm) { if (frm.doc.from_date == frm.doc.to_date && frm.doc.half_day == 1){ frm.doc.half_day_date = frm.doc.from_date; + }else if (frm.doc.half_day == 0){ + frm.doc.half_day_date = ""; } frm.toggle_reqd("half_day_date", frm.doc.half_day == 1); }, diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 0423824c0e9..3f25f583833 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -293,6 +293,8 @@ class LeaveApplication(Document): def set_half_day_date(self): if self.from_date == self.to_date and self.half_day == 1: self.half_day_date = self.from_date + elif self.half_day == 0: + self.half_day_date = None def notify_employee(self): employee = frappe.get_doc("Employee", self.employee) diff --git a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py index 48a204596c3..ff5dc2ff3e0 100644 --- a/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py +++ b/erpnext/hr/doctype/leave_policy/leave_policy_dashboard.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from frappe import _ def get_data(): return { @@ -8,13 +9,17 @@ def get_data(): }, 'transactions': [ { - 'items': ['Employee'] - }, - { - 'items': ['Employee Grade'] + 'label': _('Employees'), + 'items': ['Employee', 'Employee Grade'] }, { + 'label': _('Leaves'), 'items': ['Leave Allocation'] }, ] - } \ No newline at end of file + } + + + + + \ No newline at end of file diff --git a/erpnext/hr/module_onboarding/human_resource/human_resource.json b/erpnext/hr/module_onboarding/human_resource/human_resource.json index e64582b407c..518c002bcaa 100644 --- a/erpnext/hr/module_onboarding/human_resource/human_resource.json +++ b/erpnext/hr/module_onboarding/human_resource/human_resource.json @@ -13,7 +13,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/human-resources", "idx": 0, "is_complete": 0, - "modified": "2020-05-20 11:20:07.992597", + "modified": "2020-07-08 14:05:47.018799", "modified_by": "Administrator", "module": "HR", "name": "Human Resource", @@ -44,8 +44,7 @@ "step": "HR Settings" } ], - "subtitle": "Employee, Leaves and more.", - "success_message": "The HR Module is all set up!", - "title": "Let's Setup the Human Resource Module. ", - "user_can_dismiss": 0 + "subtitle": "Employee, Leaves, and more.", + "success_message": "The Human Resource Module is all set up!", + "title": "Let's Set Up the Human Resource Module. " } \ No newline at end of file diff --git a/erpnext/loan_management/doctype/loan/loan.js b/erpnext/loan_management/doctype/loan/loan.js index 9cd8b2e90a9..ffef60b6b0a 100644 --- a/erpnext/loan_management/doctype/loan/loan.js +++ b/erpnext/loan_management/doctype/loan/loan.js @@ -45,15 +45,6 @@ frappe.ui.form.on('Loan', { }); }) - frm.set_query('loan_security_pledge', function(doc, cdt, cdn) { - return { - filters: { - applicant: frm.doc.applicant, - docstatus: 1, - loan_application: frm.doc.loan_application || '' - } - }; - }); }, refresh: function (frm) { @@ -86,9 +77,6 @@ frappe.ui.form.on('Loan', { frm.toggle_display("repayment_periods", s1 - frm.doc.is_term_loan); }, - is_secured_loan: function(frm) { - frm.toggle_reqd("loan_security_pledge", frm.doc.is_secured_loan); - }, make_loan_disbursement: function (frm) { frappe.call({ diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json index b04e82274e9..192beee7e3d 100644 --- a/erpnext/loan_management/doctype/loan/loan.json +++ b/erpnext/loan_management/doctype/loan/loan.json @@ -25,15 +25,12 @@ "disbursement_date", "disbursed_amount", "column_break_11", + "maximum_loan_amount", "is_term_loan", "repayment_method", "repayment_periods", "monthly_repayment_amount", "repayment_start_date", - "loan_security_details_section", - "loan_security_pledge", - "column_break_25", - "maximum_loan_value", "account_info", "mode_of_payment", "payment_account", @@ -292,13 +289,8 @@ "default": "0", "fieldname": "is_secured_loan", "fieldtype": "Check", - "label": "Is Secured Loan" - }, - { - "depends_on": "is_secured_loan", - "fieldname": "loan_security_details_section", - "fieldtype": "Section Break", - "label": "Loan Security Details" + "label": "Is Secured Loan", + "read_only": 1 }, { "default": "0", @@ -324,12 +316,6 @@ "options": "Company:company:default_currency", "read_only": 1 }, - { - "fieldname": "loan_security_pledge", - "fieldtype": "Link", - "label": "Loan Security Pledge", - "options": "Loan Security Pledge" - }, { "fieldname": "disbursed_amount", "fieldtype": "Currency", @@ -338,21 +324,17 @@ "read_only": 1 }, { - "fetch_from": "loan_security_pledge.maximum_loan_value", - "fieldname": "maximum_loan_value", + "fetch_from": "loan_application.maximum_loan_amount", + "fieldname": "maximum_loan_amount", "fieldtype": "Currency", - "label": "Maximum Loan Value", + "label": "Maximum Loan Amount", "options": "Company:company:default_currency", "read_only": 1 - }, - { - "fieldname": "column_break_25", - "fieldtype": "Column Break" } ], "is_submittable": 1, "links": [], - "modified": "2020-04-13 13:16:10.192624", + "modified": "2020-07-02 20:46:40.128142", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan", diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py index 4e805d4a27d..e20b484fc0e 100644 --- a/erpnext/loan_management/doctype/loan/loan.py +++ b/erpnext/loan_management/doctype/loan/loan.py @@ -13,11 +13,9 @@ from erpnext.controllers.accounts_controller import AccountsController class Loan(AccountsController): def validate(self): self.set_loan_amount() - + self.validate_loan_amount() self.set_missing_fields() self.validate_accounts() - self.validate_loan_security_pledge() - self.validate_loan_amount() self.check_sanctioned_amount_limit() self.validate_repay_from_salary() @@ -56,21 +54,6 @@ class Loan(AccountsController): if self.repayment_method == "Repay Over Number of Periods": self.monthly_repayment_amount = get_monthly_repayment_amount(self.repayment_method, self.loan_amount, self.rate_of_interest, self.repayment_periods) - def validate_loan_security_pledge(self): - - if self.is_secured_loan and not self.loan_security_pledge: - frappe.throw(_("Loan Security Pledge is mandatory for secured loan")) - - if self.loan_security_pledge: - loan_security_details = frappe.db.get_value("Loan Security Pledge", self.loan_security_pledge, - ['loan', 'company'], as_dict=1) - - if loan_security_details.loan: - frappe.throw(_("Loan Security Pledge already pledged against loan {0}").format(loan_security_details.loan)) - - if loan_security_details.company != self.company: - frappe.throw(_("Loan Security Pledge Company and Loan Company must be same")) - def check_sanctioned_amount_limit(self): total_loan_amount = get_total_loan_amount(self.applicant_type, self.applicant, self.company) sanctioned_amount_limit = get_sanctioned_amount_limit(self.applicant_type, self.applicant, self.company) @@ -129,22 +112,29 @@ class Loan(AccountsController): self.total_payment = self.loan_amount def set_loan_amount(self): + if self.loan_application and not self.loan_amount: + self.loan_amount = frappe.db.get_value('Loan Application', self.loan_application, 'loan_amount') - if not self.loan_amount and self.is_secured_loan and self.loan_security_pledge: - self.loan_amount = self.maximum_loan_value def validate_loan_amount(self): - if self.is_secured_loan and self.loan_amount > self.maximum_loan_value: - msg = _("Loan amount cannot be greater than {0}").format(self.maximum_loan_value) + if self.maximum_loan_amount and self.loan_amount > self.maximum_loan_amount: + msg = _("Loan amount cannot be greater than {0}").format(self.maximum_loan_amount) frappe.throw(msg) if not self.loan_amount: frappe.throw(_("Loan amount is mandatory")) def link_loan_security_pledge(self): - frappe.db.sql("""UPDATE `tabLoan Security Pledge` SET - loan = %s, status = 'Pledged', pledge_time = %s - where name = %s """, (self.name, now_datetime(), self.loan_security_pledge)) + if self.is_secured_loan: + loan_security_pledge = frappe.db.get_value('Loan Security Pledge', {'loan_application': self.loan_application}, + 'name') + + if loan_security_pledge: + frappe.db.set_value('Loan Security Pledge', loan_security_pledge, { + 'loan': self.name, + 'status': 'Pledged', + 'pledge_time': now_datetime() + }) def unlink_loan_security_pledge(self): frappe.db.sql("""UPDATE `tabLoan Security Pledge` SET diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py index 3f37a26418b..c65996e65f2 100644 --- a/erpnext/loan_management/doctype/loan/test_loan.py +++ b/erpnext/loan_management/doctype/loan/test_loan.py @@ -16,6 +16,7 @@ from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall from erpnext.loan_management.doctype.loan.loan import create_loan_security_unpledge from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty +from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge class TestLoan(unittest.TestCase): def setUp(self): @@ -72,31 +73,31 @@ class TestLoan(unittest.TestCase): self.assertEquals(loan.total_payment, 302712) def test_loan_with_security(self): - pledges = [] - pledges.append({ + + pledge = [{ "loan_security": "Test Security 1", "qty": 4000.00, - "haircut": 50, - "loan_security_price": 500.00 - }) + }] - loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges) - - loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_security_pledge.name) + loan_application = create_loan_application('_Test Company', self.applicant2, + 'Stock Loan', pledge, "Repay Over Number of Periods", 12) + create_pledge(loan_application) + loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", + 12, loan_application) self.assertEquals(loan.loan_amount, 1000000) def test_loan_disbursement(self): - pledges = [] - pledges.append({ + pledge = [{ "loan_security": "Test Security 1", - "qty": 4000.00, - "haircut": 50 - }) + "qty": 4000.00 + }] - loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges) + loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledge, "Repay Over Number of Periods", 12) - loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_security_pledge.name) + create_pledge(loan_application) + + loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application) self.assertEquals(loan.loan_amount, 1000000) loan.submit() @@ -121,18 +122,15 @@ class TestLoan(unittest.TestCase): self.assertTrue(gl_entries2) def test_regular_loan_repayment(self): - pledges = [] - pledges.append({ + pledge = [{ "loan_security": "Test Security 1", - "qty": 4000.00, - "haircut": 50 - }) + "qty": 4000.00 + }] - loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges) - - loan = create_demand_loan(self.applicant2, "Demand Loan", loan_security_pledge.name, - posting_date=get_first_day(nowdate())) + loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge) + create_pledge(loan_application) + loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate())) loan.submit() self.assertEquals(loan.loan_amount, 1000000) @@ -166,16 +164,15 @@ class TestLoan(unittest.TestCase): penalty_amount - amounts[0], 2)) def test_loan_closure_repayment(self): - pledges = [] - pledges.append({ + pledge = [{ "loan_security": "Test Security 1", - "qty": 4000.00, - "haircut": 50 - }) + "qty": 4000.00 + }] - loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges) - loan = create_demand_loan(self.applicant2, "Demand Loan", loan_security_pledge.name, - posting_date=get_first_day(nowdate())) + loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge) + create_pledge(loan_application) + + loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate())) loan.submit() self.assertEquals(loan.loan_amount, 1000000) @@ -214,23 +211,21 @@ class TestLoan(unittest.TestCase): self.assertEquals(loan.status, "Loan Closure Requested") def test_loan_repayment_for_term_loan(self): - pledges = [] - pledges.append({ + pledges = [{ "loan_security": "Test Security 2", - "qty": 4000.00, - "haircut": 50 - }) - - pledges.append({ + "qty": 4000.00 + }, + { "loan_security": "Test Security 1", - "qty": 2000.00, - "haircut": 50 - }) + "qty": 2000.00 + }] - loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges) + loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledges, + "Repay Over Number of Periods", 12) + create_pledge(loan_application) - loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, - loan_security_pledge.name, posting_date=add_months(nowdate(), -1)) + loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application, + posting_date=add_months(nowdate(), -1)) loan.submit() @@ -250,16 +245,18 @@ class TestLoan(unittest.TestCase): self.assertEquals(amounts[1], 78303.00) def test_security_shortfall(self): - pledges = [] - pledges.append({ + pledges = [{ "loan_security": "Test Security 2", "qty": 8000.00, "haircut": 50, - }) + }] - loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges) + loan_application = create_loan_application('_Test Company', self.applicant2, + 'Stock Loan', pledges, "Repay Over Number of Periods", 12) - loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_security_pledge.name) + create_pledge(loan_application) + + loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application) loan.submit() make_loan_disbursement_entry(loan.name, loan.loan_amount) @@ -279,16 +276,15 @@ class TestLoan(unittest.TestCase): where loan_security='Test Security 2'""") def test_loan_security_unpledge(self): - pledges = [] - pledges.append({ + pledge = [{ "loan_security": "Test Security 1", - "qty": 4000.00, - "haircut": 50 - }) + "qty": 4000.00 + }] - loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges) - loan = create_demand_loan(self.applicant2, "Demand Loan", loan_security_pledge.name, - posting_date=get_first_day(nowdate())) + loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge) + create_pledge(loan_application) + + loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate())) loan.submit() self.assertEquals(loan.loan_amount, 1000000) @@ -446,12 +442,13 @@ def create_loan_security(): "haircut": 50.00, }).insert(ignore_permissions=True) -def create_loan_security_pledge(applicant, pledges): +def create_loan_security_pledge(applicant, pledges, loan_application): lsp = frappe.new_doc("Loan Security Pledge") lsp.applicant_type = 'Customer' lsp.applicant = applicant lsp.company = "_Test Company" + lsp.loan_application = loan_application for pledge in pledges: lsp.append('securities', { @@ -510,6 +507,31 @@ def create_repayment_entry(loan, applicant, posting_date, payment_type, paid_amo return lr +def create_loan_application(company, applicant, loan_type, proposed_pledges, repayment_method=None, + repayment_periods=None, posting_date=None): + loan_application = frappe.new_doc('Loan Application') + loan_application.applicant_type = 'Customer' + loan_application.company = company + loan_application.applicant = applicant + loan_application.loan_type = loan_type + loan_application.posting_date = posting_date or nowdate() + loan_application.is_secured_loan = 1 + + if repayment_method: + loan_application.repayment_method = repayment_method + loan_application.repayment_periods = repayment_periods + + for pledge in proposed_pledges: + loan_application.append('proposed_pledges', pledge) + + loan_application.save() + loan_application.submit() + + loan_application.status = 'Approved' + loan_application.save() + + return loan_application.name + def create_loan(applicant, loan_type, loan_amount, repayment_method, repayment_periods, repayment_start_date=None, posting_date=None): @@ -531,14 +553,13 @@ def create_loan(applicant, loan_type, loan_amount, repayment_method, repayment_p loan.save() return loan -def create_loan_with_security(applicant, loan_type, repayment_method, repayment_periods, loan_security_pledge, - posting_date=None, repayment_start_date=None): - +def create_loan_with_security(applicant, loan_type, repayment_method, repayment_periods, loan_application, posting_date=None, repayment_start_date=None): loan = frappe.get_doc({ "doctype": "Loan", "company": "_Test Company", "applicant_type": "Customer", "posting_date": posting_date or nowdate(), + "loan_application": loan_application, "applicant": applicant, "loan_type": loan_type, "is_term_loan": 1, @@ -547,7 +568,6 @@ def create_loan_with_security(applicant, loan_type, repayment_method, repayment_ "repayment_periods": repayment_periods, "repayment_start_date": repayment_start_date or nowdate(), "mode_of_payment": frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name'), - "loan_security_pledge": loan_security_pledge, "payment_account": 'Payment Account - _TC', "loan_account": 'Loan Account - _TC', "interest_income_account": 'Interest Income Account - _TC', @@ -558,19 +578,19 @@ def create_loan_with_security(applicant, loan_type, repayment_method, repayment_ return loan -def create_demand_loan(applicant, loan_type, loan_security_pledge, posting_date=None): +def create_demand_loan(applicant, loan_type, loan_application, posting_date=None): loan = frappe.get_doc({ "doctype": "Loan", "company": "_Test Company", "applicant_type": "Customer", "posting_date": posting_date or nowdate(), + 'loan_application': loan_application, "applicant": applicant, "loan_type": loan_type, "is_term_loan": 0, "is_secured_loan": 1, "mode_of_payment": frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name'), - "loan_security_pledge": loan_security_pledge, "payment_account": 'Payment Account - _TC', "loan_account": 'Loan Account - _TC', "interest_income_account": 'Interest Income Account - _TC', diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.py b/erpnext/loan_management/doctype/loan_application/loan_application.py index d3b816464f1..f051755f67c 100644 --- a/erpnext/loan_management/doctype/loan_application/loan_application.py +++ b/erpnext/loan_management/doctype/loan_application/loan_application.py @@ -103,10 +103,13 @@ class LoanApplication(Document): if self.is_secured_loan and not self.proposed_pledges: frappe.throw(_("Proposed Pledges are mandatory for secured Loans")) - if not self.loan_amount and self.is_secured_loan and self.proposed_pledges: - self.loan_amount = 0 + if self.is_secured_loan and self.proposed_pledges: + self.maximum_loan_amount = 0 for security in self.proposed_pledges: - self.loan_amount += security.post_haircut_amount + self.maximum_loan_amount += security.post_haircut_amount + + if not self.loan_amount and self.is_secured_loan and self.proposed_pledges: + self.loan_amount = self.maximum_loan_amount @frappe.whitelist() def create_loan(source_name, target_doc=None, submit=0): @@ -116,7 +119,6 @@ def create_loan(source_name, target_doc=None, submit=0): filters = {'name': source_doc.loan_type} )[0] - loan_security_pledge = frappe.db.get_value("Loan Security Pledge", {"loan_application": source_name}, 'name') target_doc.mode_of_payment = account_details.mode_of_payment target_doc.payment_account = account_details.payment_account @@ -124,9 +126,6 @@ def create_loan(source_name, target_doc=None, submit=0): target_doc.interest_income_account = account_details.interest_income_account target_doc.penalty_income_account = account_details.penalty_income_account - if loan_security_pledge: - target_doc.is_secured_loan = 1 - target_doc.loan_security_pledge = loan_security_pledge doclist = get_mapped_doc("Loan Application", source_name, { "Loan Application": { diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py index 0c1578ffef5..2cb26376126 100644 --- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py +++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py @@ -5,11 +5,12 @@ from __future__ import unicode_literals import frappe import unittest from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date) -from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry, +from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry, create_loan_application, make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_security_price) from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year from erpnext.selling.doctype.customer.test_customer import get_customer_dict +from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge class TestLoanDisbursement(unittest.TestCase): @@ -31,18 +32,15 @@ class TestLoanDisbursement(unittest.TestCase): self.applicant = frappe.db.get_value("Customer", {'name': '_Test Loan Customer'}, 'name') def test_loan_topup(self): - pledges = [] - pledges.append({ + pledge = [{ "loan_security": "Test Security 1", - "qty": 4000.00, - "haircut": 50, - "loan_security_price": 500.00 - }) + "qty": 4000.00 + }] - loan_security_pledge = create_loan_security_pledge(self.applicant, pledges) + loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge) + create_pledge(loan_application) - loan = create_demand_loan(self.applicant, "Demand Loan", loan_security_pledge.name, - posting_date=get_first_day(nowdate())) + loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date=get_first_day(nowdate())) loan.submit() diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py index 2afed08e185..4b85b218696 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py @@ -6,10 +6,11 @@ import frappe import unittest from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date) from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_loan_security_price, - make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan) + make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_application) from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year from erpnext.selling.doctype.customer.test_customer import get_customer_dict +from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge class TestLoanInterestAccrual(unittest.TestCase): def setUp(self): @@ -29,17 +30,15 @@ class TestLoanInterestAccrual(unittest.TestCase): self.applicant = frappe.db.get_value("Customer", {'name': '_Test Loan Customer'}, 'name') def test_loan_interest_accural(self): - pledges = [] - pledges.append({ + pledge = [{ "loan_security": "Test Security 1", - "qty": 4000.00, - "haircut": 50, - "loan_security_price": 500.00 - }) + "qty": 4000.00 + }] - loan_security_pledge = create_loan_security_pledge(self.applicant, pledges) + loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge) + create_pledge(loan_application) - loan = create_demand_loan(self.applicant, "Demand Loan", loan_security_pledge.name, + loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date=get_first_day(nowdate())) loan.submit() diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.json b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.json index 1553844704d..4572e992998 100644 --- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.json +++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "LS-.{applicant}.-.#####", "creation": "2019-08-29 18:48:51.371674", "doctype": "DocType", @@ -6,10 +7,10 @@ "engine": "InnoDB", "field_order": [ "loan_details_section", - "loan_application", - "loan", "applicant_type", "applicant", + "loan", + "loan_application", "column_break_3", "company", "pledge_time", @@ -55,15 +56,13 @@ "fieldname": "loan", "fieldtype": "Link", "label": "Loan", - "options": "Loan", - "read_only": 1 + "options": "Loan" }, { "fieldname": "loan_application", "fieldtype": "Link", "label": "Loan Application", - "options": "Loan Application", - "read_only": 1 + "options": "Loan Application" }, { "fieldname": "total_security_value", @@ -133,7 +132,8 @@ } ], "is_submittable": 1, - "modified": "2019-10-10 13:22:53.297519", + "links": [], + "modified": "2020-07-02 23:38:24.002382", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan Security Pledge", diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py index b58f999cfba..add7bbfa57d 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py @@ -44,7 +44,7 @@ class MaintenanceSchedule(TransactionBase): for d in self.get('items'): if d.serial_no: serial_nos = get_valid_serial_nos(d.serial_no) - self.validate_serial_no(serial_nos, d.start_date) + self.validate_serial_no(d.item_code, serial_nos, d.start_date) self.update_amc_date(serial_nos, d.end_date) no_email_sp = [] @@ -178,14 +178,18 @@ class MaintenanceSchedule(TransactionBase): serial_no_doc.amc_expiry_date = amc_expiry_date serial_no_doc.save() - def validate_serial_no(self, serial_nos, amc_start_date): + def validate_serial_no(self, item_code, serial_nos, amc_start_date): for serial_no in serial_nos: sr_details = frappe.db.get_value("Serial No", serial_no, - ["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date"], as_dict=1) + ["warranty_expiry_date", "amc_expiry_date", "warehouse", "delivery_date", "item_code"], as_dict=1) if not sr_details: frappe.throw(_("Serial No {0} not found").format(serial_no)) + if sr_details.get("item_code") != item_code: + frappe.throw(_("Serial No {0} does not belong to Item {1}") + .format(frappe.bold(serial_no), frappe.bold(item_code)), title="Invalid") + if sr_details.warranty_expiry_date \ and getdate(sr_details.warranty_expiry_date) >= getdate(amc_start_date): throw(_("Serial No {0} is under warranty upto {1}") diff --git a/erpnext/manufacturing/dashboard_fixtures.py b/erpnext/manufacturing/dashboard_fixtures.py index 64e4bc6ed06..0e9a21c0268 100644 --- a/erpnext/manufacturing/dashboard_fixtures.py +++ b/erpnext/manufacturing/dashboard_fixtures.py @@ -192,7 +192,7 @@ def get_number_cards(): ]), "function": "Count", "is_public": 1, - "label": _("Monthly Total Work Order"), + "label": _("Monthly Total Work Orders"), "show_percentage_stats": 1, "stats_time_interval": "Weekly" }, @@ -207,7 +207,7 @@ def get_number_cards(): ]), "function": "Count", "is_public": 1, - "label": _("Monthly Completed Work Order"), + "label": _("Monthly Completed Work Orders"), "show_percentage_stats": 1, "stats_time_interval": "Weekly" }, @@ -221,7 +221,7 @@ def get_number_cards(): ]), "function": "Count", "is_public": 1, - "label": _("Ongoing Job Card"), + "label": _("Ongoing Job Cards"), "show_percentage_stats": 1, "stats_time_interval": "Weekly" }, @@ -235,7 +235,7 @@ def get_number_cards(): ]), "function": "Count", "is_public": 1, - "label": _("Monthly Quality Inspection"), + "label": _("Monthly Quality Inspections"), "show_percentage_stats": 1, "stats_time_interval": "Weekly" }] \ No newline at end of file diff --git a/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json b/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json index 763f533a94b..8d11294164f 100644 --- a/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json +++ b/erpnext/manufacturing/desk_page/manufacturing/manufacturing.json @@ -93,12 +93,6 @@ "stats_filter": "{ \n \"status\": [\"not in\", [\"Completed\"]]\n}", "type": "DocType" }, - { - "label": "Dashboard", - "link_to": "Manufacturing", - "restrict_to_domain": "Manufacturing", - "type": "Dashboard" - }, { "label": "Forecasting", "link_to": "Exponential Smoothing Forecasting", @@ -119,6 +113,12 @@ "label": "Production Planning Report", "link_to": "Production Planning Report", "type": "Report" - } + }, + { + "label": "Dashboard", + "link_to": "Manufacturing", + "restrict_to_domain": "Manufacturing", + "type": "Dashboard" + } ] } \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 7d31a1cd15e..8062342cfcd 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -494,7 +494,7 @@ class BOM(WebsiteGenerator): 'image' : d.image, 'stock_uom' : d.stock_uom, 'stock_qty' : flt(d.stock_qty), - 'rate' : d.base_rate, + 'rate' : flt(d.base_rate) / flt(d.conversion_factor), 'include_item_in_manufacturing': d.include_item_in_manufacturing })) @@ -910,6 +910,7 @@ def get_bom_diff(bom1, bom2): return out +@frappe.whitelist() def item_query(doctype, txt, searchfield, start, page_len, filters): meta = frappe.get_meta("Item", cached=True) searchfields = meta.get_search_fields() @@ -989,4 +990,4 @@ def make_variant_bom(source_name, bom_no, item, variant_items, target_doc=None): }, }, target_doc, postprocess) - return doc \ No newline at end of file + return doc diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index e2233a3e2f6..f962a1157b3 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -631,6 +631,7 @@ class WorkOrder(Document): bom.set_bom_material_details() return bom +@frappe.whitelist() def get_bom_operations(doctype, txt, searchfield, start, page_len, filters): if txt: filters['operation'] = ('like', '%%%s%%' % txt) diff --git a/erpnext/manufacturing/module_onboarding/manufacturing/manufacturing.json b/erpnext/manufacturing/module_onboarding/manufacturing/manufacturing.json index 952d1f0e071..7b5747e393f 100644 --- a/erpnext/manufacturing/module_onboarding/manufacturing/manufacturing.json +++ b/erpnext/manufacturing/module_onboarding/manufacturing/manufacturing.json @@ -19,7 +19,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/manufacturing", "idx": 0, "is_complete": 0, - "modified": "2020-05-19 12:51:42.744570", + "modified": "2020-07-08 14:05:56.197563", "modified_by": "Administrator", "module": "Manufacturing", "name": "Manufacturing", @@ -50,8 +50,7 @@ "step": "Explore Manufacturing Settings" } ], - "subtitle": "Products, Raw Materials, BOM, Work Order and more.", - "success_message": "Manufacturing module is all setup!", - "title": "Let's Setup Manufacturing Module", - "user_can_dismiss": 1 + "subtitle": "Products, Raw Materials, BOM, Work Order, and more.", + "success_message": "Manufacturing module is all set up!", + "title": "Let's Set Up the Manufacturing Module." } \ No newline at end of file diff --git a/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py b/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py index c5627e0c087..e3e440ebc62 100644 --- a/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py +++ b/erpnext/manufacturing/report/bom_variance_report/bom_variance_report.py @@ -19,7 +19,7 @@ def get_columns(filters): "options": "Work Order", "width": 120 }] - + if not filters.get('bom_no'): columns.extend([ { diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 17fbcc21909..566b979adef 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -697,6 +697,7 @@ execute:frappe.rename_doc("Desk Page", "Loan Management", "Loan", force=True) erpnext.patches.v12_0.update_uom_conversion_factor erpnext.patches.v13_0.delete_old_purchase_reports erpnext.patches.v12_0.set_italian_import_supplier_invoice_permissions +erpnext.patches.v12_0.unhide_cost_center_field erpnext.patches.v13_0.update_sla_enhancements erpnext.patches.v12_0.update_address_template_for_india erpnext.patches.v13_0.update_deferred_settings @@ -706,3 +707,5 @@ execute:frappe.delete_doc_if_exists("DocType", "Bank Reconciliation") erpnext.patches.v13_0.move_doctype_reports_and_notification_from_hr_to_payroll #22-06-2020 erpnext.patches.v13_0.move_payroll_setting_separately_from_hr_settings #22-06-2020 erpnext.patches.v13_0.check_is_income_tax_component #22-06-2020 +erpnext.patches.v12_0.add_taxjar_integration_field +erpnext.patches.v12_0.update_item_tax_template_company diff --git a/erpnext/patches/v12_0/add_taxjar_integration_field.py b/erpnext/patches/v12_0/add_taxjar_integration_field.py new file mode 100644 index 00000000000..4c823e13bdf --- /dev/null +++ b/erpnext/patches/v12_0/add_taxjar_integration_field.py @@ -0,0 +1,12 @@ +from __future__ import unicode_literals + +import frappe +from erpnext.regional.united_states.setup import make_custom_fields + + +def execute(): + company = frappe.get_all('Company', filters={'country': 'United States'}) + if not company: + return + + make_custom_fields() diff --git a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py index 82c8f5c4147..43bd0ccdd7c 100644 --- a/erpnext/patches/v12_0/create_irs_1099_field_united_states.py +++ b/erpnext/patches/v12_0/create_irs_1099_field_united_states.py @@ -5,6 +5,8 @@ from erpnext.regional.united_states.setup import make_custom_fields def execute(): frappe.reload_doc('accounts', 'doctype', 'allowed_to_transact_with', force=True) + frappe.reload_doc('accounts', 'doctype', 'pricing_rule_detail', force=True) + frappe.reload_doc('crm', 'doctype', 'lost_reason_detail', force=True) company = frappe.get_all('Company', filters = {'country': 'United States'}) if not company: diff --git a/erpnext/patches/v12_0/unhide_cost_center_field.py b/erpnext/patches/v12_0/unhide_cost_center_field.py new file mode 100644 index 00000000000..6005ab70726 --- /dev/null +++ b/erpnext/patches/v12_0/unhide_cost_center_field.py @@ -0,0 +1,13 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.db.sql(""" + DELETE FROM `tabProperty Setter` + WHERE doc_type in ('Sales Invoice', 'Purchase Invoice', 'Payment Entry') + AND field_name = 'cost_center' + AND property = 'hidden' + """) \ No newline at end of file diff --git a/erpnext/patches/v12_0/update_item_tax_template_company.py b/erpnext/patches/v12_0/update_item_tax_template_company.py new file mode 100644 index 00000000000..f7496999b33 --- /dev/null +++ b/erpnext/patches/v12_0/update_item_tax_template_company.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('accounts', 'doctype', 'item_tax_template') + + item_tax_template_list = frappe.get_list('Item Tax Template') + for template in item_tax_template_list: + doc = frappe.get_doc('Item Tax Template', template.name) + for tax in doc.taxes: + doc.company = frappe.get_value('Account', tax.tax_type, 'company') + break + doc.save() \ No newline at end of file diff --git a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py index 331c5590e58..adfa20e368a 100644 --- a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py +++ b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py @@ -6,7 +6,6 @@ from __future__ import unicode_literals import frappe from frappe.utils import add_to_date -from frappe.utils.dashboard import get_config, make_records def execute(): frappe.reload_doc("manufacturing", "doctype", "work_order") diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.js b/erpnext/payroll/doctype/additional_salary/additional_salary.js index fb42b6f410e..d56cd4e967d 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.js +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.js @@ -8,8 +8,7 @@ frappe.ui.form.on('Additional Salary', { frm.set_query("employee", function() { return { filters: { - company: frm.doc.company, - status: "Active" + company: frm.doc.company } }; }); diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py index e369ba7cef6..ef174bdea20 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.py +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py @@ -33,12 +33,16 @@ class AdditionalSalary(Document): frappe.throw(_("From Date can not be greater than To Date.")) if date_of_joining: - if getdate(self.payroll_date) < getdate(date_of_joining): + if self.payroll_date and getdate(self.payroll_date) < getdate(date_of_joining): frappe.throw(_("Payroll date can not be less than employee's joining date.")) - elif getdate(self.from_date) < getdate(date_of_joining): + elif self.from_date and getdate(self.from_date) < getdate(date_of_joining): frappe.throw(_("From date can not be less than employee's joining date.")) - elif relieving_date and getdate(self.to_date) > getdate(relieving_date): + + if relieving_date: + if self.to_date and getdate(self.to_date) > getdate(relieving_date): frappe.throw(_("To date can not be greater than employee's relieving date.")) + if self.payroll_date and getdate(self.payroll_date) > getdate(relieving_date): + frappe.throw(_("Payroll date can not be greater than employee's relieving date.")) def get_amount(self, sal_start_date, sal_end_date): start_date = getdate(sal_start_date) @@ -107,4 +111,4 @@ def get_additional_salary_component(employee, start_date, end_date, component_ty existing_salary_components.append(d.salary_component) - return salary_components_details, additional_salary_details \ No newline at end of file + return salary_components_details, additional_salary_details diff --git a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py index e166a704d60..d7d00e64809 100644 --- a/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py +++ b/erpnext/payroll/doctype/employee_benefit_application/employee_benefit_application.py @@ -222,7 +222,7 @@ def get_benefit_amount_based_on_pro_rata(sal_struct, component_max_benefit): return benefit_amount - +@frappe.whitelist() def get_earning_components(doctype, txt, searchfield, start, page_len, filters): if len(filters) < 2: return {} diff --git a/erpnext/payroll/doctype/employee_incentive/employee_incentive.py b/erpnext/payroll/doctype/employee_incentive/employee_incentive.py index 44763fc077e..84a97f6bb2e 100644 --- a/erpnext/payroll/doctype/employee_incentive/employee_incentive.py +++ b/erpnext/payroll/doctype/employee_incentive/employee_incentive.py @@ -13,6 +13,7 @@ class EmployeeIncentive(Document): additional_salary = frappe.new_doc('Additional Salary') additional_salary.employee = self.employee additional_salary.salary_component = self.salary_component + additional_salary.overwrite_salary_structure_amount = 0 additional_salary.amount = self.incentive_amount additional_salary.payroll_date = self.payroll_date additional_salary.company = company diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.js b/erpnext/payroll/doctype/payroll_entry/payroll_entry.js index 1ae3553b9b9..8d35a7be471 100644 --- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.js +++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.js @@ -30,6 +30,7 @@ frappe.ui.form.on('Payroll Entry', { ).toggleClass('btn-primary', !(frm.doc.employees || []).length); } if ((frm.doc.employees || []).length) { + frm.page.clear_primary_action(); frm.page.set_primary_action(__('Create Salary Slips'), () => { frm.save('Submit').then(()=>{ frm.page.clear_primary_action(); @@ -49,13 +50,14 @@ frappe.ui.form.on('Payroll Entry', { return frappe.call({ doc: frm.doc, method: 'fill_employee_details', - callback: function(r) { - if (r.docs[0].employees){ - frm.save(); - frm.refresh(); - if(r.docs[0].validate_attendance){ - render_employee_attendance(frm, r.message); - } + }).then(r => { + if (r.docs && r.docs[0].employees){ + frm.employees = r.docs[0].employees; + frm.dirty(); + frm.save(); + frm.refresh(); + if(r.docs[0].validate_attendance){ + render_employee_attendance(frm, r.message); } } }) diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py index e6bb708e418..ad9b6d86c89 100644 --- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py +++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py @@ -539,6 +539,7 @@ def submit_salary_slips_for_employees(payroll_entry, salary_slips, publish_progr if not_submitted_ss: frappe.msgprint(_("Could not submit some Salary Slips")) +@frappe.whitelist() def get_payroll_entries_for_jv(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql(""" select name from `tabPayroll Entry` diff --git a/erpnext/payroll/doctype/payroll_period/payroll_period.json b/erpnext/payroll/doctype/payroll_period/payroll_period.json index c919b4fe13b..0e0948475cf 100644 --- a/erpnext/payroll/doctype/payroll_period/payroll_period.json +++ b/erpnext/payroll/doctype/payroll_period/payroll_period.json @@ -53,7 +53,7 @@ } ], "links": [], - "modified": "2020-06-22 20:12:32.684189", + "modified": "2020-06-29 17:17:12.689089", "modified_by": "Administrator", "module": "Payroll", "name": "Payroll Period", @@ -96,6 +96,7 @@ "write": 1 } ], + "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 diff --git a/erpnext/payroll/doctype/retention_bonus/retention_bonus.py b/erpnext/payroll/doctype/retention_bonus/retention_bonus.py index ed0d36cfa5f..b8e56ae42aa 100644 --- a/erpnext/payroll/doctype/retention_bonus/retention_bonus.py +++ b/erpnext/payroll/doctype/retention_bonus/retention_bonus.py @@ -26,6 +26,7 @@ class RetentionBonus(Document): additional_salary.amount = self.bonus_amount additional_salary.payroll_date = self.bonus_payment_date additional_salary.company = company + additional_salary.overwrite_salary_structure_amount = 0 additional_salary.ref_doctype = self.doctype additional_salary.ref_docname = self.name additional_salary.submit() @@ -53,7 +54,7 @@ class RetentionBonus(Document): 'employee': self.employee, 'salary_component': self.salary_component, 'payroll_date': self.bonus_payment_date, - 'company': company, + 'company': self.company, 'docstatus': 1, 'ref_doctype': self.doctype, 'ref_docname': self.name diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py index 2da19b03978..1e2983e4218 100644 --- a/erpnext/payroll/doctype/salary_slip/salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py @@ -207,7 +207,7 @@ class SalarySlip(TransactionBase): frappe.throw(_("There are more holidays than working days this month.")) if not payroll_based_on: - frappe.throw(_("Please set Payroll based on in HR settings")) + frappe.throw(_("Please set Payroll based on in Payroll settings")) if payroll_based_on == "Attendance": actual_lwp, absent = self.calculate_lwp_and_absent_days_based_on_attendance(holidays) @@ -244,15 +244,13 @@ class SalarySlip(TransactionBase): for holiday in holidays: if not frappe.db.exists("Attendance", {"employee": self.employee, "attendance_date": holiday, "docstatus": 1 }): self.payment_days += 1 - - else: self.payment_days = 0 def get_unmarked_days(self): marked_days = frappe.get_all("Attendance", filters = { - "attendance_date": ["between", ['2020-05-1',"2020-05-30"]], - "employee": 'HR-EMP-00003', + "attendance_date": ["between", [self.start_date, self.end_date]], + "employee": self.employee, "docstatus": 1 }, fields = ["COUNT(*) as marked_days"])[0].marked_days diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index f42b9ad11dc..37cd89a7349 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -105,7 +105,7 @@ class TestSalarySlip(unittest.TestCase): #Gross pay calculation based on attendances gross_pay = 78000 - ((78000 / (days_in_month - no_of_holidays)) * flt(ss.leave_without_pay)) - self.assertEqual(ss.gross_pay, gross_pay) + self.assertEqual(flt(ss.gross_pay, 2), flt(gross_pay, 2)) frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave") @@ -271,6 +271,7 @@ class TestSalarySlip(unittest.TestCase): # as per assigned salary structure 40500 in monthly salary so 236000*5/100/12 frappe.db.sql("""delete from `tabPayroll Period`""") frappe.db.sql("""delete from `tabSalary Component`""") + frappe.db.sql("""delete from `tabAdditional Salary`""") payroll_period = create_payroll_period() diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.js b/erpnext/payroll/doctype/salary_structure/salary_structure.js index ca458f976f6..ad93a2fa4bf 100755 --- a/erpnext/payroll/doctype/salary_structure/salary_structure.js +++ b/erpnext/payroll/doctype/salary_structure/salary_structure.js @@ -35,7 +35,9 @@ frappe.ui.form.on('Salary Structure', { d.show() }); - frm.get_field("conditions_and_formula_variable_and_example").$wrapper.append(frm.doc.filters_html).append(help_button) + let help_button_wrapper = frm.get_field("conditions_and_formula_variable_and_example").$wrapper; + help_button_wrapper.empty(); + help_button_wrapper.append(frm.doc.filters_html).append(help_button) frm.toggle_reqd(['payroll_frequency'], !frm.doc.salary_slip_based_on_timesheet) diff --git a/erpnext/payroll/module_onboarding/payroll/payroll.json b/erpnext/payroll/module_onboarding/payroll/payroll.json index a4ea53640eb..b5226b2aca3 100644 --- a/erpnext/payroll/module_onboarding/payroll/payroll.json +++ b/erpnext/payroll/module_onboarding/payroll/payroll.json @@ -13,7 +13,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/human-resources/payroll-entry", "idx": 0, "is_complete": 0, - "modified": "2020-06-04 16:35:30.650792", + "modified": "2020-07-08 14:06:13.994310", "modified_by": "Administrator", "module": "Payroll", "name": "Payroll", @@ -44,8 +44,7 @@ "step": "Payroll Settings" } ], - "subtitle": "Salary, Compensations and more.", - "success_message": "The Payroll is all set up!", - "title": "Let's Setup the Payroll Module. ", - "user_can_dismiss": 1 + "subtitle": "Salary, Compensation, and more.", + "success_message": "The Payroll Module is all set up!", + "title": "Let's Set Up the Payroll Module. " } \ No newline at end of file diff --git a/erpnext/payroll/onboarding_step/create_employee/create_employee.json b/erpnext/payroll/onboarding_step/create_employee/create_employee.json index 5839ae6ca4a..3aa33c6d862 100644 --- a/erpnext/payroll/onboarding_step/create_employee/create_employee.json +++ b/erpnext/payroll/onboarding_step/create_employee/create_employee.json @@ -15,5 +15,5 @@ "reference_document": "Employee", "show_full_form": 0, "title": "Create Employee", - "validate_action": 1 + "validate_action": 0 } \ No newline at end of file diff --git a/erpnext/payroll/report/bank_remittance/bank_remittance.py b/erpnext/payroll/report/bank_remittance/bank_remittance.py index a35d8e550ec..4b052bf5c4b 100644 --- a/erpnext/payroll/report/bank_remittance/bank_remittance.py +++ b/erpnext/payroll/report/bank_remittance/bank_remittance.py @@ -152,6 +152,9 @@ def set_company_account(payment_accounts, payroll_entries): company_accounts_map[acc.account] = acc for entry in payroll_entries: - entry["company_account"] = company_accounts_map[entry.payment_account]['bank_account_no'] + company_account = '' + if entry.payment_account in company_accounts_map: + company_account = company_accounts_map[entry.payment_account]['bank_account_no'] + entry["company_account"] = company_account return payroll_entries diff --git a/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py b/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py index 3bad5879bb3..8a79416edbf 100644 --- a/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py +++ b/erpnext/payroll/report/income_tax_deductions/income_tax_deductions.py @@ -6,8 +6,8 @@ import frappe, erpnext from frappe import _ def execute(filters=None): - columns = get_columns(filters) data = get_data(filters) + columns = get_columns(filters) if len(data) else [] return columns, data @@ -78,8 +78,11 @@ def get_conditions(filters): if filters.get("company"): conditions.append("sal.company = '%s' " % (filters["company"]) ) - if filters.get("period"): - conditions.append("month(sal.start_date) = '%s' " % (filters["period"])) + if filters.get("month"): + conditions.append("month(sal.start_date) = '%s' " % (filters["month"])) + + if filters.get("year"): + conditions.append("year(start_date) = '%s' " % (filters["year"])) return " and ".join(conditions) @@ -96,6 +99,9 @@ def get_data(filters): component_types = [comp_type[0] for comp_type in component_types] + if not len(component_types): + return [] + conditions = get_conditions(filters) entry = frappe.db.sql(""" select sal.employee, sal.employee_name, sal.posting_date, ded.salary_component, ded.amount,sal.gross_pay diff --git a/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py b/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py index 7f0c2e2e000..a0dab63654e 100644 --- a/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py +++ b/erpnext/payroll/report/salary_payments_based_on_payment_mode/salary_payments_based_on_payment_mode.py @@ -100,6 +100,8 @@ def get_data(filters, mode_of_payments): total_row = get_total_based_on_mode_of_payment(data, mode_of_payments) total_deductions = gross_pay - total_row.get("total") + report_summary = [] + if data: data.append(total_row) data.append({}) diff --git a/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py b/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py index 073bd91300e..d09745c37bb 100644 --- a/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py +++ b/erpnext/payroll/report/salary_payments_via_ecs/salary_payments_via_ecs.py @@ -84,9 +84,11 @@ def get_conditions(filters): if filters.get("company"): conditions.append("company = '%s' " % (filters["company"]) ) - if filters.get("period"): - conditions.append("month(start_date) = '%s' " % (filters["period"])) - conditions.append("year(start_date) = '%s' " % (frappe.utils.getdate().year)) + if filters.get("month"): + conditions.append("month(start_date) = '%s' " % (filters["month"])) + + if filters.get("year"): + conditions.append("year(start_date) = '%s' " % (filters["year"])) return " and ".join(conditions) diff --git a/erpnext/projects/desk_page/projects/projects.json b/erpnext/projects/desk_page/projects/projects.json index d91fe5304a3..e24cf3081cb 100644 --- a/erpnext/projects/desk_page/projects/projects.json +++ b/erpnext/projects/desk_page/projects/projects.json @@ -68,7 +68,7 @@ "type": "Report" }, { - "label": "Project Dashboard", + "label": "Dashboard", "link_to": "Project", "type": "Dashboard" } diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index afdb5b7a01d..32ea05b42ad 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -238,6 +238,7 @@ def get_list_context(context=None): "row_template": "templates/includes/projects/project_row.html" } +@frappe.whitelist() def get_users_for_project(doctype, txt, searchfield, start, page_len, filters): conditions = [] return frappe.db.sql("""select name, concat_ws(' ', first_name, middle_name, last_name) diff --git a/erpnext/projects/doctype/project/test_project.py b/erpnext/projects/doctype/project/test_project.py index 06c62b62d2f..0c4f6f1bdfe 100644 --- a/erpnext/projects/doctype/project/test_project.py +++ b/erpnext/projects/doctype/project/test_project.py @@ -7,7 +7,7 @@ import frappe, unittest test_records = frappe.get_test_records('Project') test_ignore = ["Sales Order"] -from erpnext.projects.doctype.project_template.test_project_template import get_project_template +from erpnext.projects.doctype.project_template.test_project_template import get_project_template, make_project_template from erpnext.projects.doctype.project.project import set_project_status from frappe.utils import getdate @@ -43,4 +43,24 @@ def get_project(name): expected_start_date = '2019-01-01' )).insert() + return project + +def make_project(args): + args = frappe._dict(args) + if args.project_template_name: + template = make_project_template(args.project_template_name) + else: + template = get_project_template() + + project = frappe.get_doc(dict( + doctype = 'Project', + project_name = args.project_name, + status = 'Open', + project_template = template.name, + expected_start_date = args.start_date + )) + + if not frappe.db.exists("Project", args.project_name): + project.insert() + return project \ No newline at end of file diff --git a/erpnext/projects/doctype/project_template/test_project_template.py b/erpnext/projects/doctype/project_template/test_project_template.py index efcb2eab68b..2c5831a5dc9 100644 --- a/erpnext/projects/doctype/project_template/test_project_template.py +++ b/erpnext/projects/doctype/project_template/test_project_template.py @@ -26,4 +26,23 @@ def get_project_template(): ] )).insert() - return frappe.get_doc('Project Template', 'Test Project Template') \ No newline at end of file + return frappe.get_doc('Project Template', 'Test Project Template') + +def make_project_template(project_template_name, project_tasks=[]): + if not frappe.db.exists('Project Template', project_template_name): + frappe.get_doc(dict( + doctype = 'Project Template', + name = project_template_name, + tasks = project_tasks or [ + dict(subject='Task 1', description='Task 1 description', + start=0, duration=3), + dict(subject='Task 2', description='Task 2 description', + start=0, duration=2), + dict(subject='Task 3', description='Task 3 description', + start=2, duration=4), + dict(subject='Task 4', description='Task 4 description', + start=3, duration=2), + ] + )).insert() + + return frappe.get_doc('Project Template', project_template_name) \ No newline at end of file diff --git a/erpnext/projects/doctype/task/task.js b/erpnext/projects/doctype/task/task.js index 5719276669a..8c6a9cf8d7c 100644 --- a/erpnext/projects/doctype/task/task.js +++ b/erpnext/projects/doctype/task/task.js @@ -3,55 +3,42 @@ frappe.provide("erpnext.projects"); -cur_frm.add_fetch("project", "company", "company"); - frappe.ui.form.on("Task", { - onload: function(frm) { - frm.set_query("task", "depends_on", function() { - var filters = { + setup: function (frm) { + frm.set_query("project", function () { + return { + query: "erpnext.projects.doctype.task.task.get_project" + } + }); + + frm.make_methods = { + 'Timesheet': () => frappe.model.open_mapped_doc({ + method: 'erpnext.projects.doctype.task.task.make_timesheet', + frm: frm + }) + } + }, + + onload: function (frm) { + frm.set_query("task", "depends_on", function () { + let filters = { name: ["!=", frm.doc.name] }; - if(frm.doc.project) filters["project"] = frm.doc.project; + if (frm.doc.project) filters["project"] = frm.doc.project; return { filters: filters }; }) - }, - refresh: function(frm) { - frm.fields_dict['parent_task'].get_query = function () { + frm.set_query("parent_task", function () { + let filters = { + "is_group": 1 + }; + if (frm.doc.project) filters["project"] = frm.doc.project; return { - filters: { - "is_group": 1, - } + filters: filters } - } - - if (!frm.doc.is_group) { - if (!frm.is_new()) { - if (frappe.model.can_read("Timesheet")) { - frm.add_custom_button(__("Timesheet"), () => { - frappe.route_options = { "project": frm.doc.project, "task": frm.doc.name } - frappe.set_route("List", "Timesheet"); - }, __("View"), true); - } - - if (frappe.model.can_read("Expense Claim")) { - frm.add_custom_button(__("Expense Claims"), () => { - frappe.route_options = { "project": frm.doc.project, "task": frm.doc.name }; - frappe.set_route("List", "Expense Claim"); - }, __("View"), true); - } - } - } - }, - - setup: function(frm) { - frm.fields_dict.project.get_query = function() { - return { - query: "erpnext.projects.doctype.task.task.get_project" - } - }; + }); }, is_group: function (frm) { @@ -69,12 +56,8 @@ frappe.ui.form.on("Task", { }) }, - validate: function(frm) { + validate: function (frm) { frm.doc.project && frappe.model.remove_from_locals("Project", frm.doc.project); - }, - + } }); - -cur_frm.add_fetch('task', 'subject', 'subject'); -cur_frm.add_fetch('task', 'project', 'project'); diff --git a/erpnext/projects/doctype/task/task.json b/erpnext/projects/doctype/task/task.json index f4b3d3e1ada..27f1a71a528 100644 --- a/erpnext/projects/doctype/task/task.json +++ b/erpnext/projects/doctype/task/task.json @@ -183,7 +183,8 @@ { "fieldname": "progress", "fieldtype": "Percent", - "label": "% Progress" + "label": "% Progress", + "no_copy": 1 }, { "default": "0", @@ -324,6 +325,7 @@ "options": "Department" }, { + "fetch_from": "project.company", "fieldname": "company", "fieldtype": "Link", "label": "Company", @@ -356,6 +358,7 @@ "fieldname": "completed_by", "fieldtype": "Link", "label": "Completed By", + "no_copy": 1, "options": "User" } ], @@ -364,7 +367,7 @@ "is_tree": 1, "links": [], "max_attachments": 5, - "modified": "2020-03-18 18:08:44.153211", + "modified": "2020-07-03 12:36:04.960457", "modified_by": "Administrator", "module": "Projects", "name": "Task", diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 1cb2c50cbf8..4bdda68b693 100755 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -7,10 +7,11 @@ import json import frappe from frappe import _, throw -from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate, today +from frappe.desk.form.assign_to import clear, close_all_assignments +from frappe.model.mapper import get_mapped_doc +from frappe.utils import add_days, cstr, date_diff, get_link_to_form, getdate, today, flt from frappe.utils.nestedset import NestedSet -from frappe.desk.form.assign_to import close_all_assignments, clear -from frappe.utils import date_diff + class CircularReferenceError(frappe.ValidationError): pass class EndDateCannotBeGreaterThanProjectEndDateError(frappe.ValidationError): pass @@ -62,10 +63,10 @@ class Task(NestedSet): close_all_assignments(self.doctype, self.name) def validate_progress(self): - if (self.progress or 0) > 100: + if flt(self.progress or 0) > 100: frappe.throw(_("Progress % for a task cannot be more than 100.")) - if self.progress == 100: + if flt(self.progress) == 100: self.status = 'Completed' if self.status == 'Completed': @@ -188,6 +189,7 @@ def check_if_child_exists(name): return child_tasks +@frappe.whitelist() def get_project(doctype, txt, searchfield, start, page_len, filters): from erpnext.controllers.queries import get_match_cond return frappe.db.sql(""" select name from `tabProject` @@ -219,6 +221,26 @@ def set_tasks_as_overdue(): continue frappe.get_doc("Task", task.name).update_status() + +@frappe.whitelist() +def make_timesheet(source_name, target_doc=None, ignore_permissions=False): + def set_missing_values(source, target): + target.append("time_logs", { + "hours": source.actual_time, + "completed": source.status == "Completed", + "project": source.project, + "task": source.name + }) + + doclist = get_mapped_doc("Task", source_name, { + "Task": { + "doctype": "Timesheet" + } + }, target_doc, postprocess=set_missing_values, ignore_permissions=ignore_permissions) + + return doclist + + @frappe.whitelist() def get_children(doctype, parent, task=None, project=None, is_root=False): diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 905f6fb80f5..3c56a636bd1 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1835,7 +1835,8 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ if (doc.tax_category) filters['tax_category'] = doc.tax_category; - + if (doc.company) + filters['company'] = doc.company; return { query: "erpnext.controllers.queries.get_tax_template", filters: filters diff --git a/erpnext/public/js/help_links.js b/erpnext/public/js/help_links.js index 17b726ee18f..66ff46405d1 100644 --- a/erpnext/public/js/help_links.js +++ b/erpnext/public/js/help_links.js @@ -450,7 +450,7 @@ frappe.help.help_links['Form/Opportunity'] = [ ] frappe.help.help_links['Form/Address'] = [ - { label: 'Address', url: docsUrl + 'user/manual/en/CRM/contact' }, + { label: 'Address', url: docsUrl + 'user/manual/en/CRM/address' }, ] frappe.help.help_links['Form/Contact'] = [ diff --git a/erpnext/public/js/salary_slip_deductions_report_filters.js b/erpnext/public/js/salary_slip_deductions_report_filters.js index 242037991aa..2b30e650753 100644 --- a/erpnext/public/js/salary_slip_deductions_report_filters.js +++ b/erpnext/public/js/salary_slip_deductions_report_filters.js @@ -11,8 +11,8 @@ erpnext.salary_slip_deductions_report_filters = { default: frappe.defaults.get_user_default("Company"), }, { - fieldname: "period", - label: __("Period"), + fieldname: "month", + label: __("Month"), fieldtype: "Select", reqd: 1 , options: [ @@ -31,6 +31,12 @@ erpnext.salary_slip_deductions_report_filters = { ], default: frappe.datetime.str_to_obj(frappe.datetime.get_today()).getMonth() + 1 }, + { + fieldname:"year", + label: __("Year"), + fieldtype: "Select", + reqd: 1 + }, { fieldname: "department", label: __("Department"), @@ -43,5 +49,18 @@ erpnext.salary_slip_deductions_report_filters = { fieldtype: "Link", options: "Branch", } - ] + ], + + "onload": function() { + return frappe.call({ + method: "erpnext.regional.report.provident_fund_deductions.provident_fund_deductions.get_years", + callback: function(r) { + var year_filter = frappe.query_report.get_filter('year'); + year_filter.df.options = r.message; + year_filter.df.default = r.message.split("\n")[0]; + year_filter.refresh(); + year_filter.set_input(year_filter.df.default); + } + }); + } } \ No newline at end of file diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 99c1b8ae8f3..065326744c2 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -4,7 +4,7 @@ frappe.provide("erpnext.utils"); erpnext.utils.get_party_details = function(frm, method, args, callback) { - if(!method) { + if (!method) { method = "erpnext.accounts.party.get_party_details"; } @@ -22,12 +22,12 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { } } - if(!args) { - if((frm.doctype != "Purchase Order" && frm.doc.customer) + if (!args) { + if ((frm.doctype != "Purchase Order" && frm.doc.customer) || (frm.doc.party_name && in_list(['Quotation', 'Opportunity'], frm.doc.doctype))) { let party_type = "Customer"; - if(frm.doc.quotation_to && frm.doc.quotation_to === "Lead") { + if (frm.doc.quotation_to && frm.doc.quotation_to === "Lead") { party_type = "Lead"; } @@ -36,7 +36,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { party_type: party_type, price_list: frm.doc.selling_price_list }; - } else if(frm.doc.supplier) { + } else if (frm.doc.supplier) { args = { party: frm.doc.supplier, party_type: "Supplier", @@ -78,13 +78,17 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { args.posting_date = frm.doc.posting_date || frm.doc.transaction_date; } } - if(!args || !args.party) return; + if (!args || !args.party) return; - if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) { - if(!erpnext.utils.validate_mandatory(frm, "Posting/Transaction Date", + if (frappe.meta.get_docfield(frm.doc.doctype, "taxes")) { + if (!erpnext.utils.validate_mandatory(frm, "Posting / Transaction Date", args.posting_date, args.party_type=="Customer" ? "customer": "supplier")) return; } + if (!erpnext.utils.validate_mandatory(frm, "Company", frm.doc.company, args.party_type=="Customer" ? "customer": "supplier")) { + return; + } + args.currency = frm.doc.currency; args.company = frm.doc.company; args.doctype = frm.doc.doctype; @@ -92,14 +96,14 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { method: method, args: args, callback: function(r) { - if(r.message) { + if (r.message) { frm.supplier_tds = r.message.supplier_tds; frm.updating_party_details = true; frappe.run_serially([ () => frm.set_value(r.message), () => { frm.updating_party_details = false; - if(callback) callback(); + if (callback) callback(); frm.refresh(); erpnext.utils.add_item(frm); } @@ -110,9 +114,9 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { } erpnext.utils.add_item = function(frm) { - if(frm.is_new()) { + if (frm.is_new()) { var prev_route = frappe.get_prev_route(); - if(prev_route[1]==='Item' && !(frm.doc.items && frm.doc.items.length)) { + if (prev_route[1]==='Item' && !(frm.doc.items && frm.doc.items.length)) { // add row var item = frm.add_child('items'); frm.refresh_field('items'); @@ -124,23 +128,23 @@ erpnext.utils.add_item = function(frm) { } erpnext.utils.get_address_display = function(frm, address_field, display_field, is_your_company_address) { - if(frm.updating_party_details) return; + if (frm.updating_party_details) return; - if(!address_field) { - if(frm.doctype != "Purchase Order" && frm.doc.customer) { + if (!address_field) { + if (frm.doctype != "Purchase Order" && frm.doc.customer) { address_field = "customer_address"; - } else if(frm.doc.supplier) { + } else if (frm.doc.supplier) { address_field = "supplier_address"; } else return; } - if(!display_field) display_field = "address_display"; - if(frm.doc[address_field]) { + if (!display_field) display_field = "address_display"; + if (frm.doc[address_field]) { frappe.call({ method: "frappe.contacts.doctype.address.address.get_address_display", args: {"address_dict": frm.doc[address_field] }, callback: function(r) { - if(r.message) { + if (r.message) { frm.set_value(display_field, r.message) } } @@ -151,15 +155,15 @@ erpnext.utils.get_address_display = function(frm, address_field, display_field, }; erpnext.utils.set_taxes_from_address = function(frm, triggered_from_field, billing_address_field, shipping_address_field) { - if(frm.updating_party_details) return; + if (frm.updating_party_details) return; - if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) { - if(!erpnext.utils.validate_mandatory(frm, "Lead/Customer/Supplier", + if (frappe.meta.get_docfield(frm.doc.doctype, "taxes")) { + if (!erpnext.utils.validate_mandatory(frm, "Lead / Customer / Supplier", frm.doc.customer || frm.doc.supplier || frm.doc.lead || frm.doc.party_name, triggered_from_field)) { return; } - if(!erpnext.utils.validate_mandatory(frm, "Posting/Transaction Date", + if (!erpnext.utils.validate_mandatory(frm, "Posting / Transaction Date", frm.doc.posting_date || frm.doc.transaction_date, triggered_from_field)) { return; } @@ -175,8 +179,8 @@ erpnext.utils.set_taxes_from_address = function(frm, triggered_from_field, billi "shipping_address": frm.doc[shipping_address_field] }, callback: function(r) { - if(!r.exc){ - if(frm.doc.tax_category != r.message) { + if (!r.exc){ + if (frm.doc.tax_category != r.message) { frm.set_value("tax_category", r.message); } else { erpnext.utils.set_taxes(frm, triggered_from_field); @@ -187,13 +191,17 @@ erpnext.utils.set_taxes_from_address = function(frm, triggered_from_field, billi }; erpnext.utils.set_taxes = function(frm, triggered_from_field) { - if(frappe.meta.get_docfield(frm.doc.doctype, "taxes")) { - if(!erpnext.utils.validate_mandatory(frm, "Lead/Customer/Supplier", + if (frappe.meta.get_docfield(frm.doc.doctype, "taxes")) { + if (!erpnext.utils.validate_mandatory(frm, "Company", frm.doc.company, triggered_from_field)) { + return; + } + + if (!erpnext.utils.validate_mandatory(frm, "Lead / Customer / Supplier", frm.doc.customer || frm.doc.supplier || frm.doc.lead || frm.doc.party_name, triggered_from_field)) { return; } - if(!erpnext.utils.validate_mandatory(frm, "Posting/Transaction Date", + if (!erpnext.utils.validate_mandatory(frm, "Posting / Transaction Date", frm.doc.posting_date || frm.doc.transaction_date, triggered_from_field)) { return; } @@ -230,7 +238,7 @@ erpnext.utils.set_taxes = function(frm, triggered_from_field) { "shipping_address": frm.doc.shipping_address_name }, callback: function(r) { - if(r.message){ + if (r.message){ frm.set_value("taxes_and_charges", r.message) } } @@ -238,14 +246,14 @@ erpnext.utils.set_taxes = function(frm, triggered_from_field) { }; erpnext.utils.get_contact_details = function(frm) { - if(frm.updating_party_details) return; + if (frm.updating_party_details) return; - if(frm.doc["contact_person"]) { + if (frm.doc["contact_person"]) { frappe.call({ method: "frappe.contacts.doctype.contact.contact.get_contact_details", args: {contact: frm.doc.contact_person }, callback: function(r) { - if(r.message) + if (r.message) frm.set_value(r.message); } }) @@ -253,10 +261,10 @@ erpnext.utils.get_contact_details = function(frm) { } erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) { - if(!value) { + if (!value) { frm.doc[trigger_on] = ""; refresh_field(trigger_on); - frappe.msgprint(__("Please enter {0} first", [label])); + frappe.throw({message:__("Please enter {0} first", [label]), title:__("Mandatory")}); return false; } return true; @@ -271,12 +279,12 @@ erpnext.utils.get_shipping_address = function(frm, callback){ address: frm.doc.shipping_address }, callback: function(r){ - if(r.message){ + if (r.message){ frm.set_value("shipping_address", r.message[0]) //Address title or name frm.set_value("shipping_address_display", r.message[1]) //Address to be displayed on the page } - if(callback){ + if (callback){ return callback(); } } diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.js b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.js index 63747afb3f4..dac6ac40a71 100644 --- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.js +++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.js @@ -5,21 +5,28 @@ frappe.ui.form.on('Quality Feedback', { refresh: function(frm) { frm.set_value("date", frappe.datetime.get_today()); }, - template: function(frm){ - frappe.call({ - "method": "frappe.client.get", - args: { - doctype: "Quality Feedback Template", - name: frm.doc.template - }, - callback: function(data){ - frm.fields_dict.parameters.grid.remove_all(); - for (var i in data.message.parameters){ - frm.add_child("parameters"); - frm.fields_dict.parameters.get_value()[i].parameter = data.message.parameters[i].parameter; + + template: function(frm) { + if (frm.doc.template) { + frappe.call({ + "method": "frappe.client.get", + args: { + doctype: "Quality Feedback Template", + name: frm.doc.template + }, + callback: function(data) { + if (data && data.message) { + frm.fields_dict.parameters.grid.remove_all(); + + // fetch parameters from template and autofill + for (let template_parameter of data.message.parameters) { + let row = frm.add_child("parameters"); + row.parameter = template_parameter.parameter; + } + frm.refresh(); + } } - frm.refresh(); - } - }); + }); + } } }); diff --git a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.json b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.json index 460438af621..ab9084fa79b 100644 --- a/erpnext/quality_management/doctype/quality_feedback/quality_feedback.json +++ b/erpnext/quality_management/doctype/quality_feedback/quality_feedback.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "format:FDBK-{#####}", "creation": "2019-05-26 21:23:05.308379", "doctype": "DocType", @@ -53,12 +54,13 @@ { "fieldname": "document_name", "fieldtype": "Dynamic Link", - "label": "Name", + "label": "Feedback By", "options": "document_type", "reqd": 1 } ], - "modified": "2019-05-28 15:16:01.161662", + "links": [], + "modified": "2020-07-03 15:50:58.589302", "modified_by": "Administrator", "module": "Quality Management", "name": "Quality Feedback", diff --git a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.json b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.json index 31efd04682a..bdc9dbab492 100644 --- a/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.json +++ b/erpnext/quality_management/doctype/quality_feedback_template/quality_feedback_template.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "format:TMPL-{template}", "creation": "2019-05-26 21:17:24.283061", "doctype": "DocType", @@ -30,10 +31,12 @@ "fieldname": "parameters", "fieldtype": "Table", "label": "Parameters", - "options": "Quality Feedback Template Parameter" + "options": "Quality Feedback Template Parameter", + "reqd": 1 } ], - "modified": "2019-05-26 21:48:47.770610", + "links": [], + "modified": "2020-07-03 16:06:03.749415", "modified_by": "Administrator", "module": "Quality Management", "name": "Quality Feedback Template", diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.js b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.js index a1cea8f6092..c7442667c22 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.js +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.js @@ -3,6 +3,7 @@ frappe.ui.form.on('GSTR 3B Report', { refresh : function(frm) { + frm.doc.__unsaved = 1; if(!frm.is_new()) { frm.set_intro(__("Please save the report again to rebuild or update")); frm.add_custom_button(__('Download JSON'), function() { diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py index 619734ff263..2d306ba1726 100644 --- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py +++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py @@ -243,20 +243,15 @@ class GSTR3BReport(Document): osup_det = self.report_dict["sup_details"]["osup_det"] - for d in inter_state_supply.get("Unregistered", []): - self.report_dict["inter_sup"]["unreg_details"].append(d) - osup_det["txval"] = flt(osup_det["txval"] + d["txval"], 2) - osup_det["iamt"] = flt(osup_det["iamt"] + d["iamt"], 2) + for key, value in iteritems(inter_state_supply): + if key[0] == "Unregistered": + self.report_dict["inter_sup"]["unreg_details"].append(value) - for d in inter_state_supply.get("Registered Composition", []): - self.report_dict["inter_sup"]["comp_details"].append(d) - osup_det["txval"] = flt(osup_det["txval"] + d["txval"], 2) - osup_det["iamt"] = flt(osup_det["iamt"] + d["iamt"], 2) + if key[0] == "Registered Composition": + self.report_dict["inter_sup"]["comp_details"].append(value) - for d in inter_state_supply.get("UIN Holders", []): - self.report_dict["inter_sup"]["uin_details"].append(d) - osup_det["txval"] = flt(osup_det["txval"] + d["txval"], 2) - osup_det["iamt"] = flt(osup_det["iamt"] + d["iamt"], 2) + if key[0] == "UIN Holders": + self.report_dict["inter_sup"]["uin_details"].append(value) def get_total_taxable_value(self, doctype, reverse_charge): @@ -301,41 +296,55 @@ class GSTR3BReport(Document): (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1)[0].total def get_inter_state_supplies(self, state_number): - - inter_state_supply_taxable_value = frappe.db.sql(""" select sum(s.net_total) as total, s.place_of_supply, s.gst_category - from `tabSales Invoice` s where s.docstatus = 1 and month(s.posting_date) = %s and year(s.posting_date) = %s - and s.company = %s and s.company_gstin = %s and s.gst_category in ('Unregistered', 'Registered Composition', 'UIN Holders') - group by s.gst_category, s.place_of_supply""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1) - - inter_state_supply_tax = frappe.db.sql(""" select sum(t.tax_amount_after_discount_amount) as tax_amount, s.place_of_supply, s.gst_category - from `tabSales Invoice` s, `tabSales Taxes and Charges` t + inter_state_supply_tax = frappe.db.sql(""" select t.account_head, t.tax_amount_after_discount_amount as tax_amount, + s.name, s.net_total, s.place_of_supply, s.gst_category from `tabSales Invoice` s, `tabSales Taxes and Charges` t where t.parent = s.name and s.docstatus = 1 and month(s.posting_date) = %s and year(s.posting_date) = %s and s.company = %s and s.company_gstin = %s and s.gst_category in ('Unregistered', 'Registered Composition', 'UIN Holders') - group by s.gst_category, s.place_of_supply""", (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1) + """, (self.month_no, self.year, self.company, self.gst_details.get("gstin")), as_dict=1) - inter_state_supply_tax_mapping={} + inter_state_supply_tax_mapping = {} inter_state_supply_details = {} for d in inter_state_supply_tax: - inter_state_supply_tax_mapping.setdefault(d.place_of_supply, d.tax_amount) + inter_state_supply_tax_mapping.setdefault(d.name, { + 'place_of_supply': d.place_of_supply, + 'taxable_value': d.net_total, + 'camt': 0.0, + 'samt': 0.0, + 'iamt': 0.0, + 'csamt': 0.0 + }) - for d in inter_state_supply_taxable_value: - inter_state_supply_details.setdefault( - d.gst_category, [] - ) + if d.account_head in [d.cgst_account for d in self.account_heads]: + inter_state_supply_tax_mapping[d.name]['camt'] += d.tax_amount + if d.account_head in [d.sgst_account for d in self.account_heads]: + inter_state_supply_tax_mapping[d.name]['samt'] += d.tax_amount + + if d.account_head in [d.igst_account for d in self.account_heads]: + inter_state_supply_tax_mapping[d.name]['iamt'] += d.tax_amount + + if d.account_head in [d.cess_account for d in self.account_heads]: + inter_state_supply_tax_mapping[d.name]['csamt'] += d.tax_amount + + for key, value in iteritems(inter_state_supply_tax_mapping): if d.place_of_supply: + osup_det = self.report_dict["sup_details"]["osup_det"] + osup_det["txval"] = flt(osup_det["txval"] + value['taxable_value'], 2) + osup_det["iamt"] = flt(osup_det["iamt"] + value['iamt'], 2) + osup_det["camt"] = flt(osup_det["camt"] + value['camt'], 2) + osup_det["samt"] = flt(osup_det["samt"] + value['samt'], 2) + osup_det["csamt"] = flt(osup_det["csamt"] + value['csamt'], 2) + if state_number != d.place_of_supply.split("-")[0]: - inter_state_supply_details[d.gst_category].append({ + inter_state_supply_details.setdefault((d.gst_category, d.place_of_supply), { + "txval": 0.0, "pos": d.place_of_supply.split("-")[0], - "txval": flt(d.total, 2), - "iamt": flt(inter_state_supply_tax_mapping.get(d.place_of_supply), 2) + "iamt": 0.0 }) - else: - osup_det = self.report_dict["sup_details"]["osup_det"] - osup_det["txval"] = flt(osup_det["txval"] + d.total, 2) - osup_det["camt"] = flt(osup_det["camt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2) - osup_det["samt"] = flt(osup_det["samt"] + inter_state_supply_tax_mapping.get(d.place_of_supply)/2, 2) + + inter_state_supply_details[(d.gst_category, d.place_of_supply)]['txval'] += value['taxable_value'] + inter_state_supply_details[(d.gst_category, d.place_of_supply)]['iamt'] += value['iamt'] return inter_state_supply_details diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py index 05ffa87f144..fe7e0c807c5 100644 --- a/erpnext/regional/india/utils.py +++ b/erpnext/regional/india/utils.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals import frappe, re, json from frappe import _ -from frappe.utils import cstr, flt, date_diff, nowdate +from frappe.utils import cstr, flt, date_diff, nowdate, round_based_on_smallest_currency_fraction, money_in_words from erpnext.regional.india import states, state_numbers from erpnext.controllers.taxes_and_totals import get_itemised_tax, get_itemised_taxable_amount from erpnext.controllers.accounts_controller import get_taxes_and_charges @@ -458,19 +458,23 @@ def generate_ewb_json(dt, dn): @frappe.whitelist() def download_ewb_json(): - data = frappe._dict(frappe.local.form_dict) - - frappe.local.response.filecontent = json.dumps(data['data'], indent=4, sort_keys=True) + data = json.loads(frappe.local.form_dict.data) + frappe.local.response.filecontent = json.dumps(data, indent=4, sort_keys=True) frappe.local.response.type = 'download' - billList = json.loads(data['data'])['billLists'] + filename_prefix = 'Bulk' + docname = frappe.local.form_dict.docname + if docname: + if docname.startswith('['): + docname = json.loads(docname) + if len(docname) == 1: + docname = docname[0] - if len(billList) > 1: - doc_name = 'Bulk' - else: - doc_name = data['docname'] + if not isinstance(docname, list): + # removes characters not allowed in a filename (https://stackoverflow.com/a/38766141/4767738) + filename_prefix = re.sub('[^\w_.)( -]', '', docname) - frappe.local.response.filename = '{0}_e-WayBill_Data_{1}.json'.format(doc_name, frappe.utils.random_string(5)) + frappe.local.response.filename = '{0}_e-WayBill_Data_{1}.json'.format(filename_prefix, frappe.utils.random_string(5)) @frappe.whitelist() def get_gstins_for_company(company): @@ -644,6 +648,7 @@ def validate_state_code(state_code, address): else: return int(state_code) +@frappe.whitelist() def get_gst_accounts(company, account_wise=False): gst_accounts = frappe._dict() gst_settings_accounts = frappe.get_all("GST Account", @@ -662,14 +667,55 @@ def get_gst_accounts(company, account_wise=False): return gst_accounts -def make_reverse_charge_entries(doc, method): +def update_grand_total_for_rcm(doc, method): + country = frappe.get_cached_value('Company', doc.company, 'country') + + if country != 'India': + return + + if doc.reverse_charge == 'Y': + gst_accounts = get_gst_accounts(doc.company) + gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \ + + gst_accounts.get('igst_account') + + gst_tax = 0 + for tax in doc.get('taxes'): + if tax.category not in ("Total", "Valuation and Total"): + continue + + if flt(tax.base_tax_amount_after_discount_amount) and tax.account_head in gst_account_list: + gst_tax += tax.base_tax_amount_after_discount_amount + + doc.taxes_and_charges_added -= gst_tax + doc.total_taxes_and_charges -= gst_tax + + update_totals(gst_tax, doc) + +def update_totals(gst_tax, doc): + doc.grand_total -= gst_tax + + if doc.meta.get_field("rounded_total"): + if doc.is_rounded_total_disabled(): + doc.outstanding_amount = doc.grand_total + else: + doc.rounded_total = round_based_on_smallest_currency_fraction(doc.grand_total, + doc.currency, doc.precision("rounded_total")) + + doc.rounding_adjustment += flt(doc.rounded_total - doc.grand_total, + doc.precision("rounding_adjustment")) + + doc.outstanding_amount = doc.rounded_total or doc.grand_total + + doc.in_words = money_in_words(doc.grand_total, doc.currency) + doc.set_payment_schedule() + +def make_regional_gl_entries(gl_entries, doc): country = frappe.get_cached_value('Company', doc.company, 'country') if country != 'India': return if doc.reverse_charge == 'Y': - gl_entries = [] gst_accounts = get_gst_accounts(doc.company) gst_account_list = gst_accounts.get('cgst_account') + gst_accounts.get('sgst_account') \ + gst_accounts.get('igst_account') @@ -694,19 +740,4 @@ def make_reverse_charge_entries(doc, method): }, account_currency, item=tax) ) - gl_entries.append(doc.get_gl_dict( - { - "account": doc.credit_to if doc.doctype == 'Purchase Invoice' else doc.debit_to, - "cost_center": doc.cost_center, - "posting_date": doc.posting_date, - "party_type": 'Supplier', - "party": doc.supplier, - "against": tax.account_head, - "debit": tax.base_tax_amount_after_discount_amount, - "debit_in_account_currency": tax.base_tax_amount_after_discount_amount \ - if account_currency==doc.company_currency \ - else tax.tax_amount_after_discount_amount - }, account_currency, item=doc) - ) - - make_gl_entries(gl_entries) \ No newline at end of file + return gl_entries \ No newline at end of file diff --git a/erpnext/regional/report/datev/datev.js b/erpnext/regional/report/datev/datev.js index d8638ab05de..55f12cf3738 100644 --- a/erpnext/regional/report/datev/datev.js +++ b/erpnext/regional/report/datev/datev.js @@ -30,7 +30,7 @@ frappe.query_reports["DATEV"] = { } ], onload: function(query_report) { - query_report.page.add_inner_button("Download DATEV Export", () => { + query_report.page.add_menu_item(__("Download DATEV File"), () => { const filters = JSON.stringify(query_report.get_values()); window.open(`/api/method/erpnext.regional.report.datev.datev.download_datev_csv?filters=${filters}`); }); diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py index a8e40cc4930..7fec94e740c 100644 --- a/erpnext/regional/report/datev/datev.py +++ b/erpnext/regional/report/datev/datev.py @@ -8,17 +8,18 @@ Provide a report and downloadable CSV according to the German DATEV format. all required columns. Used to import the data into the DATEV Software. """ from __future__ import unicode_literals + import datetime import json -import zlib import zipfile import six +import frappe +import pandas as pd + +from frappe import _ from csv import QUOTE_NONNUMERIC from six import BytesIO from six import string_types -import frappe -from frappe import _ -import pandas as pd from .datev_constants import DataCategory from .datev_constants import Transactions from .datev_constants import DebtorsCreditors @@ -130,8 +131,10 @@ def get_customers(filters): SELECT acc.account_number as 'Konto', - cus.customer_name as 'Name (Adressatentyp Unternehmen)', - case cus.customer_type when 'Individual' then 1 when 'Company' then 2 else 0 end as 'Adressatentyp', + CASE cus.customer_type WHEN 'Company' THEN cus.customer_name ELSE null END as 'Name (Adressatentyp Unternehmen)', + CASE cus.customer_type WHEN 'Individual' THEN con.last_name ELSE null END as 'Name (Adressatentyp natürl. Person)', + CASE cus.customer_type WHEN 'Individual' THEN con.first_name ELSE null END as 'Vorname (Adressatentyp natürl. Person)', + CASE cus.customer_type WHEN 'Individual' THEN '1' WHEN 'Company' THEN '2' ELSE '0' end as 'Adressatentyp', adr.address_line1 as 'Straße', adr.pincode as 'Postleitzahl', adr.city as 'Ort', @@ -140,8 +143,7 @@ def get_customers(filters): con.email_id as 'E-Mail', coalesce(con.mobile_no, con.phone) as 'Telefon', cus.website as 'Internet', - cus.tax_id as 'Steuernummer', - ccl.credit_limit as 'Kreditlimit (Debitor)' + cus.tax_id as 'Steuernummer' FROM `tabParty Account` par @@ -160,10 +162,6 @@ def get_customers(filters): left join `tabContact` con on con.name = cus.customer_primary_contact - left join `tabCustomer Credit Limit` ccl - on ccl.parent = cus.name - and ccl.company = par.company - WHERE par.company = %(company)s AND par.parenttype = 'Customer'""", filters, as_dict=1) @@ -179,8 +177,10 @@ def get_suppliers(filters): SELECT acc.account_number as 'Konto', - sup.supplier_name as 'Name (Adressatentyp Unternehmen)', - case sup.supplier_type when 'Individual' then '1' when 'Company' then '2' else '0' end as 'Adressatentyp', + CASE sup.supplier_type WHEN 'Company' THEN sup.supplier_name ELSE null END as 'Name (Adressatentyp Unternehmen)', + CASE sup.supplier_type WHEN 'Individual' THEN con.last_name ELSE null END as 'Name (Adressatentyp natürl. Person)', + CASE sup.supplier_type WHEN 'Individual' THEN con.first_name ELSE null END as 'Vorname (Adressatentyp natürl. Person)', + CASE sup.supplier_type WHEN 'Individual' THEN '1' WHEN 'Company' THEN '2' ELSE '0' end as 'Adressatentyp', adr.address_line1 as 'Straße', adr.pincode as 'Postleitzahl', adr.city as 'Ort', @@ -226,9 +226,18 @@ def get_suppliers(filters): def get_account_names(filters): - return frappe.get_list("Account", - fields=["account_number as Konto", "name as Kontenbeschriftung"], - filters={"company": filters.get("company"), "is_group": "0"}) + return frappe.db.sql(""" + SELECT + + account_number as 'Konto', + LEFT(account_name, 40) as 'Kontenbeschriftung', + 'de-DE' as 'Sprach-ID' + + FROM `tabAccount` + WHERE company = %(company)s + AND is_group = 0 + AND account_number != '' + """, filters, as_dict=1) def get_datev_csv(data, filters, csv_class): @@ -287,9 +296,7 @@ def get_datev_csv(data, filters, csv_class): def get_header(filters, csv_class): - coa = frappe.get_value("Company", filters.get("company"), "chart_of_accounts") - description = filters.get("voucher_type", csv_class.FORMAT_NAME) - coa_used = "04" if "SKR04" in coa else ("03" if "SKR03" in coa else "") + description = filters.get('voucher_type', csv_class.FORMAT_NAME) header = [ # DATEV format @@ -316,19 +323,19 @@ def get_header(filters, csv_class): # J = Imported by -- stays empty '', # K = Tax consultant number (Beraternummer) - frappe.get_value("DATEV Settings", filters.get("company"), "consultant_number"), + filters.get('consultant_number', '0000000'), # L = Tax client number (Mandantennummer) - frappe.get_value("DATEV Settings", filters.get("company"), "client_number"), + filters.get('client_number', '00000'), # M = Start of the fiscal year (Wirtschaftsjahresbeginn) frappe.utils.formatdate(frappe.defaults.get_user_default("year_start_date"), "yyyyMMdd"), # N = Length of account numbers (Sachkontenlänge) - '4', + '%d' % filters.get('acc_len', 4), # O = Transaction batch start date (YYYYMMDD) - frappe.utils.formatdate(filters.get('from_date'), "yyyyMMdd"), + frappe.utils.formatdate(filters.get('from_date'), "yyyyMMdd") if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '', # P = Transaction batch end date (YYYYMMDD) - frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd"), + frappe.utils.formatdate(filters.get('to_date'), "yyyyMMdd") if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '', # Q = Description (for example, "Sales Invoice") Max. 30 chars - '"{}"'.format(_(description)), + '"{}"'.format(_(description)) if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '', # R = Diktatkürzel '', # S = Buchungstyp @@ -343,12 +350,12 @@ def get_header(filters, csv_class): # 40 = Kalkulatorik # 11 = Reserviert # 12 = Reserviert - '0', + '0' if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '', # U = Festschreibung # TODO: Filter by Accounting Period. In export for closed Accounting Period, this will be "1" '0', # V = Default currency, for example, "EUR" - '"%s"' % frappe.get_value("Company", filters.get("company"), "default_currency"), + '"%s"' % filters.get('default_currency', 'EUR') if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '', # reserviert '', # Derivatskennzeichen @@ -358,7 +365,7 @@ def get_header(filters, csv_class): # reserviert '', # SKR - '"%s"' % coa_used, + '"%s"' % filters.get('skr', '04'), # Branchen-Lösungs-ID '', # reserviert @@ -389,6 +396,18 @@ def download_datev_csv(filters=None): validate(filters) + # set chart of accounts used + coa = frappe.get_value('Company', filters.get('company'), 'chart_of_accounts') + filters['skr'] = '04' if 'SKR04' in coa else ('03' if 'SKR03' in coa else '') + + # set account number length + account_numbers = frappe.get_list('Account', fields=['account_number'], filters={'is_group': 0, 'account_number': ('!=', '')}) + filters['acc_len'] = max([len(a.account_number) for a in account_numbers]) + + filters['consultant_number'] = frappe.get_value('DATEV Settings', filters.get('company'), 'consultant_number') + filters['client_number'] = frappe.get_value('DATEV Settings', filters.get('company'), 'client_number') + filters['default_currency'] = frappe.get_value('Company', filters.get('company'), 'default_currency') + # This is where my zip will be written zip_buffer = BytesIO() # This is my zip file diff --git a/erpnext/regional/report/datev/datev_constants.py b/erpnext/regional/report/datev/datev_constants.py index a059ed365a9..e0637030051 100644 --- a/erpnext/regional/report/datev/datev_constants.py +++ b/erpnext/regional/report/datev/datev_constants.py @@ -465,60 +465,71 @@ QUERY_REPORT_COLUMNS = [ "label": "Umsatz (ohne Soll/Haben-Kz)", "fieldname": "Umsatz (ohne Soll/Haben-Kz)", "fieldtype": "Currency", + "width": 100 }, { "label": "Soll/Haben-Kennzeichen", "fieldname": "Soll/Haben-Kennzeichen", "fieldtype": "Data", + "width": 100 }, { "label": "Konto", "fieldname": "Konto", "fieldtype": "Data", + "width": 100 }, { "label": "Gegenkonto (ohne BU-Schlüssel)", "fieldname": "Gegenkonto (ohne BU-Schlüssel)", "fieldtype": "Data", + "width": 100 }, { "label": "Belegdatum", "fieldname": "Belegdatum", "fieldtype": "Date", + "width": 100 }, { "label": "Belegfeld 1", "fieldname": "Belegfeld 1", "fieldtype": "Data", + "width": 150 }, { "label": "Buchungstext", "fieldname": "Buchungstext", "fieldtype": "Text", + "width": 300 }, { "label": "Beleginfo - Art 1", "fieldname": "Beleginfo - Art 1", "fieldtype": "Link", - "options": "DocType" + "options": "DocType", + "width": 100 }, { "label": "Beleginfo - Inhalt 1", "fieldname": "Beleginfo - Inhalt 1", "fieldtype": "Dynamic Link", - "options": "Beleginfo - Art 1" + "options": "Beleginfo - Art 1", + "width": 150 }, { "label": "Beleginfo - Art 2", "fieldname": "Beleginfo - Art 2", "fieldtype": "Link", - "options": "DocType" + "options": "DocType", + "width": 100 }, { "label": "Beleginfo - Inhalt 2", "fieldname": "Beleginfo - Inhalt 2", "fieldtype": "Dynamic Link", - "options": "Beleginfo - Art 2" + "options": "Beleginfo - Art 2", + "width": 150 } ] diff --git a/erpnext/regional/report/datev/test_datev.py b/erpnext/regional/report/datev/test_datev.py index 3cc65fe9d3a..eed62a8690f 100644 --- a/erpnext/regional/report/datev/test_datev.py +++ b/erpnext/regional/report/datev/test_datev.py @@ -90,7 +90,7 @@ def make_customer_with_account(customer_name, company): if not frappe.db.exists("Customer", customer_name): customer = frappe.get_doc({ - "doctype": "Customer", + "doctype": "Customer", "customer_name": customer_name, "customer_type": "Company", "accounts": [{ @@ -155,17 +155,17 @@ class TestDatev(TestCase): setup_fiscal_year() warehouse = frappe.db.get_value("Item Default", { - "parent": item.name, + "parent": item.name, "company": self.company.name }, "default_warehouse") income_account = frappe.db.get_value("Account", { - "account_number": "4200", + "account_number": "4200", "company": self.company.name }, "name") tax_account = frappe.db.get_value("Account", { - "account_number": "3806", + "account_number": "3806", "company": self.company.name }, "name") @@ -186,9 +186,12 @@ class TestDatev(TestCase): "charge_type": "On Net Total", "account_head": tax_account, "description": "Umsatzsteuer 19 %", - "rate": 19 + "rate": 19, + "cost_center": self.company.cost_center }) + si.cost_center = self.company.cost_center + si.save() si.submit() @@ -196,7 +199,7 @@ class TestDatev(TestCase): def is_subset(get_data, allowed_keys): """ Validate that the dict contains only allowed keys. - + Params: get_data -- Function that returns a list of dicts. allowed_keys -- List of allowed keys diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py index 43b1ea83eb9..8885b88c2a4 100644 --- a/erpnext/regional/report/gstr_1/gstr_1.py +++ b/erpnext/regional/report/gstr_1/gstr_1.py @@ -118,7 +118,7 @@ class Gstr1Report(object): row.append(invoice_details.get(fieldname)) taxable_value = 0 - if invoice in self.cgst_igst_invoices: + if invoice in self.cgst_sgst_invoices: division_factor = 2 else: division_factor = 1 @@ -129,6 +129,8 @@ class Gstr1Report(object): taxable_value += abs(net_amount) elif not self.item_tax_rate.get(invoice): taxable_value += abs(net_amount) + elif tax_rate: + taxable_value += abs(net_amount) row += [tax_rate or 0, taxable_value] @@ -227,7 +229,7 @@ class Gstr1Report(object): self.items_based_on_tax_rate = {} self.invoice_cess = frappe._dict() - self.cgst_igst_invoices = [] + self.cgst_sgst_invoices = [] unidentified_gst_accounts = [] for parent, account, item_wise_tax_detail, tax_amount in self.tax_details: @@ -251,8 +253,8 @@ class Gstr1Report(object): tax_rate = tax_amounts[0] if cgst_or_sgst: tax_rate *= 2 - if parent not in self.cgst_igst_invoices: - self.cgst_igst_invoices.append(parent) + if parent not in self.cgst_sgst_invoices: + self.cgst_sgst_invoices.append(parent) rate_based_dict = self.items_based_on_tax_rate\ .setdefault(parent, {}).setdefault(tax_rate, []) diff --git a/erpnext/regional/report/gstr_2/gstr_2.py b/erpnext/regional/report/gstr_2/gstr_2.py index f326fe07cac..f899349ccc0 100644 --- a/erpnext/regional/report/gstr_2/gstr_2.py +++ b/erpnext/regional/report/gstr_2/gstr_2.py @@ -44,30 +44,30 @@ class Gstr2Report(Gstr1Report): for inv, items_based_on_rate in self.items_based_on_tax_rate.items(): invoice_details = self.invoices.get(inv) for rate, items in items_based_on_rate.items(): - if inv not in self.igst_invoices: - rate = rate / 2 - row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) - tax_amount = taxable_value * rate / 100 - row += [0, tax_amount, tax_amount] - else: - row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) - tax_amount = taxable_value * rate / 100 - row += [tax_amount, 0, 0] + if rate: + if inv not in self.igst_invoices: + rate = rate / 2 + row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) + tax_amount = taxable_value * rate / 100 + row += [0, tax_amount, tax_amount] + else: + row, taxable_value = self.get_row_data_for_invoice(inv, invoice_details, rate, items) + tax_amount = taxable_value * rate / 100 + row += [tax_amount, 0, 0] + row += [ + self.invoice_cess.get(inv), + invoice_details.get('eligibility_for_itc'), + invoice_details.get('itc_integrated_tax'), + invoice_details.get('itc_central_tax'), + invoice_details.get('itc_state_tax'), + invoice_details.get('itc_cess_amount') + ] + if self.filters.get("type_of_business") == "CDNR": + row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N") + row.append("C" if invoice_details.return_against else "R") - row += [ - self.invoice_cess.get(inv), - invoice_details.get('eligibility_for_itc'), - invoice_details.get('itc_integrated_tax'), - invoice_details.get('itc_central_tax'), - invoice_details.get('itc_state_tax'), - invoice_details.get('itc_cess_amount') - ] - if self.filters.get("type_of_business") == "CDNR": - row.append("Y" if invoice_details.posting_date <= date(2017, 7, 1) else "N") - row.append("C" if invoice_details.return_against else "R") - - self.data.append(row) + self.data.append(row) def get_igst_invoices(self): self.igst_invoices = [] @@ -86,7 +86,7 @@ class Gstr2Report(Gstr1Report): conditions += opts[1] if self.filters.get("type_of_business") == "B2B": - conditions += "and ifnull(gst_category, '') != 'Overseas' and is_return != 1 " + conditions += "and ifnull(gst_category, '') in ('Registered Regular', 'Deemed Export', 'SEZ') and is_return != 1 " elif self.filters.get("type_of_business") == "CDNR": conditions += """ and is_return = 1 """ diff --git a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py index 900fe963b4b..acde68a942b 100644 --- a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py +++ b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py @@ -7,8 +7,8 @@ from frappe import _ from erpnext.regional.report.provident_fund_deductions.provident_fund_deductions import get_conditions def execute(filters=None): - columns = get_columns(filters) data = get_data(filters) + columns = get_columns(filters) if len(data) else [] return columns, data @@ -45,6 +45,9 @@ def get_data(filters): component_type_dict = frappe._dict(frappe.db.sql(""" select name, component_type from `tabSalary Component` where component_type = 'Professional Tax' """)) + if not len(component_type_dict): + return [] + conditions = get_conditions(filters) entry = frappe.db.sql(""" select sal.employee, sal.employee_name, ded.salary_component, ded.amount diff --git a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py index 9f58957fed8..597072c53a1 100644 --- a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py +++ b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py @@ -3,11 +3,12 @@ from __future__ import unicode_literals import frappe +from frappe.utils import getdate from frappe import _ def execute(filters=None): - columns = get_columns(filters) data = get_data(filters) + columns = get_columns(filters) if len(data) else [] return columns, data @@ -71,10 +72,13 @@ def get_conditions(filters): conditions.append("sal.branch = '%s' " % (filters["branch"]) ) if filters.get("company"): - conditions.append("sal.company = '%s' " % (filters["company"]) ) + conditions.append("sal.company = '%s' " % (filters["company"])) - if filters.get("period"): - conditions.append("month(sal.start_date) = '%s' " % (filters["period"])) + if filters.get("month"): + conditions.append("month(sal.start_date) = '%s' " % (filters["month"])) + + if filters.get("year"): + conditions.append("year(start_date) = '%s' " % (filters["year"])) if filters.get("mode_of_payment"): conditions.append("sal.mode_of_payment = '%s' " % (filters["mode_of_payment"])) @@ -97,7 +101,7 @@ def prepare_data(entry,component_type_dict): "employee": d.employee, "employee_name": d.employee_name, "pf_account": employee_account_dict.get(d.employee), - "component_type": d.amount + component_type: d.amount }) return data_list @@ -114,6 +118,9 @@ def get_data(filters): component_type_dict = frappe._dict(frappe.db.sql(""" select name, component_type from `tabSalary Component` where component_type in ('Provident Fund', 'Additional Provident Fund', 'Provident Fund Loan')""")) + if not len(component_type_dict): + return [] + entry = frappe.db.sql(""" select sal.name, sal.employee, sal.employee_name, ded.salary_component, ded.amount from `tabSalary Slip` sal, `tabSalary Detail` ded where sal.name = ded.parent @@ -150,4 +157,12 @@ def get_data(filters): data.append(employee) - return data \ No newline at end of file + return data + +@frappe.whitelist() +def get_years(): + year_list = frappe.db.sql_list("""select distinct YEAR(end_date) from `tabSalary Slip` ORDER BY YEAR(end_date) DESC""") + if not year_list: + year_list = [getdate().year] + + return "\n".join(str(year) for year in year_list) \ No newline at end of file diff --git a/erpnext/regional/united_arab_emirates/utils.py b/erpnext/regional/united_arab_emirates/utils.py index 772bbf5914b..a0425f6b1c2 100644 --- a/erpnext/regional/united_arab_emirates/utils.py +++ b/erpnext/regional/united_arab_emirates/utils.py @@ -11,14 +11,17 @@ def update_itemised_tax_data(doc): for row in doc.items: tax_rate = 0.0 - item_tax_rate = frappe.parse_json(row.item_tax_rate) + item_tax_rate = 0.0 + + if row.item_tax_rate: + item_tax_rate = frappe.parse_json(row.item_tax_rate) # First check if tax rate is present # If not then look up in item_wise_tax_detail if item_tax_rate: for account, rate in iteritems(item_tax_rate): tax_rate += rate - elif itemised_tax.get(row.item_code): + elif row.item_code and itemised_tax.get(row.item_code): tax_rate = sum([tax.get('tax_rate', 0) for d, tax in itemised_tax.get(row.item_code).items()]) row.tax_rate = flt(tax_rate, row.precision("tax_rate")) diff --git a/erpnext/regional/united_states/setup.py b/erpnext/regional/united_states/setup.py index cae28bee8bc..2b0ecafebc5 100644 --- a/erpnext/regional/united_states/setup.py +++ b/erpnext/regional/united_states/setup.py @@ -14,6 +14,22 @@ def make_custom_fields(update=True): 'Supplier': [ dict(fieldname='irs_1099', fieldtype='Check', insert_after='tax_id', label='Is IRS 1099 reporting required for supplier?') + ], + 'Sales Order': [ + dict(fieldname='exempt_from_sales_tax', fieldtype='Check', insert_after='taxes_and_charges', + label='Is customer exempted from sales tax?') + ], + 'Sales Invoice': [ + dict(fieldname='exempt_from_sales_tax', fieldtype='Check', insert_after='taxes_section', + label='Is customer exempted from sales tax?') + ], + 'Customer': [ + dict(fieldname='exempt_from_sales_tax', fieldtype='Check', insert_after='represents_company', + label='Is customer exempted from sales tax?') + ], + 'Quotation': [ + dict(fieldname='exempt_from_sales_tax', fieldtype='Check', insert_after='taxes_and_charges', + label='Is customer exempted from sales tax?') ] } create_custom_fields(custom_fields, update=update) diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py index a748f9a0075..357deaac007 100644 --- a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py +++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py @@ -65,6 +65,7 @@ def make_invoice(table, customer, mode_of_payment): return invoice.name +@frappe.whitelist() def item_query_restaurant(doctype='Item', txt='', searchfield='name', start=0, page_len=20, filters=None, as_dict=False): '''Return items that are selected in active menu of the restaurant''' restaurant, menu = get_restaurant_and_menu_name(filters['table']) @@ -84,4 +85,4 @@ def get_restaurant_and_menu_name(table): if not menu: frappe.throw(_('Please set an active menu for Restaurant {0}').format(restaurant)) - return restaurant, menu \ No newline at end of file + return restaurant, menu diff --git a/erpnext/selling/desk_page/selling/selling.json b/erpnext/selling/desk_page/selling/selling.json index 60b15326e83..225238233a3 100644 --- a/erpnext/selling/desk_page/selling/selling.json +++ b/erpnext/selling/desk_page/selling/selling.json @@ -23,7 +23,7 @@ { "hidden": 0, "label": "Other Reports", - "links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Customer Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"route_options\": {\n \"party_type\": \"Customer\"\n },\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Available Stock for Packing Items\",\n \"name\": \"Available Stock for Packing Items\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Pending SO Items For Purchase Request\",\n \"name\": \"Pending SO Items For Purchase Request\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customers Without Any Sales Transactions\",\n \"name\": \"Customers Without Any Sales Transactions\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n }\n]" + "links": "[\n {\n \"dependencies\": [\n \"Lead\"\n ],\n \"doctype\": \"Lead\",\n \"is_query_report\": true,\n \"label\": \"Lead Details\",\n \"name\": \"Lead Details\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Address\"\n ],\n \"doctype\": \"Address\",\n \"is_query_report\": true,\n \"label\": \"Customer Addresses And Contacts\",\n \"name\": \"Address And Contacts\",\n \"route_options\": {\n \"party_type\": \"Customer\"\n },\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Item\"\n ],\n \"doctype\": \"Item\",\n \"is_query_report\": true,\n \"label\": \"Available Stock for Packing Items\",\n \"name\": \"Available Stock for Packing Items\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Order\"\n ],\n \"doctype\": \"Sales Order\",\n \"is_query_report\": true,\n \"label\": \"Pending SO Items For Purchase Request\",\n \"name\": \"Pending SO Items For Purchase Request\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Delivery Note\"\n ],\n \"doctype\": \"Delivery Note\",\n \"is_query_report\": true,\n \"label\": \"Delivery Note Trends\",\n \"name\": \"Delivery Note Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Sales Invoice\"\n ],\n \"doctype\": \"Sales Invoice\",\n \"is_query_report\": true,\n \"label\": \"Sales Invoice Trends\",\n \"name\": \"Sales Invoice Trends\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customer Credit Balance\",\n \"name\": \"Customer Credit Balance\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Customers Without Any Sales Transactions\",\n \"name\": \"Customers Without Any Sales Transactions\",\n \"type\": \"report\"\n },\n {\n \"dependencies\": [\n \"Customer\"\n ],\n \"doctype\": \"Customer\",\n \"is_query_report\": true,\n \"label\": \"Sales Partners Commission\",\n \"name\": \"Sales Partners Commission\",\n \"type\": \"report\"\n }\n]" } ], "category": "Modules", @@ -44,7 +44,7 @@ "idx": 0, "is_standard": 1, "label": "Selling", - "modified": "2020-06-19 13:23:24.861706", + "modified": "2020-06-29 19:26:35.139097", "modified_by": "Administrator", "module": "Selling", "name": "Selling", diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index d70c64fce49..e614acdb823 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -342,11 +342,10 @@ def get_loyalty_programs(doc): @frappe.whitelist() def get_customer_list(doctype, txt, searchfield, start, page_len, filters=None): from erpnext.controllers.queries import get_fields + fields = ["name", "customer_name", "customer_group", "territory"] if frappe.db.get_default("cust_master_name") == "Customer Name": fields = ["name", "customer_group", "territory"] - else: - fields = ["name", "customer_name", "customer_group", "territory"] fields = get_fields("Customer", fields) @@ -542,6 +541,7 @@ def make_address(args, is_primary_address=1): return address +@frappe.whitelist() def get_customer_primary_contact(doctype, txt, searchfield, start, page_len, filters): customer = filters.get('customer') return frappe.db.sql(""" @@ -552,4 +552,4 @@ def get_customer_primary_contact(doctype, txt, searchfield, start, page_len, fil """, { 'customer': customer, 'txt': '%%%s%%' % txt - }) + }) \ No newline at end of file diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.py b/erpnext/selling/doctype/product_bundle/product_bundle.py index c8a71677f93..0c85a1b53cb 100644 --- a/erpnext/selling/doctype/product_bundle/product_bundle.py +++ b/erpnext/selling/doctype/product_bundle/product_bundle.py @@ -22,12 +22,13 @@ class ProductBundle(Document): """Validates, main Item is not a stock item""" if frappe.db.get_value("Item", self.new_item_code, "is_stock_item"): frappe.throw(_("Parent Item {0} must not be a Stock Item").format(self.new_item_code)) - + def validate_child_items(self): for item in self.items: if frappe.db.exists("Product Bundle", item.item_code): - frappe.throw(_("Child Item should not be a Product Bundle. Please remove item `{0}` and save").format(item.item_code)) - + frappe.throw(_("Row #{0}: Child Item should not be a Product Bundle. Please remove Item {1} and Save").format(item.idx, frappe.bold(item.item_code))) + +@frappe.whitelist() def get_new_item_code(doctype, txt, searchfield, start, page_len, filters): from erpnext.controllers.queries import get_match_cond diff --git a/erpnext/selling/doctype/quotation/quotation_list.js b/erpnext/selling/doctype/quotation/quotation_list.js index 802c0ba641d..f425acf180a 100644 --- a/erpnext/selling/doctype/quotation/quotation_list.js +++ b/erpnext/selling/doctype/quotation/quotation_list.js @@ -3,13 +3,15 @@ frappe.listview_settings['Quotation'] = { "company", "currency", 'valid_till'], onload: function(listview) { - listview.page.fields_dict.quotation_to.get_query = function() { - return { - "filters": { - "name": ["in", ["Customer", "Lead"]], - } + if (listview.page.fields_dict.quotation_to) { + listview.page.fields_dict.quotation_to.get_query = function() { + return { + "filters": { + "name": ["in", ["Customer", "Lead"]], + } + }; }; - }; + } }, get_indicator: function(doc) { diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py index ee6b429ccae..b4c3d79f31c 100644 --- a/erpnext/selling/doctype/quotation/test_quotation.py +++ b/erpnext/selling/doctype/quotation/test_quotation.py @@ -280,5 +280,3 @@ def make_quotation(**args): qo.submit() return qo - - diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index b57c4f30981..cd4e1d07926 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -143,11 +143,15 @@ { "fieldname": "customer_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "options": "fa fa-user" }, { "fieldname": "column_break0", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Column Break", "width": "50%" }, @@ -157,6 +161,8 @@ "fieldname": "title", "fieldtype": "Data", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Title", "no_copy": 1, "print_hide": 1 @@ -164,6 +170,8 @@ { "fieldname": "naming_series", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "label": "Series", "no_copy": 1, "oldfieldname": "naming_series", @@ -177,6 +185,8 @@ "bold": 1, "fieldname": "customer", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "in_global_search": 1, "in_standard_filter": 1, "label": "Customer", @@ -192,6 +202,8 @@ "fetch_from": "customer.customer_name", "fieldname": "customer_name", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "in_global_search": 1, "label": "Customer Name", "read_only": 1 @@ -200,6 +212,8 @@ "default": "Sales", "fieldname": "order_type", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "label": "Order Type", "oldfieldname": "order_type", "oldfieldtype": "Select", @@ -210,6 +224,8 @@ { "fieldname": "column_break1", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Column Break", "width": "50%" }, @@ -217,6 +233,8 @@ "fieldname": "amended_from", "fieldtype": "Link", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "ignore_user_permissions": 1, "label": "Amended From", "no_copy": 1, @@ -230,6 +248,8 @@ { "fieldname": "company", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "in_standard_filter": 1, "label": "Company", "oldfieldname": "company", @@ -244,6 +264,8 @@ "default": "Today", "fieldname": "transaction_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "in_standard_filter": 1, "label": "Date", "no_copy": 1, @@ -258,6 +280,8 @@ "depends_on": "eval:!doc.skip_delivery_note", "fieldname": "delivery_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "in_list_view": 1, "label": "Delivery Date", "no_copy": 1 @@ -266,6 +290,8 @@ "allow_on_submit": 1, "fieldname": "po_no", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "Customer's Purchase Order", "oldfieldname": "po_no", "oldfieldtype": "Data", @@ -276,6 +302,8 @@ "depends_on": "eval:doc.po_no", "fieldname": "po_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "label": "Customer's Purchase Order Date", "oldfieldname": "po_date", "oldfieldtype": "Date", @@ -285,6 +313,8 @@ "fetch_from": "customer.tax_id", "fieldname": "tax_id", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "Tax Id", "read_only": 1, "width": "100px" @@ -294,6 +324,8 @@ "depends_on": "customer", "fieldname": "contact_info", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Address and Contact", "options": "fa fa-bullhorn" }, @@ -301,6 +333,8 @@ "allow_on_submit": 1, "fieldname": "customer_address", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Customer Address", "options": "Address", "print_hide": 1 @@ -309,12 +343,16 @@ "allow_on_submit": 1, "fieldname": "address_display", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Address", "read_only": 1 }, { "fieldname": "contact_person", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Contact Person", "options": "Contact", "print_hide": 1 @@ -322,6 +360,8 @@ { "fieldname": "contact_display", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "in_global_search": 1, "label": "Contact", "read_only": 1 @@ -329,6 +369,8 @@ { "fieldname": "contact_mobile", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Mobile No", "read_only": 1 }, @@ -336,6 +378,8 @@ "fieldname": "contact_email", "fieldtype": "Data", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Contact Email", "options": "Email", "print_hide": 1, @@ -344,24 +388,32 @@ { "fieldname": "company_address_display", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Company Address", "read_only": 1 }, { "fieldname": "company_address", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Company Address Name", "options": "Address" }, { "fieldname": "col_break46", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "width": "50%" }, { "allow_on_submit": 1, "fieldname": "shipping_address_name", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Shipping Address Name", "options": "Address", "print_hide": 1 @@ -370,6 +422,8 @@ "allow_on_submit": 1, "fieldname": "shipping_address", "fieldtype": "Small Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Shipping Address", "print_hide": 1, "read_only": 1 @@ -378,6 +432,8 @@ "fieldname": "customer_group", "fieldtype": "Link", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Customer Group", "options": "Customer Group", "print_hide": 1 @@ -385,6 +441,8 @@ { "fieldname": "territory", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Territory", "options": "Territory", "print_hide": 1 @@ -393,6 +451,8 @@ "collapsible": 1, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Currency and Price List", "options": "fa fa-tag", "print_hide": 1 @@ -400,6 +460,8 @@ { "fieldname": "currency", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Currency", "oldfieldname": "currency", "oldfieldtype": "Select", @@ -412,6 +474,8 @@ "description": "Rate at which customer's currency is converted to company's base currency", "fieldname": "conversion_rate", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Exchange Rate", "oldfieldname": "conversion_rate", "oldfieldtype": "Currency", @@ -423,11 +487,15 @@ { "fieldname": "column_break2", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "width": "50%" }, { "fieldname": "selling_price_list", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Price List", "oldfieldname": "price_list_name", "oldfieldtype": "Select", @@ -439,6 +507,8 @@ { "fieldname": "price_list_currency", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Price List Currency", "options": "Currency", "print_hide": 1, @@ -449,6 +519,8 @@ "description": "Rate at which Price list currency is converted to company's base currency", "fieldname": "plc_conversion_rate", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Price List Exchange Rate", "precision": "9", "print_hide": 1, @@ -458,6 +530,8 @@ "default": "0", "fieldname": "ignore_pricing_rule", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Ignore Pricing Rule", "no_copy": 1, "permlevel": 1, @@ -465,11 +539,15 @@ }, { "fieldname": "sec_warehouse", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "set_warehouse", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Set Source Warehouse", "options": "Warehouse", "print_hide": 1 @@ -477,18 +555,24 @@ { "fieldname": "items_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Section Break", "options": "fa fa-shopping-cart" }, { "fieldname": "scan_barcode", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "Scan Barcode" }, { "allow_bulk_edit": 1, "fieldname": "items", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Items", "oldfieldname": "sales_order_details", "oldfieldtype": "Table", @@ -498,32 +582,44 @@ { "fieldname": "pricing_rule_details", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Pricing Rules" }, { "fieldname": "pricing_rules", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Pricing Rule Detail", "options": "Pricing Rule Detail", "read_only": 1 }, { "fieldname": "section_break_31", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "column_break_33a", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "total_qty", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Quantity", "read_only": 1 }, { "fieldname": "base_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, @@ -532,6 +628,8 @@ { "fieldname": "base_net_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Net Total (Company Currency)", "oldfieldname": "net_total", "oldfieldtype": "Currency", @@ -542,11 +640,15 @@ }, { "fieldname": "column_break_33", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total", "options": "currency", "read_only": 1 @@ -554,6 +656,8 @@ { "fieldname": "net_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Net Total", "options": "currency", "print_hide": 1, @@ -562,6 +666,8 @@ { "fieldname": "total_net_weight", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Net Weight", "print_hide": 1, "read_only": 1 @@ -569,6 +675,8 @@ { "fieldname": "taxes_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Taxes and Charges", "oldfieldtype": "Section Break", "options": "fa fa-money" @@ -576,17 +684,23 @@ { "fieldname": "tax_category", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Tax Category", "options": "Tax Category", "print_hide": 1 }, { "fieldname": "column_break_38", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "shipping_rule", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Shipping Rule", "oldfieldtype": "Button", "options": "Shipping Rule", @@ -594,11 +708,15 @@ }, { "fieldname": "section_break_40", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "taxes_and_charges", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Taxes and Charges Template", "oldfieldname": "charge", "oldfieldtype": "Link", @@ -608,6 +726,8 @@ { "fieldname": "taxes", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Taxes and Charges", "oldfieldname": "other_charges", "oldfieldtype": "Table", @@ -617,11 +737,15 @@ "collapsible": 1, "fieldname": "sec_tax_breakup", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Tax Breakup" }, { "fieldname": "other_charges_calculation", "fieldtype": "Long Text", + "hide_days": 1, + "hide_seconds": 1, "label": "Taxes and Charges Calculation", "no_copy": 1, "oldfieldtype": "HTML", @@ -630,11 +754,15 @@ }, { "fieldname": "section_break_43", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "base_total_taxes_and_charges", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Taxes and Charges (Company Currency)", "oldfieldname": "other_charges_total", "oldfieldtype": "Currency", @@ -645,11 +773,15 @@ }, { "fieldname": "column_break_46", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "total_taxes_and_charges", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Taxes and Charges", "options": "currency", "print_hide": 1, @@ -659,6 +791,8 @@ "fieldname": "loyalty_points_redemption", "fieldtype": "Section Break", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Loyalty Points Redemption", "print_hide": 1 }, @@ -666,6 +800,8 @@ "fieldname": "loyalty_points", "fieldtype": "Int", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Loyalty Points", "read_only": 1 }, @@ -673,6 +809,8 @@ "fieldname": "loyalty_amount", "fieldtype": "Currency", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Loyalty Amount", "print_hide": 1, "read_only": 1 @@ -682,11 +820,15 @@ "collapsible_depends_on": "discount_amount", "fieldname": "section_break_48", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Additional Discount and Coupon Code" }, { "fieldname": "coupon_code", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Coupon Code", "options": "Coupon Code" }, @@ -694,6 +836,8 @@ "default": "Grand Total", "fieldname": "apply_discount_on", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "label": "Apply Additional Discount On", "options": "\nGrand Total\nNet Total", "print_hide": 1 @@ -701,6 +845,8 @@ { "fieldname": "base_discount_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Additional Discount Amount (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, @@ -708,17 +854,23 @@ }, { "fieldname": "column_break_50", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "additional_discount_percentage", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Additional Discount Percentage", "print_hide": 1 }, { "fieldname": "discount_amount", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Additional Discount Amount", "options": "currency", "print_hide": 1 @@ -726,6 +878,8 @@ { "fieldname": "totals", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Section Break", "options": "fa fa-money", "print_hide": 1 @@ -733,6 +887,8 @@ { "fieldname": "base_grand_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Grand Total (Company Currency)", "oldfieldname": "grand_total", "oldfieldtype": "Currency", @@ -744,6 +900,8 @@ { "fieldname": "base_rounding_adjustment", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Rounding Adjustment (Company Currency)", "no_copy": 1, "options": "Company:company:default_currency", @@ -753,6 +911,8 @@ { "fieldname": "base_rounded_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Rounded Total (Company Currency)", "oldfieldname": "rounded_total", "oldfieldtype": "Currency", @@ -765,6 +925,8 @@ "description": "In Words will be visible once you save the Sales Order.", "fieldname": "base_in_words", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "In Words (Company Currency)", "oldfieldname": "in_words", "oldfieldtype": "Data", @@ -775,6 +937,8 @@ { "fieldname": "column_break3", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Column Break", "print_hide": 1, "width": "50%" @@ -782,6 +946,8 @@ { "fieldname": "grand_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "in_list_view": 1, "label": "Grand Total", "oldfieldname": "grand_total_export", @@ -793,6 +959,8 @@ { "fieldname": "rounding_adjustment", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Rounding Adjustment", "no_copy": 1, "options": "currency", @@ -803,6 +971,8 @@ "bold": 1, "fieldname": "rounded_total", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Rounded Total", "oldfieldname": "rounded_total_export", "oldfieldtype": "Currency", @@ -813,6 +983,8 @@ { "fieldname": "in_words", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "In Words", "oldfieldname": "in_words_export", "oldfieldtype": "Data", @@ -823,6 +995,8 @@ { "fieldname": "advance_paid", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Advance Paid", "no_copy": 1, "options": "party_account_currency", @@ -834,6 +1008,8 @@ "collapsible_depends_on": "packed_items", "fieldname": "packing_list", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Packing List", "oldfieldtype": "Section Break", "options": "fa fa-suitcase", @@ -842,6 +1018,8 @@ { "fieldname": "packed_items", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Packed Items", "options": "Packed Item", "print_hide": 1, @@ -850,11 +1028,15 @@ { "fieldname": "payment_schedule_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Payment Terms" }, { "fieldname": "payment_terms_template", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Payment Terms Template", "options": "Payment Terms Template", "print_hide": 1 @@ -862,6 +1044,8 @@ { "fieldname": "payment_schedule", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Payment Schedule", "no_copy": 1, "options": "Payment Schedule", @@ -872,6 +1056,8 @@ "collapsible_depends_on": "terms", "fieldname": "terms_section_break", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Terms and Conditions", "oldfieldtype": "Section Break", "options": "fa fa-legal" @@ -879,6 +1065,8 @@ { "fieldname": "tc_name", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Terms", "oldfieldname": "tc_name", "oldfieldtype": "Link", @@ -888,6 +1076,8 @@ { "fieldname": "terms", "fieldtype": "Text Editor", + "hide_days": 1, + "hide_seconds": 1, "label": "Terms and Conditions Details", "oldfieldname": "terms", "oldfieldtype": "Text Editor" @@ -897,6 +1087,8 @@ "collapsible_depends_on": "project", "fieldname": "more_info", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "More Information", "oldfieldtype": "Section Break", "options": "fa fa-file-text", @@ -905,6 +1097,8 @@ { "fieldname": "inter_company_order_reference", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Inter Company Order Reference", "options": "Purchase Order" }, @@ -912,6 +1106,8 @@ "description": "Track this Sales Order against any Project", "fieldname": "project", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Project", "oldfieldname": "project", "oldfieldtype": "Link", @@ -921,6 +1117,8 @@ "fieldname": "party_account_currency", "fieldtype": "Link", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Party Account Currency", "no_copy": 1, "options": "Currency", @@ -929,11 +1127,15 @@ }, { "fieldname": "column_break_77", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "source", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Source", "oldfieldname": "source", "oldfieldtype": "Select", @@ -943,6 +1145,8 @@ { "fieldname": "campaign", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Campaign", "oldfieldname": "campaign", "oldfieldtype": "Link", @@ -953,11 +1157,15 @@ "collapsible": 1, "fieldname": "printing_details", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Print Settings" }, { "fieldname": "language", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "Print Language", "print_hide": 1, "read_only": 1 @@ -966,6 +1174,8 @@ "allow_on_submit": 1, "fieldname": "letter_head", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Letter Head", "oldfieldname": "letter_head", "oldfieldtype": "Select", @@ -975,6 +1185,8 @@ { "fieldname": "column_break4", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "oldfieldtype": "Column Break", "print_hide": 1, "width": "50%" @@ -983,6 +1195,8 @@ "allow_on_submit": 1, "fieldname": "select_print_heading", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Print Heading", "no_copy": 1, "oldfieldname": "select_print_heading", @@ -996,6 +1210,8 @@ "default": "0", "fieldname": "group_same_items", "fieldtype": "Check", + "hide_days": 1, + "hide_seconds": 1, "label": "Group same items", "print_hide": 1 }, @@ -1003,6 +1219,8 @@ "collapsible": 1, "fieldname": "section_break_78", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Billing and Delivery Status", "oldfieldtype": "Column Break", "print_hide": 1, @@ -1012,6 +1230,8 @@ "default": "Draft", "fieldname": "status", "fieldtype": "Select", + "hide_days": 1, + "hide_seconds": 1, "in_list_view": 1, "label": "Status", "no_copy": 1, @@ -1028,6 +1248,8 @@ "fieldname": "delivery_status", "fieldtype": "Select", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "in_standard_filter": 1, "label": "Delivery Status", "no_copy": 1, @@ -1039,6 +1261,8 @@ "description": "% of materials delivered against this Sales Order", "fieldname": "per_delivered", "fieldtype": "Percent", + "hide_days": 1, + "hide_seconds": 1, "in_list_view": 1, "label": "% Delivered", "no_copy": 1, @@ -1050,13 +1274,17 @@ }, { "fieldname": "column_break_81", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "depends_on": "eval:!doc.__islocal", "description": "% of materials billed against this Sales Order", "fieldname": "per_billed", "fieldtype": "Percent", + "hide_days": 1, + "hide_seconds": 1, "in_list_view": 1, "label": "% Amount Billed", "no_copy": 1, @@ -1070,6 +1298,8 @@ "fieldname": "billing_status", "fieldtype": "Select", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "in_standard_filter": 1, "label": "Billing Status", "no_copy": 1, @@ -1081,6 +1311,8 @@ "collapsible_depends_on": "commission_rate", "fieldname": "sales_team_section_break", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Commission", "oldfieldtype": "Section Break", "options": "fa fa-group", @@ -1089,6 +1321,8 @@ { "fieldname": "sales_partner", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Partner", "oldfieldname": "sales_partner", "oldfieldtype": "Link", @@ -1099,12 +1333,16 @@ { "fieldname": "column_break7", "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1, "print_hide": 1, "width": "50%" }, { "fieldname": "commission_rate", "fieldtype": "Float", + "hide_days": 1, + "hide_seconds": 1, "label": "Commission Rate", "oldfieldname": "commission_rate", "oldfieldtype": "Currency", @@ -1114,6 +1352,8 @@ { "fieldname": "total_commission", "fieldtype": "Currency", + "hide_days": 1, + "hide_seconds": 1, "label": "Total Commission", "oldfieldname": "total_commission", "oldfieldtype": "Currency", @@ -1125,6 +1365,8 @@ "collapsible_depends_on": "sales_team", "fieldname": "section_break1", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Team", "print_hide": 1 }, @@ -1132,6 +1374,8 @@ "allow_on_submit": 1, "fieldname": "sales_team", "fieldtype": "Table", + "hide_days": 1, + "hide_seconds": 1, "label": "Sales Team", "oldfieldname": "sales_team", "oldfieldtype": "Table", @@ -1140,8 +1384,11 @@ }, { "allow_on_submit": 1, + "collapsible": 1, "fieldname": "subscription_section", "fieldtype": "Section Break", + "hide_days": 1, + "hide_seconds": 1, "label": "Auto Repeat Section", "no_copy": 1, "print_hide": 1, @@ -1151,6 +1398,8 @@ "allow_on_submit": 1, "fieldname": "from_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "label": "From Date", "no_copy": 1 }, @@ -1158,16 +1407,22 @@ "allow_on_submit": 1, "fieldname": "to_date", "fieldtype": "Date", + "hide_days": 1, + "hide_seconds": 1, "label": "To Date", "no_copy": 1 }, { "fieldname": "column_break_108", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "hide_days": 1, + "hide_seconds": 1 }, { "fieldname": "auto_repeat", "fieldtype": "Link", + "hide_days": 1, + "hide_seconds": 1, "label": "Auto Repeat", "options": "Auto Repeat" }, @@ -1176,11 +1431,15 @@ "depends_on": "eval: doc.auto_repeat", "fieldname": "update_auto_repeat_reference", "fieldtype": "Button", + "hide_days": 1, + "hide_seconds": 1, "label": "Update Auto Repeat Reference" }, { "fieldname": "contact_phone", "fieldtype": "Data", + "hide_days": 1, + "hide_seconds": 1, "label": "Phone", "read_only": 1 }, @@ -1189,6 +1448,8 @@ "fieldname": "skip_delivery_note", "fieldtype": "Check", "hidden": 1, + "hide_days": 1, + "hide_seconds": 1, "label": "Skip Delivery Note", "print_hide": 1 } @@ -1197,7 +1458,7 @@ "idx": 105, "is_submittable": 1, "links": [], - "modified": "2020-05-19 21:39:19.486684", + "modified": "2020-06-30 11:56:42.301317", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/test_records.json b/erpnext/selling/doctype/sales_order/test_records.json index 6cbd6c2fc17..8a090e6d3d3 100644 --- a/erpnext/selling/doctype/sales_order/test_records.json +++ b/erpnext/selling/doctype/sales_order/test_records.json @@ -1,39 +1,39 @@ [ { "advance_paid": 0.0, - "company": "_Test Company", - "conversion_rate": 1.0, - "currency": "INR", - "customer": "_Test Customer", - "customer_group": "_Test Customer Group", - "customer_name": "_Test Customer", - "doctype": "Sales Order", - "base_grand_total": 1000.0, - "grand_total": 1000.0, - "naming_series": "_T-Sales Order-", - "order_type": "Sales", - "plc_conversion_rate": 1.0, - "price_list_currency": "INR", + "company": "_Test Company", + "conversion_rate": 1.0, + "currency": "INR", + "customer": "_Test Customer", + "customer_group": "_Test Customer Group", + "customer_name": "_Test Customer", + "doctype": "Sales Order", + "base_grand_total": 1000.0, + "grand_total": 1000.0, + "naming_series": "_T-Sales Order-", + "order_type": "Sales", + "plc_conversion_rate": 1.0, + "price_list_currency": "INR", "items": [ { - "base_amount": 1000.0, - "base_rate": 100.0, - "description": "CPU", - "doctype": "Sales Order Item", - "item_code": "_Test Item Home Desktop 100", - "item_name": "CPU", - "delivery_date": "2013-02-23", - "parentfield": "items", - "qty": 10.0, - "rate": 100.0, + "base_amount": 1000.0, + "base_rate": 100.0, + "description": "CPU", + "doctype": "Sales Order Item", + "item_code": "_Test Item", + "item_name": "_Test Item 1", + "delivery_date": "2013-02-23", + "parentfield": "items", + "qty": 10.0, + "rate": 100.0, "warehouse": "_Test Warehouse - _TC", "stock_uom": "_Test UOM", "conversion_factor": 1.0, "uom": "_Test UOM" } - ], - "selling_price_list": "_Test Price List", - "territory": "_Test Territory", + ], + "selling_price_list": "_Test Price List", + "territory": "_Test Territory", "transaction_date": "2013-02-21" } ] \ No newline at end of file diff --git a/erpnext/selling/module_onboarding/selling/selling.json b/erpnext/selling/module_onboarding/selling/selling.json index 10a33c9cf52..160208ff680 100644 --- a/erpnext/selling/module_onboarding/selling/selling.json +++ b/erpnext/selling/module_onboarding/selling/selling.json @@ -19,7 +19,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/selling", "idx": 0, "is_complete": 0, - "modified": "2020-06-01 13:35:16.100512", + "modified": "2020-07-08 14:05:37.669753", "modified_by": "Administrator", "module": "Selling", "name": "Selling", @@ -47,8 +47,7 @@ "step": "Selling Settings" } ], - "subtitle": "Products, Sales, Analysis and more.", + "subtitle": "Products, Sales, Analysis, and more.", "success_message": "The Selling Module is all set up!", - "title": "Let's Set Up the Selling Module.", - "user_can_dismiss": 1 + "title": "Let's Set Up the Selling Module." } \ No newline at end of file diff --git a/erpnext/selling/onboarding_step/setup_your_warehouse/setup_your_warehouse.json b/erpnext/selling/onboarding_step/setup_your_warehouse/setup_your_warehouse.json index 557c905bd6c..9457deee262 100644 --- a/erpnext/selling/onboarding_step/setup_your_warehouse/setup_your_warehouse.json +++ b/erpnext/selling/onboarding_step/setup_your_warehouse/setup_your_warehouse.json @@ -8,13 +8,13 @@ "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-19 18:54:19.383397", + "modified": "2020-07-04 12:33:16.970031", "modified_by": "Administrator", "name": "Setup your Warehouse", "owner": "Administrator", "path": "Tree/Warehouse", "reference_document": "Warehouse", "show_full_form": 0, - "title": "Setup your Warehouse", + "title": "Set up your Warehouse", "validate_action": 1 } \ No newline at end of file diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index dfa0f7f2dbf..1ae1fde588d 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -167,6 +167,7 @@ def get_item_group_condition(pos_profile): return cond % tuple(item_groups) +@frappe.whitelist() def item_group_query(doctype, txt, searchfield, start, page_len, filters): item_groups = [] cond = "1=1" @@ -187,4 +188,4 @@ def item_group_query(doctype, txt, searchfield, start, page_len, filters): @frappe.whitelist() def get_pos_fields(): return frappe.get_all("POS Field", fields=["label", "fieldname", - "fieldtype", "default_value", "reqd", "read_only", "options"]) \ No newline at end of file + "fieldtype", "default_value", "reqd", "read_only", "options"]) diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py index 14d80315823..e89c45182fd 100644 --- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py @@ -158,7 +158,7 @@ def get_data(): } pending_so.append(so_record) else: - for item in bundled_item_map.get((so.name, so.item_code)): + for item in bundled_item_map.get((so.name, so.item_code), []): material_requests_against_so = materials_request_dict.get((so.name, item.item_code)) or {} if flt(item.qty) > flt(material_requests_against_so.get('qty')): so_record = { diff --git a/erpnext/setup/doctype/customer_group/customer_group.py b/erpnext/setup/doctype/customer_group/customer_group.py index f62613ea1bb..68e1ccb6356 100644 --- a/erpnext/setup/doctype/customer_group/customer_group.py +++ b/erpnext/setup/doctype/customer_group/customer_group.py @@ -6,9 +6,12 @@ import frappe from frappe import _ -from frappe.utils.nestedset import NestedSet +from frappe.utils.nestedset import NestedSet, get_root_of class CustomerGroup(NestedSet): nsm_parent_field = 'parent_customer_group' + def validate(self): + if not self.parent_customer_group: + self.parent_customer_group = get_root_of("Customer Group") def on_update(self): self.validate_name_with_customer() diff --git a/erpnext/setup/doctype/sales_person/sales_person.py b/erpnext/setup/doctype/sales_person/sales_person.py index 3379534cf82..19c2e5b9543 100644 --- a/erpnext/setup/doctype/sales_person/sales_person.py +++ b/erpnext/setup/doctype/sales_person/sales_person.py @@ -5,13 +5,16 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import flt -from frappe.utils.nestedset import NestedSet +from frappe.utils.nestedset import NestedSet, get_root_of from erpnext import get_default_currency class SalesPerson(NestedSet): nsm_parent_field = 'parent_sales_person' def validate(self): + if not self.parent_sales_person: + self.parent_sales_person = get_root_of("Sales Person") + for d in self.get('targets') or []: if not flt(d.target_qty) and not flt(d.target_amount): frappe.throw(_("Either target qty or target amount is mandatory.")) diff --git a/erpnext/setup/doctype/territory/territory.py b/erpnext/setup/doctype/territory/territory.py index 808b5386abe..05e8f666cfb 100644 --- a/erpnext/setup/doctype/territory/territory.py +++ b/erpnext/setup/doctype/territory/territory.py @@ -6,12 +6,14 @@ import frappe from frappe.utils import flt from frappe import _ -from frappe.utils.nestedset import NestedSet +from frappe.utils.nestedset import NestedSet, get_root_of class Territory(NestedSet): nsm_parent_field = 'parent_territory' def validate(self): + if not self.parent_territory: + self.parent_territory = get_root_of("Territory") for d in self.get('targets') or []: if not flt(d.target_qty) and not flt(d.target_amount): diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index 74ff0ecfd8f..aa9fbc0a92c 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -29,12 +29,10 @@ def after_install(): def check_setup_wizard_not_completed(): - if frappe.db.get_default('desktop:home_page') == 'desktop': - print() - print("ERPNext can only be installed on a fresh site where the setup wizard is not completed") - print("You can reinstall this site (after saving your data) using: bench --site [sitename] reinstall") - print() - return False + if frappe.db.get_default('desktop:home_page') != 'setup-wizard': + message = """ERPNext can only be installed on a fresh site where the setup wizard is not completed. +You can reinstall this site (after saving your data) using: bench --site [sitename] reinstall""" + frappe.throw(message) def set_single_defaults(): @@ -105,4 +103,3 @@ def add_company_to_session_defaults(): "ref_doctype": "Company" }) settings.save() - diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index a921a56f53f..4b04a0a8c3d 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -537,11 +537,8 @@ class TestDeliveryNote(unittest.TestCase): dt = make_delivery_trip(dn.name) self.assertEqual(dn.name, dt.delivery_stops[0].delivery_note) - def test_delivery_note_for_enable_allow_cost_center_in_entry_of_bs_account(self): + def test_delivery_note_with_cost_center(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - TCP1" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company with perpetual inventory") @@ -567,13 +564,8 @@ class TestDeliveryNote(unittest.TestCase): } for i, gle in enumerate(gl_entries): self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - def test_delivery_note_for_disable_allow_cost_center_in_entry_of_bs_account(self): - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() + def test_delivery_note_cost_center_with_balance_sheet_account(self): cost_center = "Main - TCP1" company = frappe.db.get_value('Warehouse', 'Stores - TCP1', 'company') @@ -583,7 +575,11 @@ class TestDeliveryNote(unittest.TestCase): make_stock_entry(target="Stores - TCP1", qty=5, basic_rate=100) stock_in_hand_account = get_inventory_account('_Test Company with perpetual inventory') - dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1") + dn = create_delivery_note(company='_Test Company with perpetual inventory', warehouse='Stores - TCP1', cost_center = 'Main - TCP1', expense_account = "Cost of Goods Sold - TCP1", + do_not_submit=1) + + dn.get('items')[0].cost_center = None + dn.submit() gl_entries = get_gl_entries("Delivery Note", dn.name) @@ -593,7 +589,7 @@ class TestDeliveryNote(unittest.TestCase): "cost_center": cost_center }, stock_in_hand_account: { - "cost_center": None + "cost_center": cost_center } } for i, gle in enumerate(gl_entries): diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index 7ea2de27533..3d57f476010 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -1,5 +1,4 @@ { - "actions": [], "autoname": "hash", "creation": "2013-04-22 13:15:44", "doctype": "DocType", @@ -82,6 +81,7 @@ "accounting_dimensions_section", "cost_center", "dimension_col_break", + "project", "section_break_72", "page_break" ], @@ -701,6 +701,12 @@ "fieldname": "dimension_col_break", "fieldtype": "Column Break" }, + { + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + }, { "fieldname": "dn_detail", "fieldtype": "Data", @@ -714,7 +720,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2020-03-05 14:18:33.131672", + "modified": "2020-07-20 12:25:06.177894", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index c371999a277..963c87a0af5 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -987,6 +987,7 @@ "read_only": 1 }, { + "collapsible": 1, "depends_on": "eval:(!doc.is_item_from_hub)", "fieldname": "hub_publishing_sb", "fieldtype": "Section Break", @@ -1060,7 +1061,7 @@ "image_field": "image", "links": [], "max_attachments": 1, - "modified": "2020-04-08 15:56:06.195722", + "modified": "2020-06-30 12:01:07.534447", "modified_by": "Administrator", "module": "Stock", "name": "Item", @@ -1122,4 +1123,4 @@ "sort_order": "DESC", "title_field": "item_name", "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json index 6c1a55945c8..9ca887c77e3 100644 --- a/erpnext/stock/doctype/item/test_records.json +++ b/erpnext/stock/doctype/item/test_records.json @@ -92,8 +92,7 @@ { "doctype": "Item Tax", "parentfield": "taxes", - "item_tax_template": "_Test Account Excise Duty @ 10", - "tax_category": "" + "item_tax_template": "_Test Account Excise Duty @ 10" } ], "stock_uom": "_Test UOM 1" @@ -371,8 +370,7 @@ { "doctype": "Item Tax", "parentfield": "taxes", - "item_tax_template": "_Test Account Excise Duty @ 10", - "tax_category": "" + "item_tax_template": "_Test Account Excise Duty @ 10" }, { "doctype": "Item Tax", @@ -451,14 +449,13 @@ { "doctype": "Item Tax", "parentfield": "taxes", - "item_tax_template": "_Test Account Excise Duty @ 20", - "tax_category": "" + "item_tax_template": "_Test Account Excise Duty @ 20" }, { "doctype": "Item Tax", "parentfield": "taxes", - "item_tax_template": "_Test Item Tax Template 1", - "tax_category": "_Test Tax Category 1" + "tax_category": "_Test Tax Category 1", + "item_tax_template": "_Test Item Tax Template 1" } ] } diff --git a/erpnext/stock/doctype/item_alternative/item_alternative.py b/erpnext/stock/doctype/item_alternative/item_alternative.py index da0c3b7f1e4..522dfc67a9c 100644 --- a/erpnext/stock/doctype/item_alternative/item_alternative.py +++ b/erpnext/stock/doctype/item_alternative/item_alternative.py @@ -42,6 +42,7 @@ class ItemAlternative(Document): 'alternative_item_code': self.alternative_item_code, 'name': ('!=', self.name)}): frappe.throw(_("Already record exists for the item {0}").format(self.item_code)) +@frappe.whitelist() def get_alternative_items(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql(""" (select alternative_item_code from `tabItem Alternative` where item_code = %(item_code)s and alternative_item_code like %(txt)s) @@ -52,4 +53,4 @@ def get_alternative_items(doctype, txt, searchfield, start, page_len, filters): """.format(start, page_len), { "item_code": filters.get('item_code'), "txt": '%' + txt + '%' - }) \ No newline at end of file + }) diff --git a/erpnext/stock/doctype/item_price/item_price.json b/erpnext/stock/doctype/item_price/item_price.json index 2e0ddfdaefc..5f62381f8b3 100644 --- a/erpnext/stock/doctype/item_price/item_price.json +++ b/erpnext/stock/doctype/item_price/item_price.json @@ -172,7 +172,7 @@ "default": "Today", "fieldname": "valid_from", "fieldtype": "Date", - "label": "Valid From " + "label": "Valid From" }, { "default": "0", @@ -187,7 +187,7 @@ { "fieldname": "valid_upto", "fieldtype": "Date", - "label": "Valid Upto " + "label": "Valid Upto" }, { "fieldname": "section_break_24", @@ -208,7 +208,7 @@ "icon": "fa fa-flag", "idx": 1, "links": [], - "modified": "2020-02-28 14:21:25.580331", + "modified": "2020-07-06 22:31:32.943475", "modified_by": "Administrator", "module": "Stock", "name": "Item Price", diff --git a/erpnext/stock/doctype/item_tax/item_tax.json b/erpnext/stock/doctype/item_tax/item_tax.json index a93e4636add..ae36efc7e3f 100644 --- a/erpnext/stock/doctype/item_tax/item_tax.json +++ b/erpnext/stock/doctype/item_tax/item_tax.json @@ -1,5 +1,4 @@ { - "actions": [], "creation": "2013-02-22 01:28:01", "doctype": "DocType", "editable_grid": 1, @@ -38,8 +37,7 @@ ], "idx": 1, "istable": 1, - "links": [], - "modified": "2019-12-28 21:54:40.807849", + "modified": "2020-06-25 01:40:28.859752", "modified_by": "Administrator", "module": "Stock", "name": "Item Tax", diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js index 3a8deb6d254..60f5ff3629b 100644 --- a/erpnext/stock/doctype/material_request/material_request.js +++ b/erpnext/stock/doctype/material_request/material_request.js @@ -180,9 +180,8 @@ frappe.ui.form.on('Material Request', { }); }, - get_item_data: function(frm, item) { + get_item_data: function(frm, item, overwrite_warehouse=false) { if (item && !item.item_code) { return; } - frm.call({ method: "erpnext.stock.get_item_details.get_item_details", child: item, @@ -203,7 +202,8 @@ frappe.ui.form.on('Material Request', { plc_conversion_rate: 1, rate: item.rate, conversion_factor: item.conversion_factor - } + }, + overwrite_warehouse: overwrite_warehouse }, callback: function(r) { const d = item; @@ -354,29 +354,29 @@ frappe.ui.form.on("Material Request Item", { } const item = locals[doctype][name]; - frm.events.get_item_data(frm, item); + frm.events.get_item_data(frm, item, false); }, from_warehouse: function(frm, doctype, name) { const item = locals[doctype][name]; - frm.events.get_item_data(frm, item); + frm.events.get_item_data(frm, item, false); }, warehouse: function(frm, doctype, name) { const item = locals[doctype][name]; - frm.events.get_item_data(frm, item); + frm.events.get_item_data(frm, item, false); }, rate: function(frm, doctype, name) { const item = locals[doctype][name]; - frm.events.get_item_data(frm, item); + frm.events.get_item_data(frm, item, false); }, item_code: function(frm, doctype, name) { const item = locals[doctype][name]; item.rate = 0; set_schedule_date(frm); - frm.events.get_item_data(frm, item); + frm.events.get_item_data(frm, item, true); }, schedule_date: function(frm, cdt, cdn) { diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 97606f4e3a0..25f1ed95058 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -402,6 +402,7 @@ def get_material_requests_based_on_supplier(doctype, txt, searchfield, start, pa return material_requests +@frappe.whitelist() def get_default_supplier_query(doctype, txt, searchfield, start, page_len, filters): doc = frappe.get_doc("Material Request", filters.get("doc")) item_list = [] @@ -567,4 +568,4 @@ def create_pick_list(source_name, target_doc=None): doc.set_item_locations() - return doc \ No newline at end of file + return doc diff --git a/erpnext/stock/doctype/packing_slip/packing_slip.py b/erpnext/stock/doctype/packing_slip/packing_slip.py index 7a5ae317c2b..4f831d7a858 100644 --- a/erpnext/stock/doctype/packing_slip/packing_slip.py +++ b/erpnext/stock/doctype/packing_slip/packing_slip.py @@ -175,6 +175,7 @@ class PackingSlip(Document): self.update_item_details() +@frappe.whitelist() def item_details(doctype, txt, searchfield, start, page_len, filters): from erpnext.controllers.queries import get_match_cond return frappe.db.sql("""select name, item_name, description from `tabItem` diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json index 44d5f690285..df9eb50843f 100755 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json @@ -1,5 +1,4 @@ { - "actions": [], "allow_import": 1, "autoname": "naming_series:", "creation": "2013-05-21 16:16:39", @@ -104,6 +103,7 @@ "bill_no", "bill_date", "more_info", + "project", "status", "amended_from", "range", @@ -132,17 +132,13 @@ { "fieldname": "supplier_section", "fieldtype": "Section Break", - "options": "fa fa-user", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-user" }, { "fieldname": "column_break0", "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -153,9 +149,7 @@ "hidden": 1, "label": "Title", "no_copy": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "naming_series", @@ -167,9 +161,7 @@ "options": "MAT-PRE-.YYYY.-", "print_hide": 1, "reqd": 1, - "set_only_once": 1, - "show_days": 1, - "show_seconds": 1 + "set_only_once": 1 }, { "bold": 1, @@ -184,8 +176,6 @@ "print_width": "150px", "reqd": 1, "search_index": 1, - "show_days": 1, - "show_seconds": 1, "width": "150px" }, { @@ -196,24 +186,18 @@ "fieldtype": "Data", "in_global_search": 1, "label": "Supplier Name", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "supplier_delivery_note", "fieldtype": "Data", - "label": "Supplier Delivery Note", - "show_days": 1, - "show_seconds": 1 + "label": "Supplier Delivery Note" }, { "fieldname": "column_break1", "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -228,8 +212,6 @@ "print_width": "100px", "reqd": 1, "search_index": 1, - "show_days": 1, - "show_seconds": 1, "width": "100px" }, { @@ -243,8 +225,6 @@ "print_hide": 1, "print_width": "100px", "reqd": 1, - "show_days": 1, - "show_seconds": 1, "width": "100px" }, { @@ -253,9 +233,7 @@ "fieldname": "set_posting_time", "fieldtype": "Check", "label": "Edit Posting Date and Time", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "company", @@ -269,8 +247,6 @@ "print_width": "150px", "remember_last_selected_value": 1, "reqd": 1, - "show_days": 1, - "show_seconds": 1, "width": "150px" }, { @@ -280,9 +256,7 @@ "label": "Is Return", "no_copy": 1, "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "is_return", @@ -292,60 +266,46 @@ "no_copy": 1, "options": "Purchase Receipt", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "fieldname": "section_addresses", "fieldtype": "Section Break", - "label": "Address and Contact", - "show_days": 1, - "show_seconds": 1 + "label": "Address and Contact" }, { "fieldname": "supplier_address", "fieldtype": "Link", "label": "Select Supplier Address", "options": "Address", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "contact_person", "fieldtype": "Link", "label": "Contact Person", "options": "Contact", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "address_display", "fieldtype": "Small Text", "label": "Address", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "contact_display", "fieldtype": "Small Text", "in_global_search": 1, "label": "Contact", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "contact_email", @@ -353,42 +313,32 @@ "label": "Contact Email", "options": "Email", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "col_break_address", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "shipping_address", "fieldtype": "Link", "label": "Select Shipping Address", "options": "Address", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "shipping_address_display", "fieldtype": "Small Text", "label": "Shipping Address", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", "label": "Currency and Price List", - "options": "fa fa-tag", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-tag" }, { "fieldname": "currency", @@ -398,9 +348,7 @@ "oldfieldtype": "Select", "options": "Currency", "print_hide": 1, - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "description": "Rate at which supplier's currency is converted to company's base currency", @@ -411,17 +359,13 @@ "oldfieldtype": "Currency", "precision": "9", "print_hide": 1, - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "fieldname": "column_break2", "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -429,9 +373,7 @@ "fieldtype": "Link", "label": "Price List", "options": "Price List", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "depends_on": "buying_price_list", @@ -440,9 +382,7 @@ "label": "Price List Currency", "options": "Currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "buying_price_list", @@ -450,9 +390,7 @@ "fieldtype": "Float", "label": "Price List Exchange Rate", "precision": "9", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "default": "0", @@ -461,15 +399,11 @@ "label": "Ignore Pricing Rule", "no_copy": 1, "permlevel": 1, - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "sec_warehouse", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "description": "Sets 'Accepted Warehouse' in each row of the items table.", @@ -477,9 +411,7 @@ "fieldtype": "Link", "label": "Accepted Warehouse", "options": "Warehouse", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "description": "Sets 'Rejected Warehouse' in each row of the items table.", @@ -490,15 +422,11 @@ "oldfieldname": "rejected_warehouse", "oldfieldtype": "Link", "options": "Warehouse", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "col_break_warehouse", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "default": "No", @@ -508,9 +436,7 @@ "oldfieldname": "is_subcontracted", "oldfieldtype": "Select", "options": "No\nYes", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "depends_on": "eval:doc.is_subcontracted==\"Yes\"", @@ -523,17 +449,13 @@ "options": "Warehouse", "print_hide": 1, "print_width": "50px", - "show_days": 1, - "show_seconds": 1, "width": "50px" }, { "fieldname": "items_section", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-shopping-cart" }, { "allow_bulk_edit": 1, @@ -543,26 +465,20 @@ "oldfieldname": "purchase_receipt_details", "oldfieldtype": "Table", "options": "Purchase Receipt Item", - "reqd": 1, - "show_days": 1, - "show_seconds": 1 + "reqd": 1 }, { "collapsible": 1, "fieldname": "pricing_rule_details", "fieldtype": "Section Break", - "label": "Pricing Rules", - "show_days": 1, - "show_seconds": 1 + "label": "Pricing Rules" }, { "fieldname": "pricing_rules", "fieldtype": "Table", "label": "Pricing Rule Detail", "options": "Pricing Rule Detail", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "supplied_items", @@ -571,9 +487,7 @@ "label": "Get Current Stock", "oldfieldtype": "Button", "options": "get_current_stock", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, @@ -584,9 +498,7 @@ "oldfieldtype": "Section Break", "options": "fa fa-table", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "supplied_items", @@ -597,24 +509,18 @@ "oldfieldtype": "Table", "options": "Purchase Receipt Item Supplied", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "section_break0", "fieldtype": "Section Break", - "oldfieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Section Break" }, { "fieldname": "total_qty", "fieldtype": "Float", "label": "Total Quantity", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_total", @@ -622,9 +528,7 @@ "label": "Total (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_net_total", @@ -637,24 +541,18 @@ "print_width": "150px", "read_only": 1, "reqd": 1, - "show_days": 1, - "show_seconds": 1, "width": "150px" }, { "fieldname": "column_break_27", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "total", "fieldtype": "Currency", "label": "Total", "options": "currency", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "net_total", @@ -664,56 +562,42 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "total_net_weight", "fieldtype": "Float", "label": "Total Net Weight", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "description": "Add / Edit Taxes and Charges", "fieldname": "taxes_charges_section", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-money", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-money" }, { "fieldname": "tax_category", "fieldtype": "Link", "label": "Tax Category", "options": "Tax Category", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "shipping_col", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "shipping_rule", "fieldtype": "Link", "label": "Shipping Rule", - "options": "Shipping Rule", - "show_days": 1, - "show_seconds": 1 + "options": "Shipping Rule" }, { "fieldname": "taxes_section", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "fieldname": "taxes_and_charges", @@ -722,9 +606,7 @@ "oldfieldname": "purchase_other_charges", "oldfieldtype": "Link", "options": "Purchase Taxes and Charges Template", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "taxes", @@ -732,17 +614,13 @@ "label": "Purchase Taxes and Charges", "oldfieldname": "purchase_tax_details", "oldfieldtype": "Table", - "options": "Purchase Taxes and Charges", - "show_days": 1, - "show_seconds": 1 + "options": "Purchase Taxes and Charges" }, { "collapsible": 1, "fieldname": "sec_tax_breakup", "fieldtype": "Section Break", - "label": "Tax Breakup", - "show_days": 1, - "show_seconds": 1 + "label": "Tax Breakup" }, { "fieldname": "other_charges_calculation", @@ -751,17 +629,13 @@ "no_copy": 1, "oldfieldtype": "HTML", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "totals", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-money", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-money" }, { "fieldname": "base_taxes_and_charges_added", @@ -771,9 +645,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_taxes_and_charges_deducted", @@ -783,9 +655,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_total_taxes_and_charges", @@ -795,16 +665,12 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break3", "fieldtype": "Column Break", "print_width": "50%", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -815,9 +681,7 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "taxes_and_charges_deducted", @@ -827,9 +691,7 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "total_taxes_and_charges", @@ -837,18 +699,14 @@ "label": "Total Taxes and Charges", "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "collapsible_depends_on": "discount_amount", "fieldname": "section_break_42", "fieldtype": "Section Break", - "label": "Additional Discount", - "show_days": 1, - "show_seconds": 1 + "label": "Additional Discount" }, { "default": "Grand Total", @@ -856,9 +714,7 @@ "fieldtype": "Select", "label": "Apply Additional Discount On", "options": "\nGrand Total\nNet Total", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "base_discount_amount", @@ -866,38 +722,28 @@ "label": "Additional Discount Amount (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_44", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "additional_discount_percentage", "fieldtype": "Float", "label": "Additional Discount Percentage", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "discount_amount", "fieldtype": "Currency", "label": "Additional Discount Amount", "options": "currency", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "section_break_46", - "fieldtype": "Section Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Section Break" }, { "fieldname": "base_grand_total", @@ -907,9 +753,7 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_rounding_adjustment", @@ -918,9 +762,7 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_in_words", @@ -929,9 +771,7 @@ "oldfieldname": "in_words", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "base_rounded_total", @@ -941,15 +781,11 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "column_break_50", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "grand_total", @@ -959,9 +795,7 @@ "oldfieldname": "grand_total_import", "oldfieldtype": "Currency", "options": "currency", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "rounding_adjustment", @@ -970,9 +804,7 @@ "no_copy": 1, "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -982,9 +814,7 @@ "no_copy": 1, "options": "currency", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "in_words", @@ -993,17 +823,13 @@ "oldfieldname": "in_words_import", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "default": "0", "fieldname": "disable_rounded_total", "fieldtype": "Check", - "label": "Disable Rounded Total", - "show_days": 1, - "show_seconds": 1 + "label": "Disable Rounded Total" }, { "collapsible": 1, @@ -1012,9 +838,7 @@ "fieldtype": "Section Break", "label": "Terms and Conditions", "oldfieldtype": "Section Break", - "options": "fa fa-legal", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-legal" }, { "fieldname": "tc_name", @@ -1023,18 +847,14 @@ "oldfieldname": "tc_name", "oldfieldtype": "Link", "options": "Terms and Conditions", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "terms", "fieldtype": "Text Editor", "label": "Terms and Conditions", "oldfieldname": "terms", - "oldfieldtype": "Text Editor", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Text Editor" }, { "fieldname": "bill_no", @@ -1043,9 +863,7 @@ "label": "Bill No", "oldfieldname": "bill_no", "oldfieldtype": "Data", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "bill_date", @@ -1054,9 +872,7 @@ "label": "Bill Date", "oldfieldname": "bill_date", "oldfieldtype": "Date", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, @@ -1064,9 +880,7 @@ "fieldtype": "Section Break", "label": "More Information", "oldfieldtype": "Section Break", - "options": "fa fa-file-text", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-file-text" }, { "default": "Draft", @@ -1083,8 +897,6 @@ "read_only": 1, "reqd": 1, "search_index": 1, - "show_days": 1, - "show_seconds": 1, "width": "150px" }, { @@ -1100,8 +912,6 @@ "print_hide": 1, "print_width": "150px", "read_only": 1, - "show_days": 1, - "show_seconds": 1, "width": "150px" }, { @@ -1111,9 +921,7 @@ "label": "Range", "oldfieldname": "range", "oldfieldtype": "Data", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break4", @@ -1121,26 +929,27 @@ "oldfieldtype": "Column Break", "print_hide": 1, "print_width": "50%", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, + { + "description": "Track this Purchase Receipt against any Project", + "fieldname": "project", + "fieldtype": "Link", + "label": "Project", + "options": "Project" + }, { "fieldname": "per_billed", "fieldtype": "Percent", "label": "% Amount Billed", "no_copy": 1, "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "subscription_detail", "fieldtype": "Section Break", - "label": "Auto Repeat Detail", - "show_days": 1, - "show_seconds": 1 + "label": "Auto Repeat Detail" }, { "fieldname": "auto_repeat", @@ -1149,17 +958,13 @@ "no_copy": 1, "options": "Auto Repeat", "print_hide": 1, - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "collapsible": 1, "fieldname": "printing_settings", "fieldtype": "Section Break", - "label": "Printing Settings", - "show_days": 1, - "show_seconds": 1 + "label": "Printing Settings" }, { "allow_on_submit": 1, @@ -1167,9 +972,7 @@ "fieldtype": "Link", "label": "Letter Head", "options": "Letter Head", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "allow_on_submit": 1, @@ -1181,17 +984,13 @@ "oldfieldtype": "Link", "options": "Print Heading", "print_hide": 1, - "report_hide": 1, - "show_days": 1, - "show_seconds": 1 + "report_hide": 1 }, { "fieldname": "language", "fieldtype": "Data", "label": "Print Language", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "allow_on_submit": 1, @@ -1199,15 +998,11 @@ "fieldname": "group_same_items", "fieldtype": "Check", "label": "Group same items", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "fieldname": "column_break_97", - "fieldtype": "Column Break", - "show_days": 1, - "show_seconds": 1 + "fieldtype": "Column Break" }, { "fieldname": "other_details", @@ -1218,8 +1013,6 @@ "options": "
Other Details
", "print_hide": 1, "print_width": "30%", - "show_days": 1, - "show_seconds": 1, "width": "30%" }, { @@ -1227,17 +1020,13 @@ "fieldtype": "Small Text", "label": "Instructions", "oldfieldname": "instructions", - "oldfieldtype": "Text", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Text" }, { "fieldname": "remarks", "fieldtype": "Small Text", "label": "Remarks", - "print_hide": 1, - "show_days": 1, - "show_seconds": 1 + "print_hide": 1 }, { "collapsible": 1, @@ -1245,25 +1034,19 @@ "fieldname": "transporter_info", "fieldtype": "Section Break", "label": "Transporter Details", - "options": "fa fa-truck", - "show_days": 1, - "show_seconds": 1 + "options": "fa fa-truck" }, { "fieldname": "transporter_name", "fieldtype": "Data", "label": "Transporter Name", "oldfieldname": "transporter_name", - "oldfieldtype": "Data", - "show_days": 1, - "show_seconds": 1 + "oldfieldtype": "Data" }, { "fieldname": "column_break5", "fieldtype": "Column Break", "print_width": "50%", - "show_days": 1, - "show_seconds": 1, "width": "50%" }, { @@ -1274,8 +1057,6 @@ "oldfieldname": "lr_no", "oldfieldtype": "Data", "print_width": "100px", - "show_days": 1, - "show_seconds": 1, "width": "100px" }, { @@ -1286,8 +1067,6 @@ "oldfieldname": "lr_date", "oldfieldtype": "Date", "print_width": "100px", - "show_days": 1, - "show_seconds": 1, "width": "100px" }, { @@ -1296,48 +1075,38 @@ "fieldname": "is_internal_supplier", "fieldtype": "Check", "label": "Is Internal Supplier", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "inter_company_reference", "fieldtype": "Link", "label": "Inter Company Reference", "options": "Delivery Note", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 }, { "fieldname": "scan_barcode", "fieldtype": "Data", - "label": "Scan Barcode", - "show_days": 1, - "show_seconds": 1 + "label": "Scan Barcode" }, { "fieldname": "billing_address", "fieldtype": "Link", "label": "Select Billing Address", - "options": "Address", - "show_days": 1, - "show_seconds": 1 + "options": "Address" }, { "fieldname": "billing_address_display", "fieldtype": "Small Text", "label": "Billing Address", - "read_only": 1, - "show_days": 1, - "show_seconds": 1 + "read_only": 1 } ], "icon": "fa fa-truck", "idx": 261, "is_submittable": 1, "links": [], - "modified": "2020-06-13 22:26:03.600092", + "modified": "2020-07-15 10:01:39.302238", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt", diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 649cfdcaace..d97b9e82c3c 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -403,11 +403,8 @@ class TestPurchaseReceipt(unittest.TestCase): pr_return.submit() - def test_purchase_receipt_for_enable_allow_cost_center_in_entry_of_bs_account(self): + def test_purchase_receipt_cost_center(self): from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 1 - accounts_settings.save() cost_center = "_Test Cost Center for BS Account - TCP1" create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company with perpetual inventory") @@ -435,14 +432,7 @@ class TestPurchaseReceipt(unittest.TestCase): for i, gle in enumerate(gl_entries): self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - - def test_purchase_receipt_for_disable_allow_cost_center_in_entry_of_bs_account(self): - accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings') - accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 - accounts_settings.save() - + def test_purchase_receipt_cost_center_with_balance_sheet_account(self): if not frappe.db.exists('Location', 'Test Location'): frappe.get_doc({ 'doctype': 'Location', @@ -454,13 +444,14 @@ class TestPurchaseReceipt(unittest.TestCase): gl_entries = get_gl_entries("Purchase Receipt", pr.name) self.assertTrue(gl_entries) + cost_center = pr.get('items')[0].cost_center expected_values = { "Stock Received But Not Billed - TCP1": { - "cost_center": None + "cost_center": cost_center }, stock_in_hand_account: { - "cost_center": None + "cost_center": cost_center } } for i, gle in enumerate(gl_entries): diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py index 37ab807cb7b..568e7428765 100644 --- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py @@ -58,6 +58,7 @@ class QualityInspection(Document): .format(parent_doc=self.reference_type, child_doc=doctype), (quality_inspection, self.modified, self.reference_name, self.item_code)) +@frappe.whitelist() def item_query(doctype, txt, searchfield, start, page_len, filters): if filters.get("from"): from frappe.desk.reportview import get_match_cond @@ -86,6 +87,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters): page_len = page_len, qi_condition = qi_condition), {'parent': filters.get('parent'), 'txt': "%%%s%%" % txt}) +@frappe.whitelist() def quality_inspection_query(doctype, txt, searchfield, start, page_len, filters): return frappe.get_all('Quality Inspection', limit_start=start, @@ -118,4 +120,4 @@ def make_quality_inspection(source_name, target_doc=None): } }, target_doc, postprocess) - return doc \ No newline at end of file + return doc diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index f3514c7385d..90f0f5881d4 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -190,23 +190,6 @@ class SerialNo(StockController): if sle_exists: frappe.throw(_("Cannot delete Serial No {0}, as it is used in stock transactions").format(self.name)) - def before_rename(self, old, new, merge=False): - if merge: - frappe.throw(_("Sorry, Serial Nos cannot be merged")) - - def after_rename(self, old, new, merge=False): - """rename serial_no text fields""" - for dt in frappe.db.sql("""select parent from tabDocField - where fieldname='serial_no' and fieldtype in ('Text', 'Small Text')"""): - - for item in frappe.db.sql("""select name, serial_no from `tab%s` - where serial_no like %s""" % (dt[0], frappe.db.escape('%' + old + '%'))): - - serial_nos = map(lambda i: new if i.upper()==old.upper() else i, item[1].split('\n')) - frappe.db.sql("""update `tab%s` set serial_no = %s - where name=%s""" % (dt[0], '%s', '%s'), - ('\n'.join(list(serial_nos)), item[0])) - def update_serial_no_reference(self, serial_no=None): last_sle = self.get_last_sle(serial_no) self.set_purchase_details(last_sle.get("purchase_sle")) diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.js b/erpnext/stock/doctype/stock_settings/stock_settings.js index d5049ac6ed0..48624e0f25e 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.js +++ b/erpnext/stock/doctype/stock_settings/stock_settings.js @@ -20,7 +20,7 @@ frappe.tour['Stock Settings'] = [ { fieldname: "item_naming_by", title: __("Item Naming By"), - description: __("By default, the Item Name is set as per the Item Code entered. If you want Items to be named by a") + "Naming Series" + __(" choose the 'Naming Series' option."), + description: __("By default, the Item Name is set as per the Item Code entered. If you want Items to be named by a ") + "Naming Series" + __(" choose the 'Naming Series' option."), }, { fieldname: "default_warehouse", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 0ed3b276e39..b8554c83e24 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -47,6 +47,8 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru """ args = process_args(args) + for_validate = process_string_args(for_validate) + overwrite_warehouse = process_string_args(overwrite_warehouse) item = frappe.get_cached_doc("Item", args.item_code) validate_item_details(args, item) @@ -166,6 +168,10 @@ def process_args(args): set_transaction_type(args) return args +def process_string_args(args): + if isinstance(args, string_types): + args = json.loads(args) + return args @frappe.whitelist() def get_item_code(barcode=None, serial_no=None): @@ -413,7 +419,7 @@ def get_item_tax_info(company, tax_category, item_codes): continue out[item_code] = {} item = frappe.get_cached_doc("Item", item_code) - get_item_tax_template({"tax_category": tax_category}, item, out[item_code]) + get_item_tax_template({"company": company, "tax_category": tax_category}, item, out[item_code]) out[item_code]["item_tax_rate"] = get_item_tax_map(company, out[item_code].get("item_tax_template"), as_json=True) return out @@ -442,7 +448,8 @@ def _get_item_tax_template(args, taxes, out={}, for_validate=False): taxes_with_no_validity = [] for tax in taxes: - if tax.valid_from: + tax_company = frappe.get_value("Item Tax Template", tax.item_tax_template, 'company') + if tax.valid_from and tax_company == args['company']: # In purchase Invoice first preference will be given to supplier invoice date # if supplier date is not present then posting date validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date') @@ -450,7 +457,8 @@ def _get_item_tax_template(args, taxes, out={}, for_validate=False): if getdate(tax.valid_from) <= getdate(validation_date): taxes_with_validity.append(tax) else: - taxes_with_no_validity.append(tax) + if tax_company == args['company']: + taxes_with_no_validity.append(tax) if taxes_with_validity: taxes = sorted(taxes_with_validity, key = lambda i: i.valid_from, reverse=True) @@ -637,6 +645,10 @@ def get_item_price(args, item_code, ignore_party=False): conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')""" + if args.get('posting_date'): + conditions += """ and %(posting_date)s between + ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')""" + return frappe.db.sql(""" select name, price_list_rate, uom from `tabItem Price` {conditions} order by valid_from desc, uom desc """.format(conditions=conditions), args) @@ -657,6 +669,7 @@ def get_price_list_rate_for(args, item_code): "supplier": args.get('supplier'), "uom": args.get('uom'), "transaction_date": args.get('transaction_date'), + "posting_date": args.get('posting_date'), } item_price_data = 0 diff --git a/erpnext/stock/module_onboarding/stock/stock.json b/erpnext/stock/module_onboarding/stock/stock.json index de24575a140..1d5bf8c97ca 100644 --- a/erpnext/stock/module_onboarding/stock/stock.json +++ b/erpnext/stock/module_onboarding/stock/stock.json @@ -19,7 +19,7 @@ "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/stock", "idx": 0, "is_complete": 0, - "modified": "2020-05-19 19:03:23.602423", + "modified": "2020-07-08 14:22:07.951891", "modified_by": "Administrator", "module": "Stock", "name": "Stock", @@ -31,15 +31,15 @@ { "step": "Create a Product" }, + { + "step": "Create a Supplier" + }, { "step": "Introduction to Stock Entry" }, { "step": "Create a Stock Entry" }, - { - "step": "Create a Supplier" - }, { "step": "Create a Purchase Receipt" }, @@ -47,8 +47,7 @@ "step": "Stock Settings" } ], - "subtitle": "Inventory, Warehouses, Analysis and more.", + "subtitle": "Inventory, Warehouses, Analysis, and more.", "success_message": "The Stock Module is all set up!", - "title": "Let's Setup the Stock Module.", - "user_can_dismiss": 1 + "title": "Let's Set Up the Stock Module." } \ No newline at end of file diff --git a/erpnext/stock/onboarding_step/setup_your_warehouse/setup_your_warehouse.json b/erpnext/stock/onboarding_step/setup_your_warehouse/setup_your_warehouse.json index 557c905bd6c..9457deee262 100644 --- a/erpnext/stock/onboarding_step/setup_your_warehouse/setup_your_warehouse.json +++ b/erpnext/stock/onboarding_step/setup_your_warehouse/setup_your_warehouse.json @@ -8,13 +8,13 @@ "is_mandatory": 0, "is_single": 0, "is_skipped": 0, - "modified": "2020-05-19 18:54:19.383397", + "modified": "2020-07-04 12:33:16.970031", "modified_by": "Administrator", "name": "Setup your Warehouse", "owner": "Administrator", "path": "Tree/Warehouse", "reference_document": "Warehouse", "show_full_form": 0, - "title": "Setup your Warehouse", + "title": "Set up your Warehouse", "validate_action": 1 } \ No newline at end of file diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index abf959eb0bf..a5f92e2c76c 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -4,10 +4,10 @@ from __future__ import unicode_literals import frappe +from frappe.utils import cint, flt from erpnext.stock.utils import update_included_uom_in_report from frappe import _ - def execute(filters=None): include_uom = filters.get("include_uom") columns = get_columns() @@ -15,6 +15,7 @@ def execute(filters=None): sl_entries = get_stock_ledger_entries(filters, items) item_details = get_item_details(items, sl_entries, include_uom) opening_row = get_opening_balance(filters, columns) + precision = cint(frappe.db.get_single_value("System Settings", "float_precision")) data = [] conversion_factors = [] @@ -29,7 +30,7 @@ def execute(filters=None): sle.update(item_detail) if filters.get("batch_no"): - actual_qty += sle.actual_qty + actual_qty += flt(sle.actual_qty, precision) stock_value += sle.stock_value_difference if sle.voucher_type == 'Stock Reconciliation': diff --git a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py index 6a86889aa3d..5873a7a3008 100644 --- a/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py +++ b/erpnext/stock/report/supplier_wise_sales_analytics/supplier_wise_sales_analytics.py @@ -21,7 +21,7 @@ def execute(filters=None): for cd in consumed_details.get(item_code): if (cd.voucher_no not in material_transfer_vouchers): - if cd.voucher_type=="Delivery Note": + if cd.voucher_type in ["Delivery Note", "Sales Invoice"]: delivered_qty += abs(flt(cd.actual_qty)) delivered_amount += abs(flt(cd.stock_value_difference)) elif cd.voucher_type!="Delivery Note": diff --git a/erpnext/support/doctype/issue/issue_list.js b/erpnext/support/doctype/issue/issue_list.js index 6d702f6bdf9..513a8dca222 100644 --- a/erpnext/support/doctype/issue/issue_list.js +++ b/erpnext/support/doctype/issue/issue_list.js @@ -8,11 +8,11 @@ frappe.listview_settings['Issue'] = { var method = "erpnext.support.doctype.issue.issue.set_multiple_status"; - listview.page.add_menu_item(__("Set as Open"), function() { + listview.page.add_action_item(__("Set as Open"), function() { listview.call_for_selected_items(method, {"status": "Open"}); }); - listview.page.add_menu_item(__("Set as Closed"), function() { + listview.page.add_action_item(__("Set as Closed"), function() { listview.call_for_selected_items(method, {"status": "Closed"}); }); }, diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py index c6923157064..70c469663b7 100644 --- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py +++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document from frappe import _ -from frappe.utils import getdate, get_weekdays +from frappe.utils import getdate, get_weekdays, get_link_to_form class ServiceLevelAgreement(Document): @@ -21,8 +21,8 @@ class ServiceLevelAgreement(Document): for priority in self.priorities: # Check if response and resolution time is set for every priority - if not (priority.response_time or priority.resolution_time): - frappe.throw(_("Set Response Time and Resolution for Priority {0} at index {1}.").format(priority.priority, priority.idx)) + if not priority.response_time or not priority.resolution_time: + frappe.throw(_("Set Response Time and Resolution Time for Priority {0} in row {1}.").format(priority.priority, priority.idx)) priorities.append(priority.priority) @@ -33,7 +33,7 @@ class ServiceLevelAgreement(Document): resolution = priority.resolution_time if response > resolution: - frappe.throw(_("Response Time for {0} at index {1} can't be greater than Resolution Time.").format(priority.priority, priority.idx)) + frappe.throw(_("Response Time for {0} priority in row {1} can't be greater than Resolution Time.").format(priority.priority, priority.idx)) # Check if repeated priority if not len(set(priorities)) == len(priorities): @@ -73,8 +73,9 @@ class ServiceLevelAgreement(Document): frappe.throw(_("Workday {0} has been repeated.").format(repeated_days)) def validate_doc(self): - if not frappe.db.get_single_value("Support Settings", "track_service_level_agreement"): - frappe.throw(_("Service Level Agreement tracking is not enabled.")) + if not frappe.db.get_single_value("Support Settings", "track_service_level_agreement") and self.enable: + frappe.throw(_("{0} is not enabled in {1}").format(frappe.bold("Track Service Level Agreement"), + get_link_to_form("Support Settings", "Support Settings"))) if self.default_service_level_agreement: if frappe.db.exists("Service Level Agreement", {"default_service_level_agreement": "1", "name": ["!=", self.name]}): diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py index 2359648c95c..c8e3330908f 100644 --- a/erpnext/utilities/transaction_base.py +++ b/erpnext/utilities/transaction_base.py @@ -120,6 +120,15 @@ class TransactionBase(StatusUpdater): def validate_rate_with_reference_doc(self, ref_details): + buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"] + + if self.doctype in buying_doctypes: + to_disable = "Maintain same rate throughout Purchase cycle" + settings_page = "Buying Settings" + else: + to_disable = "Maintain same rate throughout Sales cycle" + settings_page = "Selling Settings" + for ref_dt, ref_dn_field, ref_link_field in ref_details: for d in self.get("items"): if d.get(ref_link_field): @@ -129,8 +138,8 @@ class TransactionBase(StatusUpdater): frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ") .format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate)) frappe.throw(_("To allow different rates, disable the {0} checkbox in {1}.") - .format(frappe.bold(_("Maintain Same Rate Throughout Sales Cycle")), - get_link_to_form("Selling Settings", "Selling Settings", frappe.bold("Selling Settings")))) + .format(frappe.bold(_(to_disable)), + get_link_to_form(settings_page, settings_page, frappe.bold(settings_page)))) def get_link_filters(self, for_doctype): if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype): diff --git a/requirements.txt b/requirements.txt index 9da537e4933..912d61f7a6f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,10 +2,12 @@ braintree==3.57.1 frappe gocardless-pro==1.11.0 googlemaps==3.1.1 -pandas==0.24.2 +pandas==1.0.5 plaid-python==3.4.0 +pycountry==19.8.18 PyGithub==1.44.1 python-stdnum==1.12 +taxjar==1.9.0 +tweepy==3.8.0 Unidecode==1.1.1 WooCommerce==2.1.1 -tweepy==3.8.0 \ No newline at end of file