diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 32dde37df0..e822fda512 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -4,7 +4,7 @@ import inspect import frappe from erpnext.hooks import regional_overrides -__version__ = '9.1.3' +__version__ = '9.2.0' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/fr_plan_comptable_general.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/fr_plan_comptable_general.json index f6015f3744..018d368de4 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/fr_plan_comptable_general.json +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/fr_plan_comptable_general.json @@ -851,7 +851,7 @@ "4457-Taxes sur le chiffre d'affaires collect\u00e9es par l'entreprise": { "44571-TVA collect\u00e9e": { "account_type": "Tax", - "tax_rate": 20.0 + "is_group": 1 }, "44578-Taxes assimil\u00e9es \u00e0 la TVA": {} }, diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 42cd44aeab..002562f5b9 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -417,6 +417,46 @@ "share": 1, "submit": 0, "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 0, + "read": 1, + "report": 0, + "role": "Sales User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 0 + }, + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 0, + "read": 1, + "report": 0, + "role": "Purchase User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 0 } ], "quick_entry": 1, @@ -426,4 +466,4 @@ "sort_order": "ASC", "track_changes": 1, "track_seen": 0 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/asset/asset.js b/erpnext/accounts/doctype/asset/asset.js index 7c4eeae93a..e3afc359b6 100644 --- a/erpnext/accounts/doctype/asset/asset.js +++ b/erpnext/accounts/doctype/asset/asset.js @@ -55,13 +55,13 @@ frappe.ui.form.on('Asset', { }); } - frm.trigger("show_graph"); + frm.trigger("setup_chart"); } }, - show_graph: function(frm) { - var x_intervals = ["x", frm.doc.purchase_date]; - var asset_values = ["Asset Value", frm.doc.gross_purchase_amount]; + setup_chart: function(frm) { + var x_intervals = [frm.doc.purchase_date]; + var asset_values = [frm.doc.gross_purchase_amount]; var last_depreciation_date = frm.doc.purchase_date; if(frm.doc.opening_accumulated_depreciation) { @@ -94,32 +94,21 @@ frappe.ui.form.on('Asset', { last_depreciation_date = frm.doc.disposal_date; } - frm.dashboard.setup_chart({ + frm.dashboard.render_graph({ + title: "Asset Value", data: { - x: 'x', - columns: [x_intervals, asset_values], - regions: { - 'Asset Value': [{'start': last_depreciation_date, 'style':'dashed'}] - } + labels: x_intervals, + datasets: [{ + color: 'green', + values: asset_values, + formatted: asset_values.map(d => d.toFixed(2)) + }] }, - legend: { - show: false - }, - axis: { - x: { - type: 'timeseries', - tick: { - format: "%d-%m-%Y" - } - }, - y: { - min: 0, - padding: {bottom: 10} - } - } + type: 'line' }); }, + item_code: function(frm) { if(frm.doc.item_code) { frappe.call({ diff --git a/erpnext/accounts/doctype/asset/test_asset.py b/erpnext/accounts/doctype/asset/test_asset.py index 21596f1132..831373a9c9 100644 --- a/erpnext/accounts/doctype/asset/test_asset.py +++ b/erpnext/accounts/doctype/asset/test_asset.py @@ -13,6 +13,7 @@ class TestAsset(unittest.TestCase): def setUp(self): set_depreciation_settings_in_company() create_asset() + frappe.db.sql("delete from `tabTax Rule`") def test_purchase_asset(self): asset = frappe.get_doc("Asset", "Macbook Pro 1") diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index face5ede25..790003c301 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -54,7 +54,7 @@ class JournalEntry(AccountsController): def update_advance_paid(self): advance_paid = frappe._dict() for d in self.get("accounts"): - if d.is_advance: + if d.is_advance == "Yes": if d.reference_type in ("Sales Order", "Purchase Order"): advance_paid.setdefault(d.reference_type, []).append(d.reference_name) @@ -76,7 +76,7 @@ class JournalEntry(AccountsController): def unlink_advance_entry_reference(self): for d in self.get("accounts"): - if d.is_advance and d.reference_type in ("Sales Invoice", "Purchase Invoice"): + if d.is_advance == "Yes" and d.reference_type in ("Sales Invoice", "Purchase Invoice"): doc = frappe.get_doc(d.reference_type, d.reference_name) doc.delink_advance_entries(self.name) d.reference_type = '' diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 04db9e28ae..17ac1f7056 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -405,11 +405,7 @@ frappe.ui.form.on('Payment Entry', { } // Make read only if Accounts Settings doesn't allow stale rates - frappe.model.get_value("Accounts Settings", null, "allow_stale", - function(d){ - frm.set_df_property("source_exchange_rate", "read_only", cint(d.allow_stale) ? 0 : 1); - } - ); + frm.set_df_property("source_exchange_rate", "read_only", erpnext.stale_rate_allowed()); }, target_exchange_rate: function(frm) { @@ -430,11 +426,7 @@ frappe.ui.form.on('Payment Entry', { frm.set_paid_amount_based_on_received_amount = false; // Make read only if Accounts Settings doesn't allow stale rates - frappe.model.get_value("Accounts Settings", null, "allow_stale", - function(d){ - frm.set_df_property("target_exchange_rate", "read_only", cint(d.allow_stale) ? 0 : 1); - } - ); + frm.set_df_property("target_exchange_rate", "read_only", erpnext.stale_rate_allowed()); }, paid_amount: function(frm) { @@ -660,8 +652,15 @@ frappe.ui.form.on('Payment Entry', { var party_amount = frm.doc.payment_type=="Receive" ? frm.doc.paid_amount : frm.doc.received_amount; + var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [], + function(d) { return flt(d.amount) })); + if(frm.doc.total_allocated_amount < party_amount) { - unallocated_amount = party_amount - frm.doc.total_allocated_amount; + if(frm.doc.payment_type == "Receive") { + unallocated_amount = party_amount - (frm.doc.total_allocated_amount - total_deductions); + } else { + unallocated_amount = party_amount - (frm.doc.total_allocated_amount + total_deductions); + } } } frm.set_value("unallocated_amount", unallocated_amount); @@ -680,9 +679,6 @@ frappe.ui.form.on('Payment Entry', { difference_amount = flt(frm.doc.base_paid_amount) - flt(frm.doc.base_received_amount); } - var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [], - function(d) { return flt(d.amount) })); - frm.set_value("difference_amount", difference_amount - total_deductions); frm.events.hide_unhide_fields(frm); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 9d24261038..56bdfbaf4b 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -285,8 +285,13 @@ class PaymentEntry(AccountsController): if self.party: party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount + total_deductions = sum([flt(d.amount) for d in self.get("deductions")]) + if self.total_allocated_amount < party_amount: - self.unallocated_amount = party_amount - self.total_allocated_amount + if self.payment_type == "Receive": + self.unallocated_amount = party_amount - (self.total_allocated_amount - total_deductions) + else: + self.unallocated_amount = party_amount - (self.total_allocated_amount + total_deductions) def set_difference_amount(self): base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate) diff --git a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json index da17bb3fc8..03341da658 100644 --- a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json +++ b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json @@ -296,7 +296,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-09-04 17:37:01.192312", + "modified": "2017-10-16 17:37:01.192312", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry Reference", @@ -311,4 +311,4 @@ "sort_order": "DESC", "track_changes": 1, "track_seen": 0 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 57f9f832d0..83045eae4e 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -348,6 +348,8 @@ def apply_internal_priority(pricing_rules, field_set, args): return filtered_rules or pricing_rules def set_transaction_type(args): + if args.transaction_type: + return if args.doctype in ("Opportunity", "Quotation", "Sales Order", "Delivery Note", "Sales Invoice"): args.transaction_type = "selling" elif args.doctype in ("Material Request", "Supplier Quotation", "Purchase Order", @@ -356,4 +358,4 @@ def set_transaction_type(args): elif args.customer: args.transaction_type = "selling" else: - args.transaction_type = "buying" \ No newline at end of file + args.transaction_type = "buying" diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index e3c5fb4942..3d70b3b0b9 100755 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -3440,139 +3440,13 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "subscription", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Subscription", - "length": 0, - "no_copy": 1, - "options": "Subscription", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "is_recurring", - "columns": 0, - "depends_on": "eval:doc.docstatus<2 && !doc.__islocal", - "fieldname": "recurring_invoice", - "fieldtype": "Section Break", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Recurring Invoice", - "length": 0, - "no_copy": 0, - "options": "fa fa-time", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:doc.docstatus<2", - "description": "", - "fieldname": "is_recurring", - "fieldtype": "Check", - "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": "Is Recurring", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring==1", - "description": "Select the period when the invoice will be generated automatically", - "fieldname": "recurring_type", - "fieldtype": "Select", - "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": "Recurring Type", - "length": 0, - "no_copy": 1, - "options": "Monthly\nQuarterly\nHalf-yearly\nYearly", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring==1", + "depends_on": "", "description": "Start date of current invoice's period", "fieldname": "from_date", "fieldtype": "Date", @@ -3603,7 +3477,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:doc.is_recurring==1", + "depends_on": "", "description": "End date of current invoice's period", "fieldname": "to_date", "fieldtype": "Date", @@ -3628,138 +3502,13 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "fieldname": "submit_on_creation", - "fieldtype": "Check", - "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": "Submit on creation", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "notify_by_email", - "fieldtype": "Check", - "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": "Notify by email", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring==1", - "description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc", - "fieldname": "repeat_on_day_of_month", - "fieldtype": "Int", - "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": "Repeat on Day of Month", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring==1", - "description": "The date on which recurring invoice will be stop", - "fieldname": "end_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "End Date", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "column_break_82", + "fieldname": "column_break_114", "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, @@ -3771,101 +3520,8 @@ "length": 0, "no_copy": 0, "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "50%" - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring==1", - "description": "The date on which next invoice will be generated. It is generated on submit.", - "fieldname": "next_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Next Date", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring==1", - "description": "The unique id for tracking all recurring invoices. It is generated on submit.", - "fieldname": "recurring_id", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Recurring Id", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring==1", - "description": "Enter Email Address separated by commas, invoice will be mailed automatically on particular date", - "fieldname": "notification_email_address", - "fieldtype": "Small Text", - "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": "Notification Email Address", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, + "precision": "", + "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -3881,8 +3537,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:doc.is_recurring==1", - "fieldname": "recurring_print_format", + "fieldname": "subscription", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -3891,15 +3546,15 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Recurring Print Format", + "label": "Subscription", "length": 0, - "no_copy": 0, - "options": "Print Format", + "no_copy": 1, + "options": "Subscription", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -3920,7 +3575,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2017-09-19 11:22:47.074420", + "modified": "2017-10-24 12:51:51.199594", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice", diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index ccf8a84021..6856f62d0c 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.py +++ b/erpnext/accounts/doctype/sales_invoice/pos.py @@ -88,7 +88,7 @@ def update_pos_profile_data(doc, pos_profile, company_data): doc.naming_series = pos_profile.get('naming_series') or 'SINV-' doc.letter_head = pos_profile.get('letter_head') or company_data.default_letter_head doc.ignore_pricing_rule = pos_profile.get('ignore_pricing_rule') or 0 - doc.apply_discount_on = pos_profile.get('apply_discount_on') or '' + doc.apply_discount_on = pos_profile.get('apply_discount_on') or 'Grand Total' doc.customer_group = pos_profile.get('customer_group') or get_root('Customer Group') doc.territory = pos_profile.get('territory') or get_root('Territory') doc.terms = frappe.db.get_value('Terms and Conditions', pos_profile.get('tc_name'), 'terms') or doc.terms or '' @@ -486,17 +486,21 @@ def submit_invoice(si_doc, name, doc, name_list): if frappe.message_log: frappe.message_log.pop() frappe.db.rollback() frappe.log_error(frappe.get_traceback()) - name_list = save_invoice(e, si_doc, name, name_list) + name_list = save_invoice(doc, name, name_list) return name_list -def save_invoice(e, si_doc, name, name_list): +def save_invoice(doc, name, name_list): try: if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}): - si_doc.docstatus = 0 - si_doc.flags.ignore_mandatory = True - si_doc.due_date = si_doc.posting_date - si_doc.insert() + si = frappe.new_doc('Sales Invoice') + si.update(doc) + si.set_posting_time = 1 + si.customer = get_customer_id(doc) + si.due_date = doc.get('posting_date') + si.flags.ignore_mandatory = True + si.insert(ignore_permissions=True) + frappe.db.commit() name_list.append(name) except Exception: frappe.log_error(frappe.get_traceback()) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 9aa0e6b6a2..ecd7cf9069 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -4273,414 +4273,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "subscription", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Subscription", - "length": 0, - "no_copy": 1, - "options": "Subscription", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "is_recurring", - "columns": 0, - "depends_on": "eval:doc.docstatus<2 && !doc.__islocal", - "fieldname": "recurring_invoice", - "fieldtype": "Section Break", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Recurring Invoice", - "length": 0, - "no_copy": 0, - "options": "fa fa-time", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break11", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Settings", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "50%" - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.docstatus<2", - "description": "", - "fieldname": "is_recurring", - "fieldtype": "Check", - "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": "Is Recurring", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_recurring", - "description": "", - "fieldname": "recurring_id", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reference Document", - "length": 0, - "no_copy": 1, - "options": "Sales Invoice", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "recurring_type", - "fieldtype": "Select", - "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": "Frequency", - "length": 0, - "no_copy": 1, - "options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "repeat_on_day_of_month", - "fieldtype": "Int", - "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": "Repeat on Day of Month", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "end_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "End Date", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "fieldname": "submit_on_creation", - "fieldtype": "Check", - "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": "Submit on creation", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "notify_by_email", - "fieldtype": "Check", - "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": "Notify by email", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.notify_by_email && doc.recurring_id === doc.name", - "description": "", - "fieldname": "notification_email_address", - "fieldtype": "Code", - "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": "Notification Email Address", - "length": 0, - "no_copy": 1, - "options": "Email", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.notify_by_email && doc.recurring_id === doc.name", - "fieldname": "recurring_print_format", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Recurring Print Format", - "length": 0, - "no_copy": 0, - "options": "Print Format", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break12", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "This Document", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, - "width": "50%" - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_recurring", + "depends_on": "", "description": "", "fieldname": "from_date", "fieldtype": "Date", @@ -4711,7 +4304,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "is_recurring", + "depends_on": "", "description": "", "fieldname": "to_date", "fieldtype": "Date", @@ -4742,10 +4335,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "is_recurring", - "description": "", - "fieldname": "next_date", - "fieldtype": "Date", + "fieldname": "column_break_140", + "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -4753,11 +4344,11 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Next Date", "length": 0, - "no_copy": 1, + "no_copy": 0, "permlevel": 0, - "print_hide": 1, + "precision": "", + "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -4767,6 +4358,37 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "subscription", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Subscription", + "length": 0, + "no_copy": 1, + "options": "Subscription", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -4811,7 +4433,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2017-09-19 11:23:08.675028", + "modified": "2017-10-24 12:46:48.331723", "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 6ab614863b..1c4fe3d084 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -70,6 +70,7 @@ class SalesInvoice(SellingController): self.clear_unallocated_advances("Sales Invoice Advance", "advances") self.add_remarks() self.validate_write_off_account() + self.validate_duplicate_offline_pos_entry() self.validate_account_for_change_amount() self.validate_fixed_asset() self.set_income_account_for_fixed_assets() @@ -462,6 +463,12 @@ class SalesInvoice(SellingController): if flt(self.write_off_amount) and not self.write_off_account: msgprint(_("Please enter Write Off Account"), raise_exception=1) + def validate_duplicate_offline_pos_entry(self): + if self.is_pos and self.offline_pos_name \ + and frappe.db.get_value('Sales Invoice', + {'offline_pos_name': self.offline_pos_name, 'docstatus': 1}): + frappe.throw(_("Duplicate offline pos sales invoice {0}").format(self.offline_pos_name)) + def validate_account_for_change_amount(self): if flt(self.change_amount) and not self.account_for_change_amount: msgprint(_("Please enter Account for Change Amount"), raise_exception=1) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 900a6e9d95..264f027486 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -3,8 +3,8 @@ from __future__ import unicode_literals import frappe -import unittest, copy -from frappe.utils import nowdate, add_days, flt +import unittest, copy, time +from frappe.utils import nowdate, add_days, flt, cint from frappe.model.dynamic_links import get_dynamic_link_map from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import unlink_payment_on_cancel_of_invoice @@ -665,6 +665,47 @@ class TestSalesInvoice(unittest.TestCase): self.pos_gl_entry(si, pos, 330) + def test_make_pos_invoice_in_draft(self): + from erpnext.accounts.doctype.sales_invoice.pos import make_invoice + from erpnext.stock.doctype.item.test_item import make_item + + set_perpetual_inventory() + + allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock') + if allow_negative_stock: + frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 0) + + make_pos_profile() + timestamp = cint(time.time()) + + item = make_item("_Test POS Item") + pos = copy.deepcopy(test_records[1]) + pos['items'][0]['item_code'] = item.name + pos["is_pos"] = 1 + pos["offline_pos_name"] = timestamp + pos["update_stock"] = 1 + pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300}, + {'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 330}] + + invoice_data = [{timestamp: pos}] + si = make_invoice(invoice_data).get('invoice') + self.assertEquals(si[0], timestamp) + + sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': timestamp}) + self.assertEquals(sales_invoice[0].docstatus, 0) + + timestamp = cint(time.time()) + pos["offline_pos_name"] = timestamp + invoice_data = [{timestamp: pos}] + si1 = make_invoice(invoice_data).get('invoice') + self.assertEquals(si1[0], timestamp) + + sales_invoice1 = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': timestamp}) + self.assertEquals(sales_invoice1[0].docstatus, 0) + + if allow_negative_stock: + frappe.db.set_value('Stock Settings', None, 'allow_negative_stock', 1) + def pos_gl_entry(self, si, pos, cash_amount): # check stock ledger entries sle = frappe.db.sql("""select * from `tabStock Ledger Entry` diff --git a/erpnext/accounts/doctype/subscription/subscription.js b/erpnext/accounts/doctype/subscription/subscription.js index 15927d5961..8db5be8772 100644 --- a/erpnext/accounts/doctype/subscription/subscription.js +++ b/erpnext/accounts/doctype/subscription/subscription.js @@ -12,7 +12,8 @@ frappe.ui.form.on('Subscription', { frm.fields_dict['reference_document'].get_query = function() { return { filters: { - "docstatus": 1 + "docstatus": 1, + "subscription": '' } }; }; diff --git a/erpnext/accounts/doctype/subscription/subscription.json b/erpnext/accounts/doctype/subscription/subscription.json index dfdcbecb43..7ff2e4b632 100644 --- a/erpnext/accounts/doctype/subscription/subscription.json +++ b/erpnext/accounts/doctype/subscription/subscription.json @@ -315,22 +315,23 @@ }, { "allow_bulk_edit": 0, - "allow_on_submit": 1, + "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "from_date", - "fieldtype": "Date", + "fieldname": "frequency", + "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, - "label": "From Date", + "label": "Frequency", "length": 0, "no_copy": 0, + "options": "\nDaily\nWeekly\nMonthly\nQuarterly\nHalf-yearly\nYearly", "permlevel": 0, "precision": "", "print_hide": 0, @@ -338,37 +339,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "to_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "To Date", - "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, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -402,37 +373,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "frequency", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Frequency", - "length": 0, - "no_copy": 0, - "options": "\nDaily\nWeekly\nMonthly\nQuarterly\nHalf-yearly\nYearly", - "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 - }, { "allow_bulk_edit": 0, "allow_on_submit": 1, @@ -844,7 +784,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-10-03 17:20:26.919630", + "modified": "2017-10-23 18:28:08.966403", "modified_by": "Administrator", "module": "Accounts", "name": "Subscription", diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py index b40169a36c..fb01efe13b 100644 --- a/erpnext/accounts/doctype/subscription/subscription.py +++ b/erpnext/accounts/doctype/subscription/subscription.py @@ -17,6 +17,7 @@ month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12} class Subscription(Document): def validate(self): self.update_status() + self.validate_reference_doctype() self.validate_dates() self.validate_next_schedule_date() self.validate_email_id() @@ -25,25 +26,28 @@ class Subscription(Document): validate_template(self.message or "") def before_submit(self): - self.set_next_schedule_date() + if not self.next_schedule_date: + self.next_schedule_date = get_next_schedule_date(self.start_date, + self.frequency, self.repeat_on_day) def on_submit(self): - # self.update_subscription_id() - self.update_subscription_data() + self.update_subscription_id() def on_update_after_submit(self): - self.update_subscription_data() self.validate_dates() self.set_next_schedule_date() def before_cancel(self): self.unlink_subscription_id() + self.next_schedule_date = None def unlink_subscription_id(self): - doc = frappe.get_doc(self.reference_doctype, self.reference_document) - if doc.meta.get_field('subscription'): - doc.subscription = None - doc.db_update() + frappe.db.sql("update `tab{0}` set subscription = null where subscription=%s" + .format(self.reference_doctype), self.name) + + def validate_reference_doctype(self): + if not frappe.get_meta(self.reference_doctype).has_field('subscription'): + frappe.throw(_("Add custom field Subscription in the doctype {0}").format(self.reference_doctype)) def validate_dates(self): if self.end_date and getdate(self.start_date) > getdate(self.end_date): @@ -76,30 +80,11 @@ class Subscription(Document): frappe.throw(_("'Recipients' not specified")) def set_next_schedule_date(self): - self.next_schedule_date = get_next_schedule_date(self.start_date, - self.frequency, self.repeat_on_day) - - def update_subscription_data(self): - update_doc = False - doc = frappe.get_doc(self.reference_doctype, self.reference_document) - if frappe.get_meta(self.reference_doctype).get_field("from_date"): - doc.from_date = self.from_date - doc.to_date = self.to_date - update_doc = True - - if not doc.subscription: - doc.subscription = self.name - update_doc = True - - if update_doc: - doc.db_update() + if self.repeat_on_day: + self.next_schedule_date = get_next_date(self.next_schedule_date, 0, self.repeat_on_day) def update_subscription_id(self): - doc = frappe.get_doc(self.reference_doctype, self.reference_document) - if not doc.meta.get_field('subscription'): - frappe.throw(_("Add custom field Subscription Id in the doctype {0}").format(self.reference_doctype)) - - doc.db_set('subscription', self.name) + frappe.db.set_value(self.reference_doctype, self.reference_document, "subscription", self.name) def update_status(self, status=None): self.status = { @@ -142,9 +127,6 @@ def get_subscription_entries(date): def create_documents(data, schedule_date): try: doc = make_new_document(data, schedule_date) - if getattr(doc, "from_date", None): - update_subscription_period(data, doc) - if data.notify_by_email and data.recipients: print_format = data.print_format or "Standard" send_notification(doc, data, print_format=print_format) @@ -159,13 +141,6 @@ def create_documents(data, schedule_date): if data.reference_document and not frappe.flags.in_test: notify_error_to_user(data) -def update_subscription_period(data, doc): - from_date = doc.from_date - to_date = doc.to_date - - frappe.db.set_value('Subscription', data.name, 'from_date', from_date) - frappe.db.set_value('Subscription', data.name, 'to_date', to_date) - def disable_subscription(data): subscription = frappe.get_doc('Subscription', data.name) subscription.db_set('disabled', 1) @@ -205,24 +180,49 @@ def update_doc(new_document, reference_doc, args, schedule_date): if new_document.meta.get_field('subscription'): new_document.set('subscription', args.name) - if args.from_date and args.to_date: - from_date = get_next_date(args.from_date, mcount) + for fieldname in ['naming_series', 'ignore_pricing_rule', 'posting_time' + 'select_print_heading', 'remarks', 'owner']: + if new_document.meta.get_field(fieldname): + new_document.set(fieldname, reference_doc.get(fieldname)) - if (cstr(get_first_day(args.from_date)) == cstr(args.from_date)) and \ - (cstr(get_last_day(args.to_date)) == cstr(args.to_date)): - to_date = get_last_day(get_next_date(args.to_date, mcount)) - else: - to_date = get_next_date(args.to_date, mcount) + # copy item fields + if new_document.meta.get_field('items'): + for i, item in enumerate(new_document.items): + for fieldname in ("page_break",): + item.set(fieldname, reference_doc.items[i].get(fieldname)) - if new_document.meta.get_field('from_date'): - new_document.set('from_date', from_date) - new_document.set('to_date', to_date) - - new_document.run_method("on_recurring", reference_doc=reference_doc, subscription_doc=args) for data in new_document.meta.fields: if data.fieldtype == 'Date' and data.reqd: new_document.set(data.fieldname, schedule_date) + set_subscription_period(args, mcount, new_document) + + new_document.run_method("on_recurring", reference_doc=reference_doc, subscription_doc=args) + +def set_subscription_period(args, mcount, new_document): + if new_document.meta.get_field('from_date') and new_document.meta.get_field('to_date'): + last_ref_doc = frappe.db.sql(""" + select name, from_date, to_date + from `tab{0}` + where subscription=%s and docstatus < 2 + order by creation desc + limit 1 + """.format(args.reference_doctype), args.name, as_dict=1) + + if not last_ref_doc: + return + + from_date = get_next_date(last_ref_doc[0].from_date, mcount) + + if (cstr(get_first_day(last_ref_doc[0].from_date)) == cstr(last_ref_doc[0].from_date)) and \ + (cstr(get_last_day(last_ref_doc[0].to_date)) == cstr(last_ref_doc[0].to_date)): + to_date = get_last_day(get_next_date(last_ref_doc[0].to_date, mcount)) + else: + to_date = get_next_date(last_ref_doc[0].to_date, mcount) + + new_document.set('from_date', from_date) + new_document.set('to_date', to_date) + def get_next_date(dt, mcount, day=None): dt = getdate(dt) dt += relativedelta(months=mcount, day=day) @@ -276,8 +276,11 @@ def assign_task_to_owner(name, msg, users): @frappe.whitelist() def make_subscription(doctype, docname): doc = frappe.new_doc('Subscription') + + reference_doc = frappe.get_doc(doctype, docname) doc.reference_doctype = doctype doc.reference_document = docname + doc.start_date = reference_doc.get('posting_date') or reference_doc.get('transaction_date') return doc @frappe.whitelist() diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py index b74163c92e..4ccf483c1a 100644 --- a/erpnext/accounts/doctype/subscription/test_subscription.py +++ b/erpnext/accounts/doctype/subscription/test_subscription.py @@ -30,7 +30,7 @@ class TestSubscription(unittest.TestCase): new_quotation = frappe.get_doc('Quotation', new_quotation) - for fieldname in ['customer', 'company', 'order_type', 'total', 'grand_total']: + for fieldname in ['customer', 'company', 'order_type', 'total', 'net_total']: self.assertEquals(quotation.get(fieldname), new_quotation.get(fieldname)) for fieldname in ['item_code', 'qty', 'rate', 'amount']: diff --git a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py index 5ad7970a6e..ee5b3c9d6a 100644 --- a/erpnext/accounts/doctype/tax_rule/test_tax_rule.py +++ b/erpnext/accounts/doctype/tax_rule/test_tax_rule.py @@ -11,7 +11,10 @@ test_records = frappe.get_test_records('Tax Rule') class TestTaxRule(unittest.TestCase): def setUp(self): - frappe.db.sql("delete from `tabTax Rule` where use_for_shopping_cart <> 1") + frappe.db.sql("delete from `tabTax Rule`") + + def tearDown(self): + frappe.db.sql("delete from `tabTax Rule`") def test_conflict(self): tax_rule1 = make_tax_rule(customer= "_Test Customer", diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js index 57a8a186b9..c442062ab6 100644 --- a/erpnext/accounts/page/pos/pos.js +++ b/erpnext/accounts/page/pos/pos.js @@ -84,6 +84,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.get_data_from_server(function () { me.make_control(); me.create_new(); + me.make(); }); }, @@ -382,7 +383,6 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }, setup: function () { - this.make(); this.set_primary_action(); this.party_field.$input.attr('disabled', false); if(this.selected_row) { @@ -1341,6 +1341,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.wrapper.find('input.discount-percentage').on("change", function () { me.frm.doc.additional_discount_percentage = flt($(this).val(), precision("additional_discount_percentage")); + + if(me.frm.doc.additional_discount_percentage && me.frm.doc.discount_amount) { + // Reset discount amount + me.frm.doc.discount_amount = 0; + } + var total = me.frm.doc.grand_total if (me.frm.doc.apply_discount_on == 'Net Total') { @@ -1348,15 +1354,15 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ } me.frm.doc.discount_amount = flt(total * flt(me.frm.doc.additional_discount_percentage) / 100, precision("discount_amount")); - me.wrapper.find('input.discount-amount').val(me.frm.doc.discount_amount) me.refresh(); + me.wrapper.find('input.discount-amount').val(me.frm.doc.discount_amount) }); this.wrapper.find('input.discount-amount').on("change", function () { me.frm.doc.discount_amount = flt($(this).val(), precision("discount_amount")); me.frm.doc.additional_discount_percentage = 0.0; - me.wrapper.find('input.discount-percentage').val(0); me.refresh(); + me.wrapper.find('input.discount-percentage').val(0); }); }, @@ -1517,6 +1523,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ var me = this; this.wrapper.find(".net-total").text(format_currency(me.frm.doc.total, me.frm.doc.currency)); this.wrapper.find(".grand-total").text(format_currency(me.frm.doc.grand_total, me.frm.doc.currency)); + this.wrapper.find('input.discount-percentage').val(this.frm.doc.additional_discount_percentage); + this.wrapper.find('input.discount-amount').val(this.frm.doc.discount_amount); }, set_primary_action: function () { diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index bcec0a29c9..ce049f5d87 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -76,7 +76,7 @@ def set_address_details(out, party, party_type, doctype=None, company=None): # shipping address if party_type in ["Customer", "Lead"]: - out.shipping_address_name = get_default_address(party_type, party.name, 'is_shipping_address') + out.shipping_address_name = get_party_shipping_address(party_type, party.name) out.shipping_address = get_address_display(out["shipping_address_name"]) if doctype: out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name)) @@ -418,3 +418,32 @@ def get_dashboard_info(party_type, party): info["total_unpaid"] = -1 * info["total_unpaid"] return info + + +def get_party_shipping_address(doctype, name): + """ + Returns an Address name (best guess) for the given doctype and name for which `address_type == 'Shipping'` is true. + and/or `is_shipping_address = 1`. + + It returns an empty string if there is no matching record. + + :param doctype: Party Doctype + :param name: Party name + :return: String + """ + out = frappe.db.sql( + 'SELECT dl.parent ' + 'from `tabDynamic Link` dl join `tabAddress` ta on dl.parent=ta.name ' + 'where ' + 'dl.link_doctype=%s ' + 'and dl.link_name=%s ' + 'and dl.parenttype="Address" ' + 'and ' + '(ta.address_type="Shipping" or ta.is_shipping_address=1) ' + 'order by ta.is_shipping_address desc, ta.address_type desc limit 1', + (doctype, name) + ) + if out: + return out[0][0] + else: + return '' diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 9906893254..56db392800 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -44,7 +44,7 @@ class ReceivablePayableReport(object): }) columns += [_("Age (Days)") + ":Int:80"] - + self.ageing_col_idx_start = len(columns) if not "range1" in self.filters: @@ -53,7 +53,7 @@ class ReceivablePayableReport(object): self.filters["range2"] = "60" if not "range3" in self.filters: self.filters["range3"] = "90" - + for label in ("0-{range1}".format(range1=self.filters["range1"]), "{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]), "{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]), @@ -74,14 +74,14 @@ class ReceivablePayableReport(object): }) if args.get("party_type") == "Customer": columns += [ - _("Territory") + ":Link/Territory:80", + _("Territory") + ":Link/Territory:80", _("Customer Group") + ":Link/Customer Group:120" ] if args.get("party_type") == "Supplier": columns += [_("Supplier Type") + ":Link/Supplier Type:80"] - + columns.append(_("Remarks") + "::200") - + return columns def get_data(self, party_naming_by, args): @@ -97,13 +97,13 @@ class ReceivablePayableReport(object): self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company') company_currency = frappe.db.get_value("Company", self.filters.get("company"), "default_currency") - + return_entries = self.get_return_entries(args.get("party_type")) data = [] for gle in self.get_entries_till(self.filters.report_date, args.get("party_type")): if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers): - outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle, + outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle, self.filters.report_date, dr_or_cr, return_entries, currency_precision) if abs(outstanding_amount) > 0.1/10**currency_precision: row = [gle.posting_date, gle.party] @@ -179,15 +179,15 @@ class ReceivablePayableReport(object): # entries adjusted with future vouchers ((gle.against_voucher_type, gle.against_voucher) in future_vouchers) ) - + def get_return_entries(self, party_type): doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice" - return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})] + return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})] def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries, currency_precision): payment_amount, credit_note_amount = 0.0, 0.0 reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit" - + for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no): if getdate(e.posting_date) <= report_date and e.name!=gle.name: amount = flt(e.get(reverse_dr_or_cr)) - flt(e.get(dr_or_cr)) @@ -195,11 +195,11 @@ class ReceivablePayableReport(object): payment_amount += amount else: credit_note_amount += amount - + outstanding_amount = flt((flt(gle.get(dr_or_cr)) - flt(gle.get(reverse_dr_or_cr)) \ - payment_amount - credit_note_amount), currency_precision) credit_note_amount = flt(credit_note_amount, currency_precision) - + return outstanding_amount, credit_note_amount def get_party_name(self, party_type, party_name): @@ -207,7 +207,7 @@ class ReceivablePayableReport(object): def get_territory(self, party_name): return self.get_party_map("Customer").get(party_name, {}).get("territory") or "" - + def get_customer_group(self, party_name): return self.get_party_map("Customer").get(party_name, {}).get("customer_group") or "" @@ -220,7 +220,7 @@ class ReceivablePayableReport(object): select_fields = "name, customer_name, territory, customer_group" elif party_type == "Supplier": select_fields = "name, supplier_name, supplier_type" - + self.party_map = dict(((r.name, r) for r in frappe.db.sql("select {0} from `tab{1}`" .format(select_fields, party_type), as_dict=True))) @@ -250,8 +250,8 @@ class ReceivablePayableReport(object): else: select_fields = "sum(debit) as debit, sum(credit) as credit" - self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party, - voucher_type, voucher_no, against_voucher_type, against_voucher, + self.gl_entries = frappe.db.sql("""select name, posting_date, account, party_type, party, + voucher_type, voucher_no, against_voucher_type, against_voucher, account_currency, remarks, {0} from `tabGL Entry` where docstatus < 2 and party_type=%s and (party is not null and party != '') {1} @@ -277,13 +277,13 @@ class ReceivablePayableReport(object): if party_type_field=="customer": if self.filters.get("customer_group"): - lft, rgt = frappe.db.get_value("Customer Group", + lft, rgt = frappe.db.get_value("Customer Group", self.filters.get("customer_group"), ["lft", "rgt"]) - - conditions.append("""party in (select name from tabCustomer - where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1} + + conditions.append("""party in (select name from tabCustomer + where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1} and name=tabCustomer.customer_group))""".format(lft, rgt)) - + if self.filters.get("credit_days_based_on"): conditions.append("party in (select name from tabCustomer where credit_days_based_on=%s)") values.append(self.filters.get("credit_days_based_on")) @@ -303,22 +303,22 @@ class ReceivablePayableReport(object): return self.gl_entries_map.get(party, {})\ .get(against_voucher_type, {})\ .get(against_voucher, []) - + def get_chart_data(self, columns, data): ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+4] - + rows = [] for d in data: rows.append(d[self.ageing_col_idx_start : self.ageing_col_idx_start+4]) if rows: rows.insert(0, [[d.get("label")] for d in ageing_columns]) - + return { "data": { - 'rows': rows + 'labels': rows }, - "chart_type": 'pie' + "type": 'percentage' } def execute(filters=None): diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py index 2db4ef8a26..18b07ea582 100644 --- a/erpnext/accounts/report/balance_sheet/balance_sheet.py +++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py @@ -8,18 +8,18 @@ from frappe.utils import flt, cint from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data) def execute(filters=None): - period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, + period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.periodicity, company=filters.company) - asset = get_data(filters.company, "Asset", "Debit", period_list, + asset = get_data(filters.company, "Asset", "Debit", period_list, only_current_fiscal_year=False, filters=filters, accumulated_values=filters.accumulated_values) - - liability = get_data(filters.company, "Liability", "Credit", period_list, + + liability = get_data(filters.company, "Liability", "Credit", period_list, only_current_fiscal_year=False, filters=filters, accumulated_values=filters.accumulated_values) - - equity = get_data(filters.company, "Equity", "Credit", period_list, + + equity = get_data(filters.company, "Equity", "Credit", period_list, only_current_fiscal_year=False, filters=filters, accumulated_values=filters.accumulated_values) @@ -43,17 +43,17 @@ def execute(filters=None): unclosed[period.key] = opening_balance if provisional_profit_loss: provisional_profit_loss[period.key] = provisional_profit_loss[period.key] - opening_balance - + unclosed["total"]=opening_balance data.append(unclosed) - + if provisional_profit_loss: data.append(provisional_profit_loss) if total_credit: - data.append(total_credit) + data.append(total_credit) columns = get_columns(filters.periodicity, period_list, filters.accumulated_values, company=filters.company) - + chart = get_chart_data(filters, columns, asset, liability, equity) return columns, data, message, chart @@ -87,7 +87,7 @@ def get_provisional_profit_loss(asset, liability, equity, period_list, company): total += flt(provisional_profit_loss[period.key]) provisional_profit_loss["total"] = total - + total_row_total += flt(total_row[period.key]) total_row["total"] = total_row_total @@ -98,7 +98,7 @@ def get_provisional_profit_loss(asset, liability, equity, period_list, company): "warn_if_negative": True, "currency": currency }) - + return provisional_profit_loss, total_row def check_opening_balance(asset, liability, equity): @@ -111,17 +111,17 @@ def check_opening_balance(asset, liability, equity): opening_balance -= flt(liability[0].get("opening_balance", 0), float_precision) if equity: opening_balance -= flt(equity[0].get("opening_balance", 0), float_precision) - + opening_balance = flt(opening_balance, float_precision) if opening_balance: return _("Previous Financial Year is not closed"),opening_balance return None,None - + def get_chart_data(filters, columns, asset, liability, equity): - x_intervals = ['x'] + [d.get("label") for d in columns[2:]] - + labels = [d.get("label") for d in columns[2:]] + asset_data, liability_data, equity_data = [], [], [] - + for p in columns[2:]: if asset: asset_data.append(asset[-2].get(p.get("fieldname"))) @@ -129,23 +129,25 @@ def get_chart_data(filters, columns, asset, liability, equity): liability_data.append(liability[-2].get(p.get("fieldname"))) if equity: equity_data.append(equity[-2].get(p.get("fieldname"))) - - columns = [x_intervals] + + datasets = [] if asset_data: - columns.append(["Assets"] + asset_data) + datasets.append({'title':'Assets', 'values': asset_data}) if liability_data: - columns.append(["Liabilities"] + liability_data) + datasets.append({'title':'Liabilities', 'values': liability_data}) if equity_data: - columns.append(["Equity"] + equity_data) + datasets.append({'title':'Equity', 'values': equity_data}) chart = { "data": { - 'x': 'x', - 'columns': columns + 'labels': labels, + 'datasets': datasets } } if not filters.accumulated_values: - chart["chart_type"] = "bar" + chart["type"] = "bar" + else: + chart["type"] = "line" return chart \ No newline at end of file diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 07f6979c40..78e3faab4e 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -107,6 +107,8 @@ class GrossProfitGenerator(object): def process(self): self.grouped = {} + self.grouped_data = [] + for row in self.si_list: if self.skip_row(row, self.product_bundles): continue @@ -150,7 +152,6 @@ class GrossProfitGenerator(object): def get_average_rate_based_on_group_by(self): # sum buying / selling totals for group - self.grouped_data = [] for key in self.grouped.keys(): if self.filters.get("group_by") != "Invoice": for i, row in enumerate(self.grouped[key]): diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py index 6729d672c0..89ee63aa64 100644 --- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py +++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py @@ -8,15 +8,15 @@ from frappe.utils import flt from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data) def execute(filters=None): - period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, + period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.periodicity, filters.accumulated_values, filters.company) income = get_data(filters.company, "Income", "Credit", period_list, filters = filters, - accumulated_values=filters.accumulated_values, + accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True) - + expense = get_data(filters.company, "Expense", "Debit", period_list, filters=filters, - accumulated_values=filters.accumulated_values, + accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True) net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company) @@ -61,7 +61,7 @@ def get_net_profit_loss(income, expense, period_list, company): def get_chart_data(filters, columns, income, expense, net_profit_loss): - x_intervals = ['x'] + [d.get("label") for d in columns[2:]] + labels = [d.get("label") for d in columns[2:]] income_data, expense_data, net_profit = [], [], [] @@ -73,27 +73,24 @@ def get_chart_data(filters, columns, income, expense, net_profit_loss): if net_profit_loss: net_profit.append(net_profit_loss.get(p.get("fieldname"))) - columns = [x_intervals] + datasets = [] if income_data: - columns.append(["Income"] + income_data) + datasets.append({'title': 'Income', 'values': income_data}) if expense_data: - columns.append(["Expense"] + expense_data) + datasets.append({'title': 'Expense', 'values': expense_data}) if net_profit: - columns.append(["Net Profit/Loss"] + net_profit) + datasets.append({'title': 'Net Profit/Loss', 'values': net_profit}) chart = { "data": { - 'x': 'x', - 'columns': columns, - 'colors': { - 'Income': '#5E64FF', - 'Expense': '#b8c2cc', - 'Net Profit/Loss': '#ff5858' - } + 'labels': labels, + 'datasets': datasets } } if not filters.accumulated_values: - chart["chart_type"] = "bar" + chart["type"] = "bar" + else: + chart["type"] = "line" return chart \ No newline at end of file diff --git a/erpnext/docs/user/manual/en/subscription/__init__.py b/erpnext/accounts/test/__init__.py similarity index 100% rename from erpnext/docs/user/manual/en/subscription/__init__.py rename to erpnext/accounts/test/__init__.py diff --git a/erpnext/accounts/test/test_utils.py b/erpnext/accounts/test/test_utils.py new file mode 100644 index 0000000000..0fca470fe5 --- /dev/null +++ b/erpnext/accounts/test/test_utils.py @@ -0,0 +1,84 @@ +import unittest +from erpnext.accounts.party import get_party_shipping_address +from frappe.test_runner import make_test_objects + + +class TestUtils(unittest.TestCase): + @classmethod + def setUpClass(cls): + super(TestUtils, cls).setUpClass() + make_test_objects('Address', ADDRESS_RECORDS) + + def test_get_party_shipping_address(self): + address = get_party_shipping_address('Customer', '_Test Customer 1') + self.assertEqual(address, '_Test Billing Address 2 Title-Billing') + + def test_get_party_shipping_address2(self): + address = get_party_shipping_address('Customer', '_Test Customer 2') + self.assertEqual(address, '_Test Shipping Address 2 Title-Shipping') + + +ADDRESS_RECORDS = [ + { + "doctype": "Address", + "address_type": "Billing", + "address_line1": "Address line 1", + "address_title": "_Test Billing Address Title", + "city": "Lagos", + "country": "Nigeria", + "links": [ + { + "link_doctype": "Customer", + "link_name": "_Test Customer 2", + "doctype": "Dynamic Link" + } + ] + }, + { + "doctype": "Address", + "address_type": "Shipping", + "address_line1": "Address line 2", + "address_title": "_Test Shipping Address 1 Title", + "city": "Lagos", + "country": "Nigeria", + "links": [ + { + "link_doctype": "Customer", + "link_name": "_Test Customer 2", + "doctype": "Dynamic Link" + } + ] + }, + { + "doctype": "Address", + "address_type": "Shipping", + "address_line1": "Address line 3", + "address_title": "_Test Shipping Address 2 Title", + "city": "Lagos", + "country": "Nigeria", + "is_shipping_address": "1", + "links": [ + { + "link_doctype": "Customer", + "link_name": "_Test Customer 2", + "doctype": "Dynamic Link" + } + ] + }, + { + "doctype": "Address", + "address_type": "Billing", + "address_line1": "Address line 4", + "address_title": "_Test Billing Address 2 Title", + "city": "Lagos", + "country": "Nigeria", + "is_shipping_address": "1", + "links": [ + { + "link_doctype": "Customer", + "link_name": "_Test Customer 1", + "doctype": "Dynamic Link" + } + ] + } +] diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 28b8b475c2..534af8bfc5 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -2948,418 +2948,13 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "subscription", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Subscription", - "length": 0, - "no_copy": 1, - "options": "Subscription", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "is_recurring", - "columns": 0, - "depends_on": "eval:doc.docstatus<2 && !doc.__islocal", - "fieldname": "recurring_order", - "fieldtype": "Section Break", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Recurring Order", - "length": 0, - "no_copy": 0, - "options": "fa fa-time", - "permlevel": 0, - "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Settings", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "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 - }, { "allow_bulk_edit": 0, "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "eval:doc.docstatus<2", - "description": "", - "fieldname": "is_recurring", - "fieldtype": "Check", - "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": "Is Recurring", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_recurring", - "description": "", - "fieldname": "recurring_id", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reference Document", - "length": 0, - "no_copy": 1, - "options": "Purchase Order", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "recurring_type", - "fieldtype": "Select", - "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": "Frequency", - "length": 0, - "no_copy": 1, - "options": "Monthly\nQuarterly\nHalf-yearly\nYearly", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "repeat_on_day_of_month", - "fieldtype": "Int", - "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": "Repeat on Day of Month", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "end_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "End Date", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "fieldname": "submit_on_creation", - "fieldtype": "Check", - "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": "Submit on creation", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.recurring_id === doc.name", - "description": "", - "fieldname": "notify_by_email", - "fieldtype": "Check", - "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": "Notify by email", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.notify_by_email && doc.recurring_id === doc.name", - "description": "", - "fieldname": "notification_email_address", - "fieldtype": "Code", - "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": "Notification Email Address", - "length": 0, - "no_copy": 1, - "options": "Email", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_recurring && doc.notify_by_email && doc.recurring_id === doc.name", - "fieldname": "recurring_print_format", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Recurring Print Format", - "length": 0, - "no_copy": 0, - "options": "Print Format", - "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break83", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "This Document", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_recurring", + "depends_on": "", "description": "", "fieldname": "from_date", "fieldtype": "Date", @@ -3390,7 +2985,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "is_recurring", + "depends_on": "", "description": "", "fieldname": "to_date", "fieldtype": "Date", @@ -3421,10 +3016,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "is_recurring", - "description": "", - "fieldname": "next_date", - "fieldtype": "Date", + "fieldname": "column_break_97", + "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -3432,11 +3025,11 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Next Date", "length": 0, - "no_copy": 1, + "no_copy": 0, "permlevel": 0, - "print_hide": 1, + "precision": "", + "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -3445,6 +3038,37 @@ "search_index": 0, "set_only_once": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "subscription", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Subscription", + "length": 0, + "no_copy": 1, + "options": "Subscription", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], "has_web_view": 0, @@ -3458,7 +3082,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-10-05 14:19:04.102534", + "modified": "2017-10-24 12:52:11.272306", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js index 6605a65170..5d196874c9 100644 --- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js @@ -1,7 +1,7 @@ QUnit.module('Buying'); QUnit.test("test: purchase order", function(assert) { - assert.expect(11); + assert.expect(16); let done = assert.async(); frappe.run_serially([ @@ -40,7 +40,6 @@ QUnit.test("test: purchase order", function(assert) { // Get supplier details assert.ok(cur_frm.doc.supplier_name == 'Test Supplier', "Supplier name correct"); assert.ok(cur_frm.doc.schedule_date == frappe.datetime.add_days(frappe.datetime.now_date(), 1), "Schedule Date correct"); - assert.ok($('div.control-value.like-disabled-input.for-description').text().includes('Contact 3'), "Contact display correct"); assert.ok(cur_frm.doc.contact_email == 'test@supplier.com', "Contact email correct"); // Get item details assert.ok(cur_frm.doc.items[0].item_name == 'Test Product 4', "Item name correct"); @@ -53,7 +52,7 @@ QUnit.test("test: purchase order", function(assert) { assert.ok(cur_frm.doc.items[1].qty == 2, "Quantity correct"); assert.ok(cur_frm.doc.items[1].schedule_date == cur_frm.doc.schedule_date, "Schedule Date correct"); // Calculate total - assert.ok(cur_frm.doc.total == 500, "Total correct"); + assert.ok(cur_frm.doc.total == 700, "Total correct"); // Get terms assert.ok(cur_frm.doc.terms == 'This is a term.', "Terms correct"); }, @@ -70,7 +69,7 @@ QUnit.test("test: purchase order", function(assert) { () => frappe.tests.click_button('Submit'), () => frappe.tests.click_button('Yes'), - () => frappe.timeout(0.3), + () => frappe.timeout(1), () => { assert.ok(cur_frm.doc.status == 'To Receive and Bill', "Submitted successfully"); 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 44068ce81d..50d6abdd8f 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json @@ -816,7 +816,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-07-21 14:06:46.309322", + "modified": "2017-10-17 17:27:06.281494", "modified_by": "Administrator", "module": "Buying", "name": "Request for Quotation", @@ -903,26 +903,6 @@ "submit": 0, "write": 0 }, - { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Supplier", - "set_user_permissions": 0, - "share": 0, - "submit": 0, - "write": 0 - }, { "amend": 0, "apply_user_permissions": 0, diff --git a/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation.js index a4d68aa946..1fcfe75bb0 100644 --- a/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation.js +++ b/erpnext/buying/doctype/request_for_quotation/tests/test_request_for_quotation.js @@ -27,6 +27,7 @@ QUnit.test("test: request_for_quotation", function(assert) { {tc_name: 'Test Term 1'} ]); }, + () => frappe.timeout(3), () => { assert.ok(cur_frm.doc.transaction_date == date, "Date correct"); assert.ok(cur_frm.doc.company == cur_frm.doc.company, "Company correct"); @@ -38,7 +39,7 @@ QUnit.test("test: request_for_quotation", function(assert) { assert.ok(cur_frm.doc.message_for_supplier == 'Please supply the specified items at the best possible rates', "Reply correct"); assert.ok(cur_frm.doc.tc_name == 'Test Term 1', "Term name correct"); }, - () => frappe.timeout(0.3), + () => frappe.timeout(3), () => cur_frm.print_doc(), () => frappe.timeout(1), () => { @@ -65,7 +66,7 @@ QUnit.test("test: request_for_quotation", function(assert) { assert.ok(cur_frm.doc.docstatus == 1, "Quotation request submitted"); }, () => frappe.click_button('Send Supplier Emails'), - () => frappe.timeout(4), + () => frappe.timeout(6), () => { assert.ok($('div.modal.fade.in > div.modal-dialog > div > div.modal-body.ui-front > div.msgprint').text().includes("Email sent to supplier Test Supplier"), "Send emails working"); }, diff --git a/erpnext/buying/doctype/supplier/test_supplier.js b/erpnext/buying/doctype/supplier/test_supplier.js index 99a5bc616d..05ea04422d 100644 --- a/erpnext/buying/doctype/supplier/test_supplier.js +++ b/erpnext/buying/doctype/supplier/test_supplier.js @@ -56,7 +56,8 @@ QUnit.test("test: supplier", function(assert) { () => frappe.click_button('New Contact'), () => { return frappe.tests.set_form_values(cur_frm, [ - {first_name: "Contact 3"} + {first_name: "Contact 3"}, + {email_id: "test@supplier.com"} ]); }, () => cur_frm.save(), diff --git a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.js deleted file mode 100644 index 7097a6dcb2..0000000000 --- a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.js +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -// rename this file from _test_[name] to test_[name] to activate -// and remove above this line - -QUnit.test("test: Supplier Quotation", function (assert) { - let done = assert.async(); - - // number of asserts - assert.expect(1); - - frappe.run_serially('Supplier Quotation', [ - // insert a new Supplier Quotation - () => frappe.tests.make([ - // values to be set - {key: 'value'} - ]), - () => { - assert.equal(cur_frm.doc.key, 'value'); - }, - () => done() - ]); - -}); diff --git a/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation.js index 76be06c6fb..2d2b29cb91 100644 --- a/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation.js +++ b/erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation.js @@ -27,12 +27,13 @@ QUnit.test("test: supplier quotation", function(assert) { {terms: 'This is a term'} ]); }, + () => frappe.timeout(3), () => { // Get Supplier details assert.ok(cur_frm.doc.supplier == 'Test Supplier', "Supplier correct"); assert.ok(cur_frm.doc.company == cur_frm.doc.company, "Company correct"); // Get Contact details - assert.ok(cur_frm.doc.contact_display == 'Contact 3', "Conatct correct"); + assert.ok(cur_frm.doc.contact_person == 'Contact 3-Test Supplier', "Conatct correct"); assert.ok(cur_frm.doc.contact_email == 'test@supplier.com', "Email correct"); // Get uom assert.ok(cur_frm.doc.items[0].uom == 'Unit', "Multi uom correct"); diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py index 65485912e2..ce6c0c3f43 100644 --- a/erpnext/config/desktop.py +++ b/erpnext/config/desktop.py @@ -1,3 +1,5 @@ +# coding=utf-8 + from __future__ import unicode_literals from frappe import _ @@ -284,4 +286,12 @@ def get_data(): "link": "data-import-tool", "label": _("Data Import Tool") }, + { + "module_name": "Restaurant", + "color": "#EA81E8", + "icon": "🍔", + "_doctype": "Restaurant", + "link": "List/Restaurant", + "label": _("Restaurant") + } ] diff --git a/erpnext/config/hr.py b/erpnext/config/hr.py index 43f625af42..ec281bb6ef 100644 --- a/erpnext/config/hr.py +++ b/erpnext/config/hr.py @@ -176,6 +176,10 @@ def get_data(): { "label": _("Training"), "items": [ + { + "type": "doctype", + "name": "Training Program" + }, { "type": "doctype", "name": "Training Event" diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 4f49c7747b..ebd45c4c59 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -83,6 +83,9 @@ class AccountsController(TransactionBase): self.set(fieldname, today()) break + # set taxes table if missing from `taxes_and_charges` + self.set_taxes() + def calculate_taxes_and_totals(self): from erpnext.controllers.taxes_and_totals import calculate_taxes_and_totals calculate_taxes_and_totals(self) @@ -259,9 +262,9 @@ class AccountsController(TransactionBase): if not account_currency: account_currency = get_account_currency(gl_dict.account) - if gl_dict.account and self.doctype not in ["Journal Entry", + if gl_dict.account and self.doctype not in ["Journal Entry", "Period Closing Voucher", "Payment Entry"]: - + self.validate_account_currency(gl_dict.account, account_currency) set_balance_in_account_currency(gl_dict, account_currency, self.get("conversion_rate"), self.company_currency) diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index 513b97f53a..f40d519b92 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -201,13 +201,16 @@ def copy_attributes_to_variant(item, variant): variant.variant_of = item.name variant.has_variants = 0 if not variant.description: - variant.description = '' + variant.description = "" if item.variant_based_on=='Item Attribute': if variant.attributes: - variant.description += "\n" + attributes_description = "" for d in variant.attributes: - variant.description += "
{{ doc.introduction }}
\n\n{{_("An error occured while creating recurring")}} {{ type }} {{ name }} {{_("for")}} {{ party }}.
{{_("This could be because of some invalid Email Addresses in the")}} {{ type }}.
-{{_("To stop sending repetitive error notifications from the system, we have checked "Disabled" field in the subscription")}} {{ subscription}} {{_("for the")}} {{ type }} {{ name }}.
-{{_("Please correct the")}} {{ type }} {{_('and unchcked "Disabled" in the')}} {{ subscription }} {{_("for making recurring again.")}}
+{{_("To stop sending repetitive error notifications from the system, we have checked Disabled field in the subscription")}} {{ subscription}} {{_("for the")}} {{ type }} {{ name }}.
+{{_("Please correct the")}} {{ type }} {{_('and unchcked Disabled in the')}} {{ subscription }} {{_("for making recurring again.")}}
{{_("It is necessary to take this action today itself for the above mentioned recurring")}} {{ type }} {{_('to be generated. If delayed, you will have to manually change the "Repeat on Day of Month" field diff --git a/erpnext/templates/utils.py b/erpnext/templates/utils.py index 6ebe41185f..7ee39602f5 100644 --- a/erpnext/templates/utils.py +++ b/erpnext/templates/utils.py @@ -28,11 +28,12 @@ def send_message(subject="Website Query", message="", sender="", status="Open"): )).insert(ignore_permissions=True) opportunity = frappe.get_doc(dict( - doctype='Opportunity', + doctype ='Opportunity', enquiry_from = 'Customer' if customer else 'Lead', status = 'Open', title = subject, - to_discuss=message + contact_email = sender, + to_discuss = message )) if customer: diff --git a/erpnext/tests/ui/make_fixtures.js b/erpnext/tests/ui/make_fixtures.js index 0bd74915c2..949e92b1ca 100644 --- a/erpnext/tests/ui/make_fixtures.js +++ b/erpnext/tests/ui/make_fixtures.js @@ -231,7 +231,9 @@ QUnit.test('Make fixtures', assert => { let done = assert.async(); let tasks = []; Object.keys(frappe.test_data).forEach(function(doctype) { - tasks.push(function() { return frappe.tests.setup_doctype(doctype); }); + tasks.push(function() { + return frappe.tests.setup_doctype(doctype, frappe.test_data[doctype]); + }); }); frappe.run_serially(tasks).then(() => done()); }); diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt index f35f6d7bc1..e7de60439a 100644 --- a/erpnext/tests/ui/tests.txt +++ b/erpnext/tests/ui/tests.txt @@ -72,7 +72,6 @@ erpnext/hr/doctype/appraisal/test_appraisal.js erpnext/hr/doctype/expense_claim_type/test_expense_claim_type.js erpnext/hr/doctype/expense_claim/test_expense_claim.js erpnext/hr/doctype/training_event/tests/test_training_event.js -erpnext/hr/doctype/training_event/tests/test_training_event_attendance.js erpnext/hr/doctype/training_result_employee/test_training_result.js erpnext/hr/doctype/training_feedback/test_training_feedback.js erpnext/hr/doctype/loan_type/test_loan_type.js @@ -129,4 +128,8 @@ erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue_with erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_repack.js erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js -erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js \ No newline at end of file +erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js +erpnext/restaurant/doctype/restaurant/test_restaurant.js +erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.js +erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js +erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js