diff --git a/erpnext/__init__.py b/erpnext/__init__.py index ce16a6e7db8..b245f56172a 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.0.3' +__version__ = '9.2.2' 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 f6015f37442..018d368de44 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 42cd44aeabe..002562f5b99 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 7c4eeae93a4..e3afc359b65 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 21596f11327..831373a9c99 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 375d85d1b72..790003c3010 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -12,8 +12,8 @@ from erpnext.hr.doctype.expense_claim.expense_claim import update_reimbursed_amo from erpnext.hr.doctype.employee_loan.employee_loan import update_disbursement_status class JournalEntry(AccountsController): - def __init__(self, arg1, arg2=None): - super(JournalEntry, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(JournalEntry, self).__init__(*args, **kwargs) def get_feed(self): return self.voucher_type @@ -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 04db9e28ae6..17ac1f70567 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 9d24261038b..56bdfbaf4b6 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/tests/test_payment_against_purchase_invoice.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_purchase_invoice.js new file mode 100644 index 00000000000..14aa0736d40 --- /dev/null +++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_purchase_invoice.js @@ -0,0 +1,60 @@ +QUnit.module('Payment Entry'); + +QUnit.test("test payment entry", function(assert) { + assert.expect(7 ); + let done = assert.async(); + + frappe.run_serially([ + () => { + return frappe.tests.make('Purchase Invoice', [ + {supplier: 'Test Supplier'}, + {bill_no: 'in1234'}, + {items: [ + [ + {'qty': 2}, + {'item_code': 'Test Product 1'}, + {'rate':1000}, + ] + ]}, + {update_stock:1}, + {supplier_address: 'Test1-Billing'}, + {contact_person: 'Contact 3-Test Supplier'}, + {tc_name: 'Test Term 1'}, + {terms: 'This is just a Test'} + ]); + }, + + () => cur_frm.save(), + () => frappe.tests.click_button('Submit'), + () => frappe.tests.click_button('Yes'), + () => frappe.timeout(1), + () => frappe.click_button('Make'), + () => frappe.timeout(2), + () => frappe.click_link('Payment'), + () => frappe.timeout(3), + () => cur_frm.set_value('mode_of_payment','Cash'), + () => frappe.timeout(3), + () => { + assert.equal(frappe.get_route()[1], 'Payment Entry', + 'made payment entry'); + assert.equal(cur_frm.doc.party, 'Test Supplier', + 'supplier set in payment entry'); + assert.equal(cur_frm.doc.paid_amount, 2000, + 'paid amount set in payment entry'); + assert.equal(cur_frm.doc.references[0].allocated_amount, 2000, + 'amount allocated against purchase invoice'); + assert.equal(cur_frm.doc.references[0].bill_no, 'in1234', + 'invoice number allocated against purchase invoice'); + assert.equal(cur_frm.get_field('total_allocated_amount').value, 2000, + 'correct amount allocated in Write Off'); + assert.equal(cur_frm.get_field('unallocated_amount').value, 0, + 'correct amount unallocated in Write Off'); + }, + + () => cur_frm.save(), + () => frappe.tests.click_button('Submit'), + () => frappe.tests.click_button('Yes'), + () => frappe.timeout(3), + () => done() + ]); +}); \ No newline at end of file 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 da17bb3fc85..03341da6586 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/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js index 97bbc1227f1..cb52627cf0d 100755 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.js +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js @@ -37,10 +37,10 @@ frappe.ui.form.on('POS Profile', { return { filters: { doc_type: "Sales Invoice", print_format_type: "Js"} }; }); - frappe.db.get_value('POS Settings', {name: 'POS Settings'}, 'is_online', (r) => { - is_online = r && cint(r.is_online) - frm.toggle_display('offline_pos_section', !is_online); - frm.toggle_display('print_format_for_online', is_online); + frappe.db.get_value('POS Settings', {name: 'POS Settings'}, 'use_pos_in_offline_mode', (r) => { + is_offline = r && cint(r.use_pos_in_offline_mode) + frm.toggle_display('offline_pos_section', is_offline); + frm.toggle_display('print_format_for_online', !is_offline); }); }, diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.py b/erpnext/accounts/doctype/pos_settings/pos_settings.py index 736d36eea96..13a50042fb7 100644 --- a/erpnext/accounts/doctype/pos_settings/pos_settings.py +++ b/erpnext/accounts/doctype/pos_settings/pos_settings.py @@ -3,7 +3,17 @@ # For license information, please see license.txt from __future__ import unicode_literals +import frappe from frappe.model.document import Document class POSSettings(Document): - pass \ No newline at end of file + def validate(self): + self.set_link_for_pos() + + def set_link_for_pos(self): + link = 'pos' if self.use_pos_in_offline_mode else 'point-of-sale' + desktop_icon = frappe.db.get_value('Desktop Icon', + {'standard': 1, 'module_name': 'POS'}, 'name') + + if desktop_icon: + frappe.db.set_value('Desktop Icon', desktop_icon, 'link', link) \ 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 57f9f832d03..83045eae4e3 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 e3c5fb49424..3d70b3b0b98 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/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index a46c4b96c33..78c5682ef87 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -22,8 +22,8 @@ form_grid_templates = { } class PurchaseInvoice(BuyingController): - def __init__(self, arg1, arg2=None): - super(PurchaseInvoice, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(PurchaseInvoice, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Purchase Invoice Item', 'target_dt': 'Purchase Order Item', diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js index 6e33e1d7f2c..e01dda32bf6 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js @@ -7,6 +7,7 @@ QUnit.test("test purchase invoice", function(assert) { () => { return frappe.tests.make('Purchase Invoice', [ {supplier: 'Test Supplier'}, + {bill_no: 'in123'}, {items: [ [ {'qty': 5}, @@ -36,7 +37,7 @@ QUnit.test("test purchase invoice", function(assert) { }, () => frappe.tests.click_button('Submit'), () => frappe.tests.click_button('Yes'), - () => frappe.timeout(0.3), + () => frappe.timeout(1), () => done() ]); }); diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 639620f910f..474329fc9ad 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -473,6 +473,7 @@ class TestPurchaseInvoice(unittest.TestCase): import test_records as jv_test_records jv = frappe.copy_doc(jv_test_records[1]) + jv.accounts[0].is_advance = 'Yes' jv.insert() jv.submit() diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py index 2b3459ad273..6856f62d0c6 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') if pos_profile.get('apply_discount') else '' + 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 '' @@ -417,6 +417,7 @@ def make_contact(args,customer): 'link_doctype': 'Customer', 'link_name': customer }) + doc.flags.ignore_mandatory = True doc.save(ignore_permissions=True) def make_address(args, customer): @@ -441,6 +442,7 @@ def make_address(args, customer): address.is_primary_address = 1 address.is_shipping_address = 1 address.update(args) + address.flags.ignore_mandatory = True address.save(ignore_permissions = True) def make_email_queue(email_queue): @@ -484,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.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 11d18253887..28a5d01aa8c 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -339,7 +339,7 @@ $.extend(cur_frm.cscript, new erpnext.accounts.SalesInvoiceController({frm: cur_ // ------------ cur_frm.cscript.hide_fields = function(doc) { var parent_fields = ['project', 'due_date', 'is_opening', 'source', 'total_advance', 'get_advances', - 'advances', 'sales_partner', 'commission_rate', 'total_commission', 'advances', 'from_date', 'to_date']; + 'advances', 'advances', 'from_date', 'to_date']; if(cint(doc.is_pos) == 1) { hide_field(parent_fields); @@ -520,6 +520,24 @@ frappe.ui.form.on('Sales Invoice', { }; }); }, + //When multiple companies are set up. in case company name is changed set default company address + company:function(frm){ + if (frm.doc.company) + { + frappe.call({ + method:"frappe.contacts.doctype.address.address.get_default_address", + args:{ doctype:'Company',name:frm.doc.company}, + callback: function(r){ + if (r.message){ + frm.set_value("company_address",r.message) + } + else { + frm.set_value("company_address","") + } + } + }) + } + }, project: function(frm){ frm.call({ diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 9aa0e6b6a2b..ecd7cf90690 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 7a787c4cba3..1c4fe3d0846 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -27,8 +27,8 @@ form_grid_templates = { } class SalesInvoice(SellingController): - def __init__(self, arg1, arg2=None): - super(SalesInvoice, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(SalesInvoice, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Sales Invoice Item', 'target_field': 'billed_amt', @@ -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 900a6e9d956..50d2ce810b7 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` @@ -1092,6 +1133,7 @@ class TestSalesInvoice(unittest.TestCase): import test_records as jv_test_records jv = frappe.copy_doc(jv_test_records[0]) + jv.accounts[0].is_advance = 'Yes' jv.insert() jv.submit() diff --git a/erpnext/accounts/doctype/subscription/subscription.js b/erpnext/accounts/doctype/subscription/subscription.js index 9c5b264bc08..8db5be87721 100644 --- a/erpnext/accounts/doctype/subscription/subscription.js +++ b/erpnext/accounts/doctype/subscription/subscription.js @@ -3,10 +3,17 @@ frappe.ui.form.on('Subscription', { setup: function(frm) { + frm.fields_dict['reference_doctype'].get_query = function(doc) { + return { + query: "erpnext.accounts.doctype.subscription.subscription.subscription_doctype_query" + }; + }; + 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 85779533ea2..7ff2e4b632f 100644 --- a/erpnext/accounts/doctype/subscription/subscription.json +++ b/erpnext/accounts/doctype/subscription/subscription.json @@ -135,66 +135,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "disabled", - "fieldtype": "Check", - "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": "Disabled", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 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": "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": 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, @@ -286,12 +226,12 @@ }, { "allow_bulk_edit": 0, - "allow_on_submit": 1, + "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "next_schedule_date", - "fieldtype": "Date", + "fieldname": "submit_on_creation", + "fieldtype": "Check", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -299,14 +239,44 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Next Schedule Date", + "label": "Submit on Creation", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "disabled", + "fieldtype": "Check", + "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": "Disabled", "length": 0, "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 1, + "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -320,7 +290,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "frequency_detail", + "fieldname": "section_break_10", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, @@ -329,7 +299,6 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "", "length": 0, "no_copy": 0, "permlevel": 0, @@ -381,7 +350,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "column_break_12", + "fieldname": "column_break_13", "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, @@ -437,10 +406,40 @@ }, { "allow_bulk_edit": 0, - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, + "fieldname": "next_schedule_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 Schedule Date", + "length": 0, + "no_copy": 1, + "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, + "columns": 0, "fieldname": "notification", "fieldtype": "Section Break", "hidden": 0, @@ -495,6 +494,38 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.notify_by_email", + "description": "To add dynamic subject, use jinja tags like\n\n
New {{ doc.doctype }} #{{ doc.name }}
", + "fieldname": "subject", + "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": "Subject", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -593,6 +624,69 @@ "bold": 0, "collapsible": 1, "columns": 0, + "depends_on": "eval:doc.notify_by_email", + "fieldname": "section_break_20", + "fieldtype": "Section 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": "Message", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Please find attached {{ doc.doctype }} #{{ doc.name }}", + "fieldname": "message", + "fieldtype": "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": "Message", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "depends_on": "eval: !doc.__islocal", "fieldname": "section_break_16", "fieldtype": "Section Break", "hidden": 0, @@ -690,7 +784,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-14 12:09:38.471458", + "modified": "2017-10-23 18:28:08.966403", "modified_by": "Administrator", "module": "Accounts", "name": "Subscription", @@ -700,7 +794,7 @@ { "amend": 0, "apply_user_permissions": 0, - "cancel": 0, + "cancel": 1, "create": 1, "delete": 1, "email": 1, @@ -720,7 +814,7 @@ { "amend": 0, "apply_user_permissions": 0, - "cancel": 0, + "cancel": 1, "create": 1, "delete": 1, "email": 1, @@ -740,7 +834,7 @@ { "amend": 0, "apply_user_permissions": 0, - "cancel": 0, + "cancel": 1, "create": 1, "delete": 1, "email": 1, diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py index c9df7d461e5..1103b701dc2 100644 --- a/erpnext/accounts/doctype/subscription/subscription.py +++ b/erpnext/accounts/doctype/subscription/subscription.py @@ -7,21 +7,28 @@ import frappe import calendar from frappe import _ from frappe.desk.form import assign_to +from frappe.utils.jinja import validate_template from dateutil.relativedelta import relativedelta from frappe.utils.user import get_system_managers -from frappe.utils import cstr, getdate, split_emails, add_days, today +from frappe.utils import cstr, getdate, split_emails, add_days, today, get_last_day, get_first_day from frappe.model.document import Document 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() + validate_template(self.subject or "") + 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() @@ -30,6 +37,18 @@ class Subscription(Document): 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): + 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): frappe.throw(_("End date must be greater than start date")) @@ -61,15 +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) + 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 = { @@ -114,19 +129,19 @@ def create_documents(data, schedule_date): doc = make_new_document(data, schedule_date) if data.notify_by_email and data.recipients: print_format = data.print_format or "Standard" - send_notification(doc, print_format, data.recipients) + send_notification(doc, data, print_format=print_format) frappe.db.commit() except Exception: frappe.db.rollback() frappe.db.begin() frappe.log_error(frappe.get_traceback()) - disabled_subscription(data) + disable_subscription(data) frappe.db.commit() if data.reference_document and not frappe.flags.in_test: notify_error_to_user(data) -def disabled_subscription(data): +def disable_subscription(data): subscription = frappe.get_doc('Subscription', data.name) subscription.db_set('disabled', 1) @@ -160,28 +175,79 @@ def update_doc(new_document, reference_doc, args, schedule_date): if new_document.meta.get_field('set_posting_time'): new_document.set('set_posting_time', 1) + mcount = month_map.get(args.frequency) + if new_document.meta.get_field('subscription'): new_document.set('subscription', args.name) - new_document.run_method("on_recurring", reference_doc=reference_doc, subscription_doc=args) + 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)) + + # 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)) + 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 mcount and 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) return dt -def send_notification(new_rv, print_format='Standard', recipients=None): +def send_notification(new_rv, subscription_doc, print_format='Standard'): """Notify concerned persons about recurring document generation""" print_format = print_format - frappe.sendmail(recipients, - subject= _("New {0}: #{1}").format(new_rv.doctype, new_rv.name), - message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name), - attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name, print_format=print_format)]) + if not subscription_doc.subject: + subject = _("New {0}: #{1}").format(new_rv.doctype, new_rv.name) + elif "{" in subscription_doc.subject: + subject = frappe.render_template(subscription_doc.subject, {'doc': new_rv}) + + if not subscription_doc.message: + message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name) + elif "{" in subscription_doc.message: + message = frappe.render_template(subscription_doc.message, {'doc': new_rv}) + + attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, + file_name=new_rv.name, print_format=print_format)] + + frappe.sendmail(subscription_doc.recipients, + subject=subject, message=message, attachments=attachments) def notify_errors(doc, doctype, party, owner, name): recipients = get_system_managers(only_name=True) @@ -210,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() @@ -225,4 +294,20 @@ def stop_resume_subscription(subscription, status): doc.update_status(status) doc.save() - return doc.status \ No newline at end of file + return doc.status + +def subscription_doctype_query(doctype, txt, searchfield, start, page_len, filters): + return frappe.db.sql("""select parent from `tabDocField` + where fieldname = 'subscription' + and parent like %(txt)s + order by + if(locate(%(_txt)s, parent), locate(%(_txt)s, parent), 99999), + parent + limit %(start)s, %(page_len)s""".format(**{ + 'key': searchfield, + }), { + 'txt': "%%%s%%" % txt, + '_txt': txt.replace("%", ""), + 'start': start, + 'page_len': page_len + }) \ No newline at end of file diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py index b74163c92e9..4ccf483c1a4 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 5ad7970a6e3..ee5b3c9d6a3 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 be0b6f7b727..c442062ab6f 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(); }); }, @@ -113,6 +114,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ }); this.page.add_menu_item(__("Sync Offline Invoices"), function () { + me.freeze_screen = true; me.sync_sales_invoice() }); @@ -381,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) { @@ -1340,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') { @@ -1347,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); }); }, @@ -1516,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 () { @@ -1684,6 +1693,7 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ set_interval_for_si_sync: function () { var me = this; setInterval(function () { + me.freeze_screen = false; me.sync_sales_invoice() }, 60000) }, @@ -1697,9 +1707,12 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({ this.freeze = this.customer_doc.display } + freeze_screen = this.freeze_screen || false; + if ((this.si_docs.length || this.email_queue_list || this.customers_list) && !this.freeze) { frappe.call({ method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice", + freeze: freeze_screen, args: { doc_list: me.si_docs, email_queue_list: me.email_queue_list, diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index ba7ae323d46..ce049f5d872 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -68,16 +68,18 @@ def set_address_details(out, party, party_type, doctype=None, company=None): billing_address_field = "customer_address" if party_type == "Lead" \ else party_type.lower() + "_address" out[billing_address_field] = get_default_address(party_type, party.name) - out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field])) + if doctype: + out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field])) # address display out.address_display = get_address_display(out[billing_address_field]) # 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"]) - out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name)) + if doctype: + out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name)) if doctype and doctype in ['Delivery Note', 'Sales Invoice']: out.update(get_company_address(company)) @@ -320,11 +322,15 @@ def set_taxes(party, party_type, posting_date, company, customer_group=None, sup from erpnext.accounts.doctype.tax_rule.tax_rule import get_tax_template, get_party_details args = { party_type.lower(): party, - "customer_group": customer_group, - "supplier_type": supplier_type, "company": company } + if customer_group: + args['customer_group'] = customer_group + + if supplier_type: + args['supplier_type'] = supplier_type + if billing_address or shipping_address: args.update(get_party_details(party, party_type, {"billing_address": billing_address, \ "shipping_address": shipping_address })) @@ -412,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 9906893254f..56db3928009 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 2db4ef8a261..18b07ea5829 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 07f6979c40c..78e3faab4ea 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 6729d672c07..89ee63aa649 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 00000000000..0fca470fe5e --- /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.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index a51246bcb86..0394f74b714 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -15,6 +15,8 @@ frappe.ui.form.on("Purchase Order", { }, onload: function(frm) { + set_schedule_date(frm); + erpnext.queries.setup_queries(frm, "Warehouse", function() { return erpnext.queries.warehouse(frm.doc); }); @@ -24,6 +26,29 @@ frappe.ui.form.on("Purchase Order", { }, }); +frappe.ui.form.on("Purchase Order Item", { + item_code: function(frm) { + frappe.call({ + method: "get_last_purchase_rate", + doc: frm.doc, + callback: function(r, rt) { + frm.trigger('calculate_taxes_and_totals'); + } + }) + }, + + schedule_date: function(frm, cdt, cdn) { + var row = locals[cdt][cdn]; + if (row.schedule_date) { + if(!frm.doc.schedule_date) { + erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "schedule_date"); + } else { + set_schedule_date(frm); + } + } + } +}); + erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend({ refresh: function(doc, cdt, cdn) { var me = this; @@ -107,12 +132,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( }, validate: function() { - // set default schedule date as today if missing. - (this.frm.doc.items || []).forEach(function(d) { - if(!d.schedule_date) { - d.schedule_date = frappe.datetime.nowdate(); - } - }) + set_schedule_date(this.frm); }, make_stock_entry: function() { @@ -201,7 +221,12 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( items_add: function(doc, cdt, cdn) { var row = frappe.get_doc(cdt, cdn); - this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]); + if(doc.schedule_date) { + row.schedule_date = doc.schedule_date; + refresh_field("schedule_date", cdn, "items"); + } else { + this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]); + } }, unclose_purchase_order: function(){ @@ -225,8 +250,15 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( cur_frm.cscript.calculate_taxes_and_totals(); } }) - } + }, + items_on_form_rendered: function() { + set_schedule_date(this.frm); + }, + + schedule_date: function() { + set_schedule_date(this.frm); + } }); // for backward compatibility: combine new and previous states @@ -268,8 +300,10 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) { } } -cur_frm.cscript.schedule_date = function(doc, cdt, cdn) { - erpnext.utils.copy_value_in_all_row(doc, cdt, cdn, "items", "schedule_date"); +function set_schedule_date(frm) { + if(frm.doc.schedule_date){ + erpnext.utils.copy_value_in_all_row(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date"); + } } frappe.provide("erpnext.buying"); diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 919707c08d4..534af8bfc50 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -291,9 +291,40 @@ "search_index": 1, "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fieldname": "schedule_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": "Reqd By 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, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -1206,37 +1237,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.docstatus===0 && (doc.items && doc.items.length)", - "fieldname": "get_last_purchase_rate", - "fieldtype": "Button", - "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": "Get last purchase rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -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-09-19 11:22:30.190589", + "modified": "2017-10-24 12:52:11.272306", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 56f3059f2e9..415099328b4 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -20,8 +20,8 @@ form_grid_templates = { } class PurchaseOrder(BuyingController): - def __init__(self, arg1, arg2=None): - super(PurchaseOrder, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(PurchaseOrder, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Purchase Order Item', 'target_dt': 'Material Request Item', @@ -41,6 +41,7 @@ class PurchaseOrder(BuyingController): self.set_status() self.validate_supplier() + self.validate_schedule_date() validate_for_items(self) self.check_for_closed_status() @@ -116,14 +117,13 @@ class PurchaseOrder(BuyingController): d.discount_percentage = last_purchase_details['discount_percentage'] d.base_rate = last_purchase_details['base_rate'] * (flt(d.conversion_factor) or 1.0) d.price_list_rate = d.base_price_list_rate / conversion_rate - d.rate = d.base_rate / conversion_rate + d.last_purchase_rate = d.base_rate / conversion_rate else: - msgprint(_("Last purchase rate not found")) item_last_purchase_rate = frappe.db.get_value("Item", d.item_code, "last_purchase_rate") if item_last_purchase_rate: d.base_price_list_rate = d.base_rate = d.price_list_rate \ - = d.rate = item_last_purchase_rate + = d.last_purchase_rate = item_last_purchase_rate # Check for Closed status def check_for_closed_status(self): diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 17786aa443a..2af55825d44 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -118,6 +118,7 @@ class TestPurchaseOrder(unittest.TestCase): "company": "_Test Company", "supplier" : "_Test Supplier", "is_subcontracted" : "No", + "schedule_date": add_days(nowdate(), 1), "currency" : frappe.db.get_value("Company", "_Test Company", "default_currency"), "conversion_factor" : 1, "items" : get_same_items(), @@ -149,6 +150,7 @@ def create_purchase_order(**args): if args.transaction_date: po.transaction_date = args.transaction_date + po.schedule_date = add_days(nowdate(), 1) po.company = args.company or "_Test Company" po.supplier = args.customer or "_Test Supplier" po.is_subcontracted = args.is_subcontracted or "No" diff --git a/erpnext/buying/doctype/purchase_order/test_records.json b/erpnext/buying/doctype/purchase_order/test_records.json index 2c2e792176a..74b8f1b429b 100644 --- a/erpnext/buying/doctype/purchase_order/test_records.json +++ b/erpnext/buying/doctype/purchase_order/test_records.json @@ -30,7 +30,8 @@ ], "supplier": "_Test Supplier", "supplier_name": "_Test Supplier", - "transaction_date": "2013-02-12" + "transaction_date": "2013-02-12", + "schedule_date": "2013-02-13" }, { "advance_paid": 0.0, @@ -63,6 +64,7 @@ ], "supplier": "_Test Supplier", "supplier_name": "_Test Supplier", - "transaction_date": "2013-02-12" + "transaction_date": "2013-02-12", + "schedule_date": "2013-02-13" } ] 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 e6529e60dbb..5d196874c98 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([ @@ -13,12 +13,21 @@ QUnit.test("test: purchase order", function(assert) { {items: [ [ {"item_code": 'Test Product 4'}, - {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)}, + {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 2)}, {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)}, {"qty": 5}, {"uom": 'Unit'}, {"rate": 100}, {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))} + ], + [ + {"item_code": 'Test Product 1'}, + {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)}, + {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)}, + {"qty": 2}, + {"uom": 'Unit'}, + {"rate": 100}, + {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))} ] ]}, @@ -30,14 +39,20 @@ QUnit.test("test: purchase order", function(assert) { () => { // Get supplier details assert.ok(cur_frm.doc.supplier_name == 'Test Supplier', "Supplier name correct"); - assert.ok($('div.control-value.like-disabled-input.for-description').text().includes('Contact 3'), "Contact display correct"); + assert.ok(cur_frm.doc.schedule_date == frappe.datetime.add_days(frappe.datetime.now_date(), 1), "Schedule Date 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"); assert.ok(cur_frm.doc.items[0].description == 'Test Product 4', "Description correct"); assert.ok(cur_frm.doc.items[0].qty == 5, "Quantity correct"); + assert.ok(cur_frm.doc.items[0].schedule_date == frappe.datetime.add_days(frappe.datetime.now_date(), 2), "Schedule Date correct"); + + assert.ok(cur_frm.doc.items[1].item_name == 'Test Product 1', "Item name correct"); + assert.ok(cur_frm.doc.items[1].description == 'Test Product 1', "Description correct"); + 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"); }, @@ -54,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/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js new file mode 100644 index 00000000000..d19f0174256 --- /dev/null +++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_last_purchase_rate.js @@ -0,0 +1,99 @@ +QUnit.module('Buying'); + +QUnit.test("test: purchase order with last purchase rate", function(assert) { + assert.expect(5); + let done = assert.async(); + + frappe.run_serially([ + () => { + return frappe.tests.make('Purchase Order', [ + {supplier: 'Test Supplier'}, + {is_subcontracted: 'No'}, + {currency: 'INR'}, + {items: [ + [ + {"item_code": 'Test Product 4'}, + {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)}, + {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)}, + {"qty": 1}, + {"rate": 800}, + {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))} + ], + [ + {"item_code": 'Test Product 1'}, + {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)}, + {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)}, + {"qty": 1}, + {"rate": 400}, + {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))} + ] + ]} + ]); + }, + + () => { + // Get item details + assert.ok(cur_frm.doc.items[0].item_name == 'Test Product 4', "Item 1 name correct"); + assert.ok(cur_frm.doc.items[1].item_name == 'Test Product 1', "Item 2 name correct"); + }, + + () => frappe.timeout(1), + + () => frappe.tests.click_button('Submit'), + () => frappe.tests.click_button('Yes'), + () => frappe.timeout(3), + + () => frappe.tests.click_button('Close'), + () => frappe.timeout(1), + + () => { + return frappe.tests.make('Purchase Order', [ + {supplier: 'Test Supplier'}, + {is_subcontracted: 'No'}, + {currency: 'INR'}, + {items: [ + [ + {"item_code": 'Test Product 4'}, + {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)}, + {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)}, + {"qty": 1}, + {"rate": 600}, + {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))} + ], + [ + {"item_code": 'Test Product 1'}, + {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)}, + {"expected_delivery_date": frappe.datetime.add_days(frappe.datetime.now_date(), 5)}, + {"qty": 1}, + {"rate": 200}, + {"warehouse": 'Stores - '+frappe.get_abbr(frappe.defaults.get_default("Company"))} + ] + ]} + ]); + }, + + () => frappe.timeout(2), + + // Get the last purchase rate of items + () => { + assert.ok(cur_frm.doc.items[0].last_purchase_rate == 800, "Last purchase rate of item 1 correct"); + }, + () => { + assert.ok(cur_frm.doc.items[1].last_purchase_rate == 400, "Last purchase rate of item 2 correct"); + }, + + () => frappe.tests.click_button('Submit'), + () => frappe.tests.click_button('Yes'), + () => frappe.timeout(3), + + () => frappe.tests.click_button('Close'), + + () => frappe.timeout(1), + + () => { + assert.ok(cur_frm.doc.status == 'To Receive and Bill', "Submitted successfully"); + }, + + () => done() + ]); +}); \ No newline at end of file diff --git a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_taxes_and_charges.js b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_taxes_and_charges.js index 9d87af23425..27129fb3b89 100644 --- a/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_taxes_and_charges.js +++ b/erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_taxes_and_charges.js @@ -11,6 +11,7 @@ QUnit.test("test: purchase order with taxes and charges", function(assert) { {is_subcontracted: 'No'}, {buying_price_list: 'Test-Buying-USD'}, {currency: 'USD'}, + {"schedule_date": frappe.datetime.add_days(frappe.datetime.now_date(), 1)}, {items: [ [ {"item_code": 'Test Product 4'}, diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 2dd7b6c0edd..ca1a0a76771 100755 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -140,7 +140,7 @@ "allow_on_submit": 1, "bold": 1, "collapsible": 0, - "columns": 0, + "columns": 2, "fieldname": "schedule_date", "fieldtype": "Date", "hidden": 0, @@ -148,7 +148,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Reqd By Date", "length": 0, @@ -382,7 +382,7 @@ "allow_on_submit": 0, "bold": 1, "collapsible": 0, - "columns": 2, + "columns": 1, "fieldname": "qty", "fieldtype": "Float", "hidden": 0, @@ -655,6 +655,37 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "last_purchase_rate", + "fieldtype": "Currency", + "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": "Last Purchase Rate", + "length": 0, + "no_copy": 0, + "options": "currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -718,7 +749,7 @@ "allow_on_submit": 0, "bold": 1, "collapsible": 0, - "columns": 3, + "columns": 2, "fieldname": "rate", "fieldtype": "Currency", "hidden": 0, @@ -1714,7 +1745,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-02 22:15:47.411235", + "modified": "2017-10-05 19:47:12.433095", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", 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 44068ce81d0..50d6abdd8fd 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/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py index 97c4438dd3d..5becb825dc1 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py @@ -138,7 +138,7 @@ class RequestforQuotation(BuyingController): 'user_fullname': full_name } - subject = _("Request for Quotation") + subject = _("Request for Quotation: {0}".format(self.name)) template = "templates/emails/request_for_quotation.html" sender = frappe.session.user not in STANDARD_USERS and frappe.session.user or None message = frappe.get_template(template).render(args) 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 a4d68aa946d..1fcfe75bb03 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 99a5bc616dc..05ea04422dd 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/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py index b3d92be4b6b..c395d0cfd76 100644 --- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py +++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _ -from frappe.utils import flt +from frappe.utils import flt, nowdate, add_days from frappe.model.mapper import get_mapped_doc from erpnext.controllers.buying_controller import BuyingController @@ -151,5 +151,4 @@ def make_quotation(source_name, target_doc=None): } }, target_doc) - return doclist - + return doclist \ No newline at end of file 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 76be06c6fbb..2d2b29cb916 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/accounts.py b/erpnext/config/accounts.py index 7c0f540154b..cdce13ba356 100644 --- a/erpnext/config/accounts.py +++ b/erpnext/config/accounts.py @@ -315,11 +315,16 @@ def get_data(): "name": "Payment Gateway Account", "description": _("Setup Gateway accounts.") }, + { + "type": "doctype", + "name": "POS Settings", + "description": _("Setup mode of POS (Online / Offline)") + }, { "type": "doctype", "name": "POS Profile", "label": _("Point-of-Sale Profile"), - "description": _("Rules to calculate shipping amount for a sale") + "description": _("Setup default values for POS Invoices") }, { "type": "doctype", diff --git a/erpnext/config/desktop.py b/erpnext/config/desktop.py index ef1ff103fa7..ce6c0c3f43f 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 _ @@ -127,7 +129,6 @@ def get_data(): { "module_name": "POS", "color": "#589494", - "icon": "fa fa-th", "icon": "octicon octicon-credit-card", "type": "page", "link": "pos", @@ -267,6 +268,30 @@ def get_data(): "color": "#FF888B", "icon": "octicon octicon-plus", "type": "module", - "label": _("Healthcare") + "label": _("Healthcare"), + }, + { + "module_name": "Hub", + "color": "#009248", + "icon": "/assets/erpnext/images/hub_logo.svg", + "type": "page", + "link": "hub", + "label": _("Hub") + }, + { + "module_name": "Data Import Tool", + "color": "#7f8c8d", + "icon": "octicon octicon-circuit-board", + "type": "page", + "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 43f625af42a..ec281bb6ef7 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/config/hub_node.py b/erpnext/config/hub_node.py new file mode 100644 index 00000000000..c9d5b97bf02 --- /dev/null +++ b/erpnext/config/hub_node.py @@ -0,0 +1,24 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return [ + { + "label": _("Setup"), + "items": [ + { + "type": "doctype", + "name": "Hub Settings" + }, + ] + }, + { + "label": _("Hub"), + "items": [ + { + "type": "page", + "name": "hub" + }, + ] + }, + ] \ No newline at end of file diff --git a/erpnext/config/manufacturing.py b/erpnext/config/manufacturing.py index 11711ad0049..086d61b847e 100644 --- a/erpnext/config/manufacturing.py +++ b/erpnext/config/manufacturing.py @@ -123,6 +123,12 @@ def get_data(): "is_query_report": True, "name": "BOM Search", "doctype": "BOM" + }, + { + "type": "report", + "is_query_report": True, + "name": "BOM Stock Report", + "doctype": "BOM" } ] }, diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index d04143d77d6..ebd45c4c59a 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -15,8 +15,8 @@ from erpnext.exceptions import InvalidCurrency force_item_fields = ("item_group", "barcode", "brand", "stock_uom") class AccountsController(TransactionBase): - def __init__(self, arg1, arg2=None): - super(AccountsController, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(AccountsController, self).__init__(*args, **kwargs) @property def company_currency(self): @@ -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) @@ -187,9 +190,6 @@ class AccountsController(TransactionBase): if stock_qty != len(get_serial_nos(item.get('serial_no'))): item.set(fieldname, value) - elif fieldname == "conversion_factor" and not item.get("conversion_factor"): - item.set(fieldname, value) - if ret.get("pricing_rule"): # if user changed the discount percentage then set user's discount percentage ? item.set("discount_percentage", ret.get("discount_percentage")) @@ -262,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/buying_controller.py b/erpnext/controllers/buying_controller.py index 9cc061677e0..d3010818e5a 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe from frappe import _, msgprint -from frappe.utils import flt,cint, cstr +from frappe.utils import flt,cint, cstr, getdate from erpnext.accounts.party import get_party_details from erpnext.stock.get_item_details import get_conversion_factor @@ -61,7 +61,7 @@ class BuyingController(StockController): # set contact and address details for supplier, if they are not mentioned if getattr(self, "supplier", None): - self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions)) + self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions, doctype=self.doctype, company=self.company)) self.set_missing_item_details(for_validate) @@ -408,3 +408,16 @@ class BuyingController(StockController): "actual_qty": -1*flt(d.consumed_qty), })) + def validate_schedule_date(self): + if not self.schedule_date: + self.schedule_date = min([d.schedule_date for d in self.get("items")]) + + if self.schedule_date: + for d in self.get('items'): + if not d.schedule_date: + d.schedule_date = self.schedule_date + + if d.schedule_date and getdate(d.schedule_date) < getdate(self.transaction_date): + frappe.throw(_("Expected Date cannot be before Transaction Date")) + else: + frappe.throw(_("Please enter Schedule Date")) \ No newline at end of file diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index 5b5cd9e6905..f40d519b928 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.utils import cstr, flt -import json +import json, copy class ItemVariantExistsError(frappe.ValidationError): pass class InvalidItemAttributeValueError(frappe.ValidationError): pass @@ -175,29 +175,42 @@ def copy_attributes_to_variant(item, variant): # copy non no-copy fields exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website", - "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate", "variant_based_on"] + "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate"] if item.variant_based_on=='Manufacturer': # don't copy manufacturer values if based on part no exclude_fields += ['manufacturer', 'manufacturer_part_no'] allow_fields = [d.field_name for d in frappe.get_all("Variant Field", fields = ['field_name'])] + if "variant_based_on" not in allow_fields: + allow_fields.append("variant_based_on") for field in item.meta.fields: # "Table" is part of `no_value_field` but we shouldn't ignore tables if (field.reqd or field.fieldname in allow_fields) and field.fieldname not in exclude_fields: if variant.get(field.fieldname) != item.get(field.fieldname): - variant.set(field.fieldname, item.get(field.fieldname)) + if field.fieldtype == "Table": + variant.set(field.fieldname, []) + for d in item.get(field.fieldname): + row = copy.deepcopy(d) + if row.get("name"): + row.name = None + variant.append(field.fieldname, row) + else: + variant.set(field.fieldname, item.get(field.fieldname)) 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 += "

" + d.attribute + ": " + cstr(d.attribute_value) + "

" + attributes_description += "
" + d.attribute + ": " + cstr(d.attribute_value) + "
" + + if attributes_description not in variant.description: + variant.description += attributes_description def make_variant_item_code(template_item_code, template_item_name, variant): """Uses template's item code and abbreviations to make variant's item code""" diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 7ada8ccc2f2..b1618d5eb9f 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -165,6 +165,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals and (tabItem.`{key}` LIKE %(txt)s or tabItem.item_group LIKE %(txt)s or tabItem.item_name LIKE %(txt)s + or tabItem.barcode LIKE %(txt)s or tabItem.description LIKE %(txt)s) {fcond} {mcond} order by @@ -172,7 +173,8 @@ def item_query(doctype, txt, searchfield, start, page_len, filters, as_dict=Fals if(locate(%(_txt)s, item_name), locate(%(_txt)s, item_name), 99999), idx desc, name, item_name - limit %(start)s, %(page_len)s """.format(key=searchfield, + limit %(start)s, %(page_len)s """.format( + key=searchfield, fcond=get_filters_cond(doctype, filters, conditions).replace('%', '%%'), mcond=get_match_cond(doctype).replace('%', '%%')), { diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index d881f18b33b..c1028a598dd 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -49,7 +49,8 @@ class SellingController(StockController): if getattr(self, "customer", None): from erpnext.accounts.party import _get_party_details party_details = _get_party_details(self.customer, - ignore_permissions=self.flags.ignore_permissions) + ignore_permissions=self.flags.ignore_permissions, + doctype=self.doctype, company=self.company) if not self.meta.get_field("sales_team"): party_details.pop("sales_team") diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 4251cae9545..970fd570ff1 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -42,10 +42,28 @@ class Opportunity(TransactionBase): if not self.with_items: self.items = [] - def make_new_lead_if_required(self): """Set lead against new opportunity""" if not (self.lead or self.customer) and self.contact_email: + # check if customer is already created agains the self.contact_email + customer = frappe.db.sql("""select + distinct `tabDynamic Link`.link_name as customer + from + `tabContact`, + `tabDynamic Link` + where `tabContact`.email_id='{0}' + and + `tabContact`.name=`tabDynamic Link`.parent + and + ifnull(`tabDynamic Link`.link_name, '')<>'' + and + `tabDynamic Link`.link_doctype='Customer' + """.format(self.contact_email), as_dict=True) + if customer and customer[0].customer: + self.customer = customer[0].customer + self.enquiry_from = "Customer" + return + lead_name = frappe.db.get_value("Lead", {"email_id": self.contact_email}) if not lead_name: sender_name = get_fullname(self.contact_email) diff --git a/erpnext/crm/doctype/opportunity/test_opportunity.py b/erpnext/crm/doctype/opportunity/test_opportunity.py index 4cd20ea72d2..61b583ce3b9 100644 --- a/erpnext/crm/doctype/opportunity/test_opportunity.py +++ b/erpnext/crm/doctype/opportunity/test_opportunity.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe from frappe.utils import today +from erpnext.crm.doctype.lead.lead import make_customer from erpnext.crm.doctype.opportunity.opportunity import make_quotation import unittest @@ -25,12 +26,45 @@ class TestOpportunity(unittest.TestCase): doc = frappe.get_doc('Opportunity', doc.name) self.assertEquals(doc.status, "Quotation") + def test_make_new_lead_if_required(self): + args = { + "doctype": "Opportunity", + "contact_email":"new.opportunity@example.com", + "enquiry_type": "Sales", + "with_items": 0, + "transaction_date": today() + } + # new lead should be created against the new.opportunity@example.com + opp_doc = frappe.get_doc(args).insert(ignore_permissions=True) + + self.assertTrue(opp_doc.lead) + self.assertEquals(opp_doc.enquiry_from, "Lead") + self.assertEquals(frappe.db.get_value("Lead", opp_doc.lead, "email_id"), + 'new.opportunity@example.com') + + # create new customer and create new contact against 'new.opportunity@example.com' + customer = make_customer(opp_doc.lead).insert(ignore_permissions=True) + frappe.get_doc({ + "doctype": "Contact", + "email_id": "new.opportunity@example.com", + "first_name": "_Test Opportunity Customer", + "links": [{ + "link_doctype": "Customer", + "link_name": customer.name + }] + }).insert(ignore_permissions=True) + + opp_doc = frappe.get_doc(args).insert(ignore_permissions=True) + self.assertTrue(opp_doc.customer) + self.assertEquals(opp_doc.enquiry_from, "Customer") + self.assertEquals(opp_doc.customer, customer.name) + def make_opportunity(**args): args = frappe._dict(args) opp_doc = frappe.get_doc({ "doctype": "Opportunity", - "enquiry_from": "Customer" or args.enquiry_from, + "enquiry_from": args.enquiry_from or "Customer", "enquiry_type": "Sales", "with_items": args.with_items or 0, "transaction_date": today() diff --git a/erpnext/crm/report/minutes_to_first_response_for_opportunity/minutes_to_first_response_for_opportunity.js b/erpnext/crm/report/minutes_to_first_response_for_opportunity/minutes_to_first_response_for_opportunity.js index d9c4c8b7fc8..cdfdad1eea2 100644 --- a/erpnext/crm/report/minutes_to_first_response_for_opportunity/minutes_to_first_response_for_opportunity.js +++ b/erpnext/crm/report/minutes_to_first_response_for_opportunity/minutes_to_first_response_for_opportunity.js @@ -21,23 +21,13 @@ frappe.query_reports["Minutes to First Response for Opportunity"] = { get_chart_data: function (columns, result) { return { data: { - x: 'Date', - columns: [ - ['Date'].concat($.map(result, function (d) { return d[0]; })), - ['Mins to first response'].concat($.map(result, function (d) { return d[1]; })) - ] - // rows: [['Date', 'Mins to first response']].concat(result) + labels: result.map(d => d[0]), + datasets: [{ + title: 'Mins to first response', + values: result.map(d => d[1]) + }] }, - axis: { - x: { - type: 'timeseries', - tick: { - format: frappe.ui.py_date_format - } - } - }, - chart_type: 'line', - + type: 'line', } } } diff --git a/erpnext/demo/user/purchase.py b/erpnext/demo/user/purchase.py index 960a3169cf3..8769b091560 100644 --- a/erpnext/demo/user/purchase.py +++ b/erpnext/demo/user/purchase.py @@ -103,6 +103,7 @@ def make_material_request(item_code, qty): mr.material_request_type = "Purchase" mr.transaction_date = frappe.flags.current_date + mr.schedule_date = frappe.utils.add_days(mr.transaction_date, 7) mr.append("items", { "doctype": "Material Request Item", @@ -128,6 +129,7 @@ def make_subcontract(): po = frappe.new_doc("Purchase Order") po.is_subcontracted = "Yes" po.supplier = get_random("Supplier") + po.schedule_date = frappe.utils.add_days(frappe.flags.current_date, 7) item_code = get_random("Item", {"is_sub_contracted_item": 1}) diff --git a/erpnext/docs/assets/img/human-resources/training_event.png b/erpnext/docs/assets/img/human-resources/training_event.png index 04162eb1e7c..bd1d6dc77a0 100644 Binary files a/erpnext/docs/assets/img/human-resources/training_event.png and b/erpnext/docs/assets/img/human-resources/training_event.png differ diff --git a/erpnext/docs/assets/img/human-resources/training_program.png b/erpnext/docs/assets/img/human-resources/training_program.png new file mode 100644 index 00000000000..97bd2bf7b6d Binary files /dev/null and b/erpnext/docs/assets/img/human-resources/training_program.png differ diff --git a/erpnext/docs/assets/img/restaurant/order-entry-bill.png b/erpnext/docs/assets/img/restaurant/order-entry-bill.png new file mode 100644 index 00000000000..ba96bb3c745 Binary files /dev/null and b/erpnext/docs/assets/img/restaurant/order-entry-bill.png differ diff --git a/erpnext/docs/assets/img/restaurant/order-entry.png b/erpnext/docs/assets/img/restaurant/order-entry.png new file mode 100644 index 00000000000..2fc3e7871a9 Binary files /dev/null and b/erpnext/docs/assets/img/restaurant/order-entry.png differ diff --git a/erpnext/docs/assets/img/restaurant/reservation-kanban.png b/erpnext/docs/assets/img/restaurant/reservation-kanban.png new file mode 100644 index 00000000000..df9517d9a8f Binary files /dev/null and b/erpnext/docs/assets/img/restaurant/reservation-kanban.png differ diff --git a/erpnext/docs/assets/img/restaurant/restaurant-invoice.png b/erpnext/docs/assets/img/restaurant/restaurant-invoice.png new file mode 100644 index 00000000000..9f01dfc55d1 Binary files /dev/null and b/erpnext/docs/assets/img/restaurant/restaurant-invoice.png differ diff --git a/erpnext/docs/assets/img/restaurant/restaurant-menu.png b/erpnext/docs/assets/img/restaurant/restaurant-menu.png new file mode 100644 index 00000000000..e1d85a93372 Binary files /dev/null and b/erpnext/docs/assets/img/restaurant/restaurant-menu.png differ diff --git a/erpnext/docs/assets/img/restaurant/restaurant-reservation.png b/erpnext/docs/assets/img/restaurant/restaurant-reservation.png new file mode 100644 index 00000000000..3467bc04f13 Binary files /dev/null and b/erpnext/docs/assets/img/restaurant/restaurant-reservation.png differ diff --git a/erpnext/docs/assets/img/restaurant/restaurant-table.png b/erpnext/docs/assets/img/restaurant/restaurant-table.png new file mode 100644 index 00000000000..b7ec1d0ed4e Binary files /dev/null and b/erpnext/docs/assets/img/restaurant/restaurant-table.png differ diff --git a/erpnext/docs/assets/img/restaurant/restaurant.png b/erpnext/docs/assets/img/restaurant/restaurant.png new file mode 100644 index 00000000000..1e4e47a1759 Binary files /dev/null and b/erpnext/docs/assets/img/restaurant/restaurant.png differ diff --git a/erpnext/docs/assets/img/schools/admission/student-admission.gif b/erpnext/docs/assets/img/schools/admission/student-admission.gif new file mode 100644 index 00000000000..26caea9cda7 Binary files /dev/null and b/erpnext/docs/assets/img/schools/admission/student-admission.gif differ diff --git a/erpnext/docs/user/manual/en/accounts/credit-limit.md b/erpnext/docs/user/manual/en/accounts/credit-limit.md index 8f92f909513..b48ae5689b1 100644 --- a/erpnext/docs/user/manual/en/accounts/credit-limit.md +++ b/erpnext/docs/user/manual/en/accounts/credit-limit.md @@ -16,7 +16,9 @@ To set credit limit go to Customer - Master Credit Limit -Go to the 'More Info section' and enter the amount in the field Credit Limit. +Go to the 'CREDIT LIMIT' section and enter the amount in the field Credit Limit. + +If you leave CREDIT LIMIT as 0.00, it has no effect. In case a need arises to allow more credit to the customer as a good-will, the Credit Controller has access to submit order even if credit limit is crossed. @@ -26,6 +28,25 @@ has expired, go to accounting settings and make changes. In the field Credit Controller, select the role who would be authorized to accept orders or raise credit limits of customers. + +To set credit limit at Customer Group Level go to Selling -> Customers -> Customer Group + +Go to the 'CREDIT LIMIT' field and enter the amount. +If you leave CREDIT LIMIT as 0.00, it has no effect. + + +To set credit limit at Company level go to Account -> Company + +Go to the 'ACCOUNT SETTINGS' section and enter the amount in the CREDIT LIMIT field. +If you leave CREDIT LIMIT as 0.00, it has no effect. + +For 'CREDIT LIMIT' check functionality, Priority (High to Low) is as below +1) Customer +2) Customer Group +3) Company + + + #### Figure 2: Credit Controller diff --git a/erpnext/docs/user/manual/en/customize-erpnext/articles/field-types.md b/erpnext/docs/user/manual/en/customize-erpnext/articles/field-types.md index 24cb4ab7277..c73ebc76af3 100644 --- a/erpnext/docs/user/manual/en/customize-erpnext/articles/field-types.md +++ b/erpnext/docs/user/manual/en/customize-erpnext/articles/field-types.md @@ -56,6 +56,17 @@ Integer field holds numeric value, without decimal place. Link field is connected to another master from where it fetches data. For example, in the Quotation master, Customer is a Link field. +- Geolocation + +Use Geolocation field to store GeoJSON featurecollection. Stores polygons, lines and points. Internally it uses following custom properties for identifying a circle. + +``` +{ + "point_type": "circle", + "radius": 10.00 +} +``` + - Password Password field will have decode value in it. @@ -84,4 +95,4 @@ Table will be (sort of) Link field which renders another docytpe within the curr Text Editor is text field. It has text-formatting options. In ERPNext, this field is generally used for defining Terms and Conditions. - \ No newline at end of file + diff --git a/erpnext/docs/user/manual/en/hospitality/index.md b/erpnext/docs/user/manual/en/hospitality/index.md new file mode 100644 index 00000000000..efd7377fc41 --- /dev/null +++ b/erpnext/docs/user/manual/en/hospitality/index.md @@ -0,0 +1,9 @@ +# Hospitality + +ERPNext Hospitality module is designed to handle workflows for Hotels and Restaurants. This is still in early development stage. + +### Manage Restaurants + +The Restaurant module in ERPNext will help you manage a chain of restaurants. You can create Restaurants, Menus, Tables, Reservations and a manage Order Entry and Billing. + +{index} \ No newline at end of file diff --git a/erpnext/docs/user/manual/en/hospitality/index.txt b/erpnext/docs/user/manual/en/hospitality/index.txt new file mode 100644 index 00000000000..cbe6da00773 --- /dev/null +++ b/erpnext/docs/user/manual/en/hospitality/index.txt @@ -0,0 +1,4 @@ +restaurant +restaurant-menu +reservations +order-entry \ No newline at end of file diff --git a/erpnext/docs/user/manual/en/hospitality/order-entry.md b/erpnext/docs/user/manual/en/hospitality/order-entry.md new file mode 100644 index 00000000000..929cfd8ef75 --- /dev/null +++ b/erpnext/docs/user/manual/en/hospitality/order-entry.md @@ -0,0 +1,26 @@ +# Restaurant Order Entry + +The Restaurant Order Entry is the screen where the waiters will punch in orders related to a particular table. + +This screen makes it easy for the waiters in your restaurant to punch in orders from various tables. + +When the guest places an order, the waiter will select the table number and add the items in the Order Entry. This can be changed until it is time for the bill. Unless you bill a table, you can change the items and they will automatically appear when you select the table ID. + +To place an order you can select an item and click the enter key so that the item will be updated in the items table. + +Order Entry + +You can also choose items with the POS style item selector. + +### Billing + +When it is time for billing, you just choose the bill and you can select the customer and mode of payment. On saving, a Sales Invoice is generated and the order section becomes empty. + +Order Entry + +### Sales Invoice + +To print the invoice, you can click on the Invoice Link and print the invoice + +Sales Invoice + diff --git a/erpnext/docs/user/manual/en/hospitality/reservations.md b/erpnext/docs/user/manual/en/hospitality/reservations.md new file mode 100644 index 00000000000..0d4a8abde5d --- /dev/null +++ b/erpnext/docs/user/manual/en/hospitality/reservations.md @@ -0,0 +1,13 @@ +# Restaurant Reservations + +Once you have setup the restaurant and tables, you can start taking in reservations for your restaurant. + +To take a reservation, just make a new Restaurant Reservation from the Restaurant Page and set the time, number of people and name of the guest. + +Reservation + +### Kanban + +As your guests walk in, You can also manage the reservations by making a simple Kanban board for the same. + +Reservation Kanban Board diff --git a/erpnext/docs/user/manual/en/hospitality/restaurant-menu.md b/erpnext/docs/user/manual/en/hospitality/restaurant-menu.md new file mode 100644 index 00000000000..dfbf4ce9717 --- /dev/null +++ b/erpnext/docs/user/manual/en/hospitality/restaurant-menu.md @@ -0,0 +1,7 @@ +# Restaurant Menu + +For every restaurant you must set an active Restaurant Menu from which orders can be placed. You can also set the rates for each of the item for the day. + +When you save the Restaurant Menu, a Price List is created for that Menu and all pricing is linked to that price list. This way you can easily control the items on offer and pricing from the menu. + +Restaurant Menu diff --git a/erpnext/docs/user/manual/en/hospitality/restaurant.md b/erpnext/docs/user/manual/en/hospitality/restaurant.md new file mode 100644 index 00000000000..7b72318835e --- /dev/null +++ b/erpnext/docs/user/manual/en/hospitality/restaurant.md @@ -0,0 +1,19 @@ +# Restaurant + +The Restaurant record represents one restaurant in your organization. To create a new Restaurant, just set the name, Company and Default Customer. + +You can set a unique numbering prefix for each of your restaurants. All invoices for that restuarant will follow that numbering prefix. + +If you have a default Sales Taxes and Charges Template, you can add it so that the same charge + tax will be applicable for all invoices in the restaurant. + +Restaurant + +After your restaurant is created, you can add Tables and Menus for that restaurant + +### Adding Tables + +You can add a Restaurant Table by creating a new Restaurant Table from the dashboard. + +Restaurant Table + + diff --git a/erpnext/docs/user/manual/en/human-resources/training.md b/erpnext/docs/user/manual/en/human-resources/training.md index 2aa06791f05..4d39bf1a69c 100644 --- a/erpnext/docs/user/manual/en/human-resources/training.md +++ b/erpnext/docs/user/manual/en/human-resources/training.md @@ -1,8 +1,13 @@ # Training +### Training Program + +Create Training Program and schedule Training Events under it. It has a dashboard linked to Training Event to view which event is under the Training Program. + +Employee ### Training Event -Schedule seminars, workshops, conferences etc using Training Event. You can also invite your employees to attend the event using this feature. +Schedule seminars, workshops, conferences etc using Training Event linked to a Training Program. You can also invite your employees to attend the event using this feature. Employee @@ -14,11 +19,11 @@ By default the status of the employee will be 'Open'. Employee -When you submit the Training Event, a notifcation will be sent to the employee notifying that the Training has been scheduled. This is sent via Email Alert "Training Scheduled". You can modifiy this Email Alert to customize the message. +When you submit the Training Event, a notification will be sent to the employee notifying that the Training has been scheduled. This is sent via Email Alert "Training Scheduled". You can modify this Email Alert to customize the message. ### Training Result -After compleation of the training Employee-wise training results can be stored based on the Feedback received from the Trainer. +After completion of the training Employee-wise training results can be stored based on the Feedback received from the Trainer. Employee diff --git a/erpnext/docs/user/manual/en/introduction/concepts-and-terms.md b/erpnext/docs/user/manual/en/introduction/concepts-and-terms.md index 3a512865428..c53bef92a50 100644 --- a/erpnext/docs/user/manual/en/introduction/concepts-and-terms.md +++ b/erpnext/docs/user/manual/en/introduction/concepts-and-terms.md @@ -97,8 +97,8 @@ fiscal year. A Cost Center is like an Account, but the only difference is that its structure represents your business more closely than Accounts. -For example, in your Chart of Accounts, you can separate your expenses by its type -(i.e., travel, marketing, etc.). In your Chart of Cost Centers, you can separate +For example, in your Chart of Accounts, you can separate your expenses by its type +(i.e., travel, marketing, etc.). In your Chart of Cost Centers, you can separate them by product line or business group (e.g., online sales, retail sales, etc.). > Accounts > Chart of Cost Centers @@ -316,7 +316,7 @@ A record of the monthly salary given to an Employee. #### Salary Structure -A template identifying all the components of an Employees' salary (earnings), +A template identifying all the components of an Employees' salary (earnings), tax and other social security deductions. > Human Resource > Salary and Payroll > Salary Structure diff --git a/erpnext/docs/user/manual/en/introduction/getting-started-with-erpnext.md b/erpnext/docs/user/manual/en/introduction/getting-started-with-erpnext.md index 4aae00ed058..634bb43221f 100644 --- a/erpnext/docs/user/manual/en/introduction/getting-started-with-erpnext.md +++ b/erpnext/docs/user/manual/en/introduction/getting-started-with-erpnext.md @@ -1,7 +1,3 @@ -# Getting Started With Erpnext - - - # Getting Started with ERPNext There are many ways to get started with ERPNext. diff --git a/erpnext/docs/user/manual/en/introduction/the-champion.md b/erpnext/docs/user/manual/en/introduction/the-champion.md index 57086cb9fb1..fca349e5f3f 100644 --- a/erpnext/docs/user/manual/en/introduction/the-champion.md +++ b/erpnext/docs/user/manual/en/introduction/the-champion.md @@ -1,9 +1,5 @@ # The Champion - - -

The Champion

- Champion We have seen dozens of ERP implementations over the past few years and we diff --git a/erpnext/docs/user/manual/en/schools/admission/student_admission.md b/erpnext/docs/user/manual/en/schools/admission/student_admission.md index eeaa977912b..7a63fa7a75c 100644 --- a/erpnext/docs/user/manual/en/schools/admission/student_admission.md +++ b/erpnext/docs/user/manual/en/schools/admission/student_admission.md @@ -1,13 +1,14 @@ # Student Admission -The admission process begins with filling the admission form. The Student Admission record enables to intitate your admission process for a given **Academic year**. ERPNext admission module allow you to create an admission record which can be then published on the ERPNext generate website. +The admission process begins with filling the admission form. The Student Admission record enables to initiate your admission process for a given **Academic year**. ERPNext admission module allows you to create an admission record which can be then published on the ERPNext generate website. To create a Student Admission record go to : **Schools** >> **Admissions** >> **Student Admission** >> -Student Applicant +Student Applicant +Once an admission record is created, the age eligibility criteria can be determined for the every program. Similarly, you can also determine the application fee and naming series for every student applicant. If you keep the naming series blank then the default naming series will be applied for every student applicant. -Once a admission record is created it can be published on the website and the student can apply from the web portal itself. \ No newline at end of file +The information provided in the Student Admission records will be used for the validation and creation of the Student Admission records (only if student admission link is filled there) \ No newline at end of file diff --git a/erpnext/docs/user/manual/en/subscription/index.md b/erpnext/docs/user/manual/en/subscription/index.md deleted file mode 100644 index 24d75eda95d..00000000000 --- a/erpnext/docs/user/manual/en/subscription/index.md +++ /dev/null @@ -1,22 +0,0 @@ -If you have a contract with the Customer where your organization gives bill to the Customer on a monthly, quarterly, half-yearly or annual basis, you can use subscription feature to make auto invoicing. - -Subscription - -#### Scenario - -Subscription for your hosted ERPNext account requires yearly renewal. We use Sales Invoice for generating proforma invoices. To automate proforma invoicing for renewal, we set original Sales Invoice on the subscription form. Recurring proforma invoice is created automatically just before customer's account is about to expire, and requires renewal. This recurring Proforma Invoice is also emailed automatically to the customer. - -To set the subscription for the sales invoice -Goto Subscription > select base doctype "Sales Invoice" > select base docname "Invoice No" > Save - -Subscription - -**From Date and To Date**: This defines contract period with the customer. - -**Repeat on Day**: If frequency is set as Monthly, then it will be day of the month on which recurring invoice will be generated. - -**Notify By Email**: If you want to notify the user about auto recurring invoice. - -**Print Format**: Select a print format to define document view which should be emailed to customer. - -**Disabled**: It will stop to make auto recurring documents against the subscription \ No newline at end of file diff --git a/erpnext/docs/user/manual/es/index.txt b/erpnext/docs/user/manual/es/index.txt index feb68a2fe0b..00cf97b420c 100644 --- a/erpnext/docs/user/manual/es/index.txt +++ b/erpnext/docs/user/manual/es/index.txt @@ -1,3 +1,4 @@ introduction accounts +projects schools diff --git a/erpnext/docs/user/manual/en/subscription/index.txt b/erpnext/docs/user/manual/es/projects/__init__.py similarity index 100% rename from erpnext/docs/user/manual/en/subscription/index.txt rename to erpnext/docs/user/manual/es/projects/__init__.py diff --git a/erpnext/docs/user/manual/es/projects/activity-cost.md b/erpnext/docs/user/manual/es/projects/activity-cost.md new file mode 100644 index 00000000000..71eb15e4326 --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/activity-cost.md @@ -0,0 +1,6 @@ +# Costo de Actividad + +El costo de la actividad registra la tasa de facturación por hora y la tasa de costos de un empleado en comparación con un tipo de actividad. +El sistema hace uso de esta tasa mientras hace registros de tiempo. Se usa para Costeo de proyectos. + +Activity Cost diff --git a/erpnext/docs/user/manual/es/projects/activity-type.md b/erpnext/docs/user/manual/es/projects/activity-type.md new file mode 100644 index 00000000000..20a03e2932d --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/activity-type.md @@ -0,0 +1,15 @@ +# Tipo de Actividad + +Los tipos de actividad son la lista de los diferentes tipos de actividades sobre las que se hacen registro de tiempo. + +Activity Type + +Por defecto, los siguientes tipos de actividades son creados. + +* Planning +* Research +* Proposal Writing +* Execution +* Communication + +{next} \ No newline at end of file diff --git a/erpnext/docs/user/manual/es/projects/articles/__init__.py b/erpnext/docs/user/manual/es/projects/articles/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/docs/user/manual/es/projects/articles/index.md b/erpnext/docs/user/manual/es/projects/articles/index.md new file mode 100644 index 00000000000..2d959ecb6e2 --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/articles/index.md @@ -0,0 +1,3 @@ +# Artículos + +{index} \ No newline at end of file diff --git a/erpnext/docs/user/manual/es/projects/articles/index.txt b/erpnext/docs/user/manual/es/projects/articles/index.txt new file mode 100644 index 00000000000..56c193c2776 --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/articles/index.txt @@ -0,0 +1 @@ +project-costing \ No newline at end of file diff --git a/erpnext/docs/user/manual/es/projects/articles/project-costing.md b/erpnext/docs/user/manual/es/projects/articles/project-costing.md new file mode 100644 index 00000000000..a8820c7e297 --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/articles/project-costing.md @@ -0,0 +1,40 @@ +# Costeo de proyectos + +Cada proyecto tiene multiples tareas asociadas a el. Para hacer el seguimiento del costo actual de un proyecto, primeramente en términos de servicios, el usuario +tiene que crear un registro de tiempo basado en el tiempo que invirtió en una tarea del proyecto. Siguiendo los pasos de como puedes hacer el seguimiento del costo actual de un servicio usando el proyecto. + +#### Tipo de actividad + +Tipo de actividad es un maestro de los servicios ofrecidos por su personal. Puedes agregar un nuevo Tipo de Actividad desde: + +`Project > Activity Type > New` + +#### Costo de actividad + +Costo de actividad es un maestro donde puedes hacer el seguimiento de los montos de facturación y costo de cada empleado, y por cada tipo de Tipo de Actividad. + +Activity Cost + +#### Registro de Tiempo + +Basados en el tiempo actual invertido en una Tarea del Proyecto, El empleado va a crear un registro de tiempo. + +Time Log + +Al momento de seleccionar el Tipo de Actividad en el Registro de tiempo, el monto de Facturación y Costo del empleado va a ser traído de su respectivo registro en el master de Costo de Actividad. + +Time Log Costing + +Multiplicando esos montos con el total de número de horas en el registro de tiempo, nos da el monto de costos y Facturación para el registro de tiempo específico. + +#### Costeo en Proyectos y Tareas + +Basados en el total de registros de tiempos creados por una tarea en específico, su costo va a ser actualizado en el registro maestro de la tarea, o sea, en el detalle de la tarea. + +Costing in Task + +De la misma manera, el detalle del Proyecto va a actualizar su costo basado en el total de registros de tiempo a ese proyecto, y las tareas asociadas a ese proyecto. + +Costing in Project + + \ No newline at end of file diff --git a/erpnext/docs/user/manual/es/projects/index.md b/erpnext/docs/user/manual/es/projects/index.md new file mode 100644 index 00000000000..0882752a404 --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/index.md @@ -0,0 +1,15 @@ +# Proyectos + +ERPNext le ayuda en la administración de su proyecto a traves de la creacion de tareas y +poder asignarlas a diferentes personas. + +Las compras y las ventas también se pueden rastrear en relación con los proyectos y +esto puede ayudar a la empresa a controlar su presupuesto, entrega y rentabilidad para un proyecto. + +Los proyectos pueden ser usados para manejar los proyectos internos, trabajos de manufacturación y +planificación de servicios. Para los trabajos de servicios, los Time Sheets (hojas de tiempo) pueden ser creadas +para facturar a los clientes, en caso que el proceso de facturación se haga basado en tiempo y dinero de tareas. + +### Temas + +{index} \ No newline at end of file diff --git a/erpnext/docs/user/manual/es/projects/index.txt b/erpnext/docs/user/manual/es/projects/index.txt new file mode 100644 index 00000000000..716ec1fe3aa --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/index.txt @@ -0,0 +1,7 @@ +tasks +project +time-log-batch +activity-type +activity-cost +articles +timesheet \ No newline at end of file diff --git a/erpnext/docs/user/manual/es/projects/project.md b/erpnext/docs/user/manual/es/projects/project.md new file mode 100644 index 00000000000..942433b47b0 --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/project.md @@ -0,0 +1,110 @@ +# Proyecto + +El manejo de proyectos en ERPNext se hace a traves de tareas. Puedes crear un proyecto y asignar varias tareas al mismo. + +Project + +También puedes hacer el seguimiento del % completado del proyecto usando diferentes métodos. + + 1. Tareas Completadas + 2. Progreso de tareas + 3. Peso de tarea + +Project + +Algunos ejemplos de como el % completado es cálculado basado en tareas. + +Project + +Project + +### Manejando tareas + +Los proyecto pueden ser divididos en multiples tareas. +Las tareas pueden ser creadas a traves del documento de Proyecto o pueden ser creadas via [Tarea](/docs/user/manual/en/projects/tasks.html) + +Project + +* Para ver las tareas creadas a un proyecto click en 'Tasks' + +Project - View Task + +Project - Task List + +* También puedes ver las tareas desde la misma vista del proyecto. + +Project - Task Grid + +* Para agregar peso a las tareas puedes seguir los pasos siguientes + +Project - Task Grid +Project - Task Grid + + +### Manejando tiempo + +ERPNext usa [Time Log](/docs/user/manual/en/projects/time-log.html) para hacer el seguimiento del progreso de un Proyecto. +Puedes crear registros de tiempo sobre cada Tarea. +El tiempo actual de inicio y finalización junto con el costo deben ser actualizados basados en los Registros de Tiempo. + +* Para ver los Registros de Tiempo realizados a un proyecto, dar click en 'Time Logs' + +Project - View Time Log + +Project - Time Log List + +* Puedes agregar un registro de tiempo directamente y luego asociarlo con el proyecto. + +Project - Link Time Log + +### Gestión de gastos + +Puede reservar la [Reclamación de gastos](/docs/user/manual/en/human-resources/expense-claim.html) contra una tarea de proyecto. +El sistema actualizará el monto total de las reclamaciones de gastos en la sección de costos del proyecto. + +* Para ver las reclamaciones de gastos realizadas en un proyecto, haga clic en 'Reclamaciones de gastos' + +Project - View Expense Claim + +* También puede crear un Reclamo de gastos directamente y vincularlo al Proyecto. + +Project - Link Expense Claim + +* El monto total de los Reclamos de gastos reservados contra un proyecto se muestra en 'Reclamo de gastos totales' en la Sección de Costos del proyecto + +Project - Total Expense Claim + +### Centro de Costo + +Puedes crear un [Cost Center](/docs/user/manual/en/accounts/setup/cost-center.html) sobre un proyecto o usar un centro de costo existente para hacer el seguimiento de todos los gastos realizados al proyecto. + +Project - Cost Center + +###Costeo del proyecto + +La sección Costeo del proyecto le ayuda a rastrear el tiempo y los gastos incurridos en relación con el proyecto. + +Project - Costing + +* La sección de cálculo de costos se actualiza según los registros de tiempo realizados. + +* El margen bruto es la diferencia entre el monto total de costos y el monto total de facturación + +###Facturación + +Puedes crear/enlazar una [Sales Order](/docs/user/manual/en/selling/sales-order.html) a un proyecto. Una vez asociada puedes usar el módulo de ventas para facturar a un cliente sobre el proyecto. + +Project - Sales Order + +###Gantt Chart + +Un Gantt Chart muestra la planificación del proyecto. +ERPNext te provee con una vista para visualizar las tareas de forma calendarizada usando un Gantt Chart (Hoja de Gantt). + +* Para visualizar el gantt chart de un proyecto, ve hasta el proyecto y dar click en 'Gantt Chart' + +Project - View Gantt Chart + +Project - Gantt Chart + +{next} diff --git a/erpnext/docs/user/manual/es/projects/tasks.md b/erpnext/docs/user/manual/es/projects/tasks.md new file mode 100644 index 00000000000..b07b305b7ac --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/tasks.md @@ -0,0 +1,61 @@ +# Tareas + +Proyecto es dividido en Tareas. +En ERPNext, puedes crear las tareas de forma independiente. + +Task + +### Estado de una Tarea + +Una tarea puede tener uno de los siguientes estados - Abierto, Trabajando, Pendiente de Revisión, Cerrado, o Cancelado. + +Task - Status + +* Por defecto, cada nueva tarea creada se le establece el estado 'Abierto'. + +* Si un registro de tiempo es realizado sobre una tarea, su estado es asignado a 'Working'. + +### Tarea Dependiente + +Puedes especificar una lista de tareas dependientes en la sección 'Depende de' + +Depends On + +* No puedes cerrar una tarea padre hasta que todas las tareas dependientes esten cerradas. + +* Si una tarea dependiente se encuentra en retraso y se sobrepone con la fecha esperada de inicio de la tarea padre, el sistema va a re calandarizar la tarea padre. + +### Manejando el tiempo + +ERPNext usa [Time Log](/docs/user/manual/en/projects/time-log.html) para seguir el progreso de una tarea. +Puedes crear varios registros de tiempo para cada tarea. +El tiempo de inicio y fin actual junto con el costo es actualizado en base al Registro de Tiempo. + +* Para ver el Registro de tiempo realizado a una tarea, dar click en 'Time Logs' + +Task - View Time Log + +Task - Time Log List + +* Puedes también crear un Registro de Tiempo directamente y luego asociarlo a una Tarea. + +Task - Link Time Log + +### Gestión de gastos + +Puede reservar la [Reclamación de gastos](/docs/user/manual/en/human-resources/expense-claim.html) contra una tarea de proyecto. +El sistema actualizará el monto total de las reclamaciones de gastos en la sección de costos del proyecto. + +* Para ver las reclamaciones de gastos realizadas en un proyecto, haga clic en 'Reclamaciones de gastos' + +Task - View Expense Claim + +* También puede crear un Reclamo de gastos directamente y vincularlo al Proyecto. + +Task - Link Expense Claim + +* El monto total de los Reclamos de gastos reservados contra un proyecto se muestra en 'Reclamo de gastos totales' en la Sección de Costos del proyecto + +Task - Total Expense Claim + +{next} diff --git a/erpnext/docs/user/manual/es/projects/time-log-batch.md b/erpnext/docs/user/manual/es/projects/time-log-batch.md new file mode 100644 index 00000000000..72c77b4ff82 --- /dev/null +++ b/erpnext/docs/user/manual/es/projects/time-log-batch.md @@ -0,0 +1,25 @@ +# Lote de registro de tiempo + +Puede facturar Registros de tiempo viéndolos juntos. Esto le da la flexibilidad de administrar la facturación de su cliente de la manera que desee. Para crear una nueva hoja de tiempo, ve a + +> Projects > Time Sheet > New Time Sheet + +O + +Simplemente abra su lista de registro de tiempo y marque los elementos que desea agregar al registro de tiempo. A continuación, haga clic en el botón "Crear hoja de tiempo" y se seleccionarán estos registros de tiempo. + +Time Log - Drag Calender + +###Creando Factura de Venta + +* Despues de crear la Hoja de Tiempo/Horario, el botón "Crear Factura" debe aparecer. + +Time Log - Drag Calender + +* Haga clic en ese botón para hacer una factura de venta usando la hoja de tiempo. + +Time Log - Drag Calender + +* Cuando "Presente" la Factura de Ventas, el número de Factura de Ventas se actualizará en los Registros de Tiempo y la Hoja de Horario y su estado cambiará a "Facturado". + +{next} \ No newline at end of file diff --git a/erpnext/domains/__init__.py b/erpnext/domains/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/domains/distribution.py b/erpnext/domains/distribution.py new file mode 100644 index 00000000000..020ab3b83b1 --- /dev/null +++ b/erpnext/domains/distribution.py @@ -0,0 +1,18 @@ +data = { + 'desktop_icons': [ + 'Item', + 'Customer', + 'Supplier', + 'Lead', + 'Sales Order', + 'Purchase Order', + 'Task', + 'Sales Invoice', + 'CRM', + 'ToDo' + ], + 'set_value': [ + ['Stock Settings', None, 'show_barcode_field', 1] + ], + 'default_portal_role': 'Customer' +} diff --git a/erpnext/domains/education.py b/erpnext/domains/education.py new file mode 100644 index 00000000000..7a86c764c81 --- /dev/null +++ b/erpnext/domains/education.py @@ -0,0 +1,37 @@ +data = { + 'desktop_icons': [ + 'Student', + 'Program', + 'Course', + 'Student Group', + 'Instructor', + 'Fees', + 'Task', + 'ToDo', + 'Schools' + ], + 'default_portal_role': 'Student', + 'restricted_roles': [ + 'Student', + 'Instructor', + 'Academics User' + ], + 'modules': [ + 'Schools' + ], + 'fixtures': [ + dict(doctype='Academic Year', academic_year_name='2013-14'), + dict(doctype='Academic Year', academic_year_name='2014-15'), + dict(doctype='Academic Year', academic_year_name='2015-16'), + dict(doctype='Academic Year', academic_year_name='2016-17'), + dict(doctype='Academic Year', academic_year_name='2017-18'), + dict(doctype='Academic Year', academic_year_name='2018-19'), + dict(doctype='Academic Year', academic_year_name='2019-20'), + dict(doctype='Academic Term', academic_year='2016-17', term_name='Semester 1'), + dict(doctype='Academic Term', academic_year='2016-17', term_name='Semester 2'), + dict(doctype='Academic Term', academic_year='2016-17', term_name='Semester 3'), + dict(doctype='Academic Term', academic_year='2017-18', term_name='Semester 1'), + dict(doctype='Academic Term', academic_year='2017-18', term_name='Semester 2'), + dict(doctype='Academic Term', academic_year='2017-18', term_name='Semester 3') + ] +} \ No newline at end of file diff --git a/erpnext/domains/healthcare.py b/erpnext/domains/healthcare.py new file mode 100644 index 00000000000..3c54b01d424 --- /dev/null +++ b/erpnext/domains/healthcare.py @@ -0,0 +1,29 @@ +data = { + 'desktop_icons': [ + 'Patient', + 'Patient Appointment', + 'Consultation', + 'Lab Test', + 'Healthcare', + 'Accounts', + 'Buying', + 'Stock', + 'HR', + 'ToDo' + ], + 'default_portal_role': 'Patient', + 'restricted_roles': [ + 'Healthcare Administrator', + 'LabTest Approver', + 'Laboratory User', + 'Nursing User', + 'Physician', + 'Patient' + ], + 'custom_fields': { + 'Sales Invoice': dict(fieldname='appointment', label='Patient Appointment', + fieldtype='Link', options='Patient Appointment', + insert_after='customer') + }, + 'on_setup': 'erpnext.healthcare.setup.setup_healthcare' +} \ No newline at end of file diff --git a/erpnext/domains/hospitality.py b/erpnext/domains/hospitality.py new file mode 100644 index 00000000000..bc55d9c47a6 --- /dev/null +++ b/erpnext/domains/hospitality.py @@ -0,0 +1,32 @@ +data = { + 'desktop_icons': [ + 'Restaurant', + 'Accounts', + 'Buying', + 'Stock', + 'HR', + 'Project', + 'ToDo' + ], + 'restricted_roles': [ + 'Restaurant Manager' + ], + 'custom_fields': { + 'Sales Invoice': [ + { + 'fieldname': 'restaurant', 'fieldtype': 'Link', 'options': 'Restaurant', + 'insert_after': 'customer_name', 'label': 'Restaurant', + }, + { + 'fieldname': 'restaurant_table', 'fieldtype': 'Link', 'options': 'Restaurant Table', + 'insert_after': 'restaurant', 'label': 'Restaurant Table', + } + ], + 'Price List': [ + { + 'fieldname':'restaurant_menu', 'fieldtype':'Link', 'options':'Restaurant Menu', 'label':'Restaurant Menu', + 'insert_after':'currency' + } + ] + } +} diff --git a/erpnext/domains/manufacturing.py b/erpnext/domains/manufacturing.py new file mode 100644 index 00000000000..b8bb7e05783 --- /dev/null +++ b/erpnext/domains/manufacturing.py @@ -0,0 +1,25 @@ +data = { + 'desktop_icons': [ + 'Item', + 'BOM', + 'Customer', + 'Supplier', + 'Sales Order', + 'Purchase Order', + 'Production Order', + 'Task', + 'Accounts', + 'HR', + 'ToDo' + ], + 'properties': [ + {'doctype': 'Item', 'fieldname': 'manufacturing', 'property': 'collapsible_depends_on', 'value': 'is_stock_item'}, + ], + 'set_value': [ + ['Stock Settings', None, 'show_barcode_field', 1] + ], + 'restricted_roles': [ + 'Manufacturing User' + ], + 'default_portal_role': 'Customer' +} \ No newline at end of file diff --git a/erpnext/domains/retail.py b/erpnext/domains/retail.py new file mode 100644 index 00000000000..1bfd65faf82 --- /dev/null +++ b/erpnext/domains/retail.py @@ -0,0 +1,20 @@ +data = { + 'desktop_icons': [ + 'POS', + 'Item', + 'Customer', + 'Sales Invoice', + 'Purchase Order', + 'Accounts', + 'Task', + 'ToDo' + ], + 'properties': [ + {'doctype': 'Item', 'fieldname': 'manufacturing', 'property': 'hidden', 'value': 1}, + {'doctype': 'Customer', 'fieldname': 'credit_limit_section', 'property': 'hidden', 'value': 1}, + ], + 'set_value': [ + ['Stock Settings', None, 'show_barcode_field', 1] + ], + 'default_portal_role': 'Customer' +} diff --git a/erpnext/domains/services.py b/erpnext/domains/services.py new file mode 100644 index 00000000000..1fb0e19edd2 --- /dev/null +++ b/erpnext/domains/services.py @@ -0,0 +1,19 @@ +data = { + 'desktop_icons': [ + 'Project', + 'Timesheet', + 'Customer', + 'Sales Order', + 'Sales Invoice', + 'CRM', + 'Task', + 'Expense Claim', + 'Employee', + 'HR', + 'ToDo' + ], + 'set_value': [ + ['Stock Settings', None, 'show_barcode_field', 0] + ], + 'default_portal_role': 'Customer' +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.json b/erpnext/healthcare/doctype/appointment_type/appointment_type.json index 4b34892ffd3..9d331fa74be 100644 --- a/erpnext/healthcare/doctype/appointment_type/appointment_type.json +++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.json @@ -22,7 +22,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -62,11 +62,11 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -83,7 +83,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:46:57.142289", + "modified": "2017-10-05 11:07:26.369657", "modified_by": "Administrator", "module": "Healthcare", "name": "Appointment Type", diff --git a/erpnext/healthcare/doctype/codification_table/codification_table.json b/erpnext/healthcare/doctype/codification_table/codification_table.json index c4117782ffd..7818a42ac5e 100644 --- a/erpnext/healthcare/doctype/codification_table/codification_table.json +++ b/erpnext/healthcare/doctype/codification_table/codification_table.json @@ -21,7 +21,7 @@ "fieldname": "medical_code", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -53,7 +53,7 @@ "fieldtype": "Read Only", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -84,7 +84,7 @@ "fieldtype": "Read Only", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -116,7 +116,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 14:06:50.281545", + "modified": "2017-10-04 17:07:22.880451", "modified_by": "Administrator", "module": "Healthcare", "name": "Codification Table", diff --git a/erpnext/healthcare/doctype/complaint/complaint.json b/erpnext/healthcare/doctype/complaint/complaint.json index 0899a399715..f600838b654 100644 --- a/erpnext/healthcare/doctype/complaint/complaint.json +++ b/erpnext/healthcare/doctype/complaint/complaint.json @@ -23,7 +23,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -54,7 +54,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:44:31.848346", + "modified": "2017-10-05 11:18:42.017864", "modified_by": "Administrator", "module": "Healthcare", "name": "Complaint", diff --git a/erpnext/healthcare/doctype/consultation/consultation.json b/erpnext/healthcare/doctype/consultation/consultation.json index 70482cba555..400703af614 100644 --- a/erpnext/healthcare/doctype/consultation/consultation.json +++ b/erpnext/healthcare/doctype/consultation/consultation.json @@ -63,11 +63,11 @@ "options": "C-", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -83,7 +83,7 @@ "fieldname": "appointment", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -114,7 +114,7 @@ "fieldname": "type", "fieldtype": "Link", "hidden": 1, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -122,15 +122,15 @@ "in_standard_filter": 0, "label": "Type", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Appointment Type", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -145,12 +145,12 @@ "fieldname": "patient", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Patient", "length": 0, "no_copy": 0, @@ -188,11 +188,11 @@ "options": "", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -219,11 +219,11 @@ "options": "\nMale\nFemale", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -243,7 +243,7 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Doctor", "length": 0, "no_copy": 0, @@ -329,12 +329,12 @@ "fieldname": "visit_department", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Department", "length": 0, "no_copy": 0, @@ -347,7 +347,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -430,7 +430,7 @@ "in_standard_filter": 0, "label": "Invoice", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Sales Invoice", "permlevel": 0, "precision": "", @@ -493,11 +493,11 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -542,7 +542,7 @@ "fieldname": "symptoms_select", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -550,15 +550,15 @@ "in_standard_filter": 0, "label": "Complaints", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Complaint", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -574,14 +574,14 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", "print_hide": 0, @@ -612,14 +612,14 @@ "in_standard_filter": 0, "label": "In print", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -665,7 +665,7 @@ "fieldname": "diagnosis_select", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -673,15 +673,15 @@ "in_standard_filter": 0, "label": "Diagnosis", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Diagnosis", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -698,14 +698,14 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", "print_hide": 0, @@ -737,14 +737,14 @@ "in_standard_filter": 0, "label": "In print", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -943,14 +943,14 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Review Details", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", "print_hide": 0, @@ -1004,7 +1004,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 14:24:59.935498", + "modified": "2017-10-05 12:13:52.596750", "modified_by": "Administrator", "module": "Healthcare", "name": "Consultation", diff --git a/erpnext/healthcare/doctype/consultation/consultation.py b/erpnext/healthcare/doctype/consultation/consultation.py index b8155b9b490..e16c22176c7 100755 --- a/erpnext/healthcare/doctype/consultation/consultation.py +++ b/erpnext/healthcare/doctype/consultation/consultation.py @@ -78,7 +78,7 @@ def create_invoice(company, patient, physician, consultation_id): create_invoice_items(physician, sales_invoice, company) sales_invoice.save(ignore_permissions=True) - frappe.db.sql(_("""update tabConsultation set invoice='{0}' where name='{1}'""").format(sales_invoice.name, consultation_id)) + frappe.db.sql("""update tabConsultation set invoice=%s where name=%s""", (sales_invoice.name, consultation_id)) appointment = frappe.db.get_value("Consultation", consultation_id, "appointment") if appointment: frappe.db.set_value("Patient Appointment", appointment, "sales_invoice", sales_invoice.name) diff --git a/erpnext/healthcare/doctype/diagnosis/diagnosis.json b/erpnext/healthcare/doctype/diagnosis/diagnosis.json index b14ce9491c6..936c2c50a99 100644 --- a/erpnext/healthcare/doctype/diagnosis/diagnosis.json +++ b/erpnext/healthcare/doctype/diagnosis/diagnosis.json @@ -23,7 +23,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -54,7 +54,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:40:09.731904", + "modified": "2017-10-05 11:25:46.107435", "modified_by": "Administrator", "module": "Healthcare", "name": "Diagnosis", diff --git a/erpnext/healthcare/doctype/dosage_form/dosage_form.json b/erpnext/healthcare/doctype/dosage_form/dosage_form.json index 1de0e937d9f..350aaedcba9 100644 --- a/erpnext/healthcare/doctype/dosage_form/dosage_form.json +++ b/erpnext/healthcare/doctype/dosage_form/dosage_form.json @@ -23,7 +23,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -54,7 +54,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:40:19.973532", + "modified": "2017-10-05 11:24:57.888091", "modified_by": "Administrator", "module": "Healthcare", "name": "Dosage Form", diff --git a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json index c96df228c2c..5647d3c88e9 100644 --- a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json +++ b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json @@ -21,7 +21,7 @@ "fieldname": "drug_code", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -83,7 +83,7 @@ "fieldname": "dosage", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -114,7 +114,7 @@ "fieldname": "period", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -145,7 +145,7 @@ "fieldname": "dosage_form", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -206,7 +206,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -341,11 +341,11 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -362,7 +362,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 13:59:48.222282", + "modified": "2017-10-04 17:09:54.998517", "modified_by": "Administrator", "module": "Healthcare", "name": "Drug Prescription", diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.json b/erpnext/healthcare/doctype/fee_validity/fee_validity.json index 4bbd20b9bae..595539cd852 100644 --- a/erpnext/healthcare/doctype/fee_validity/fee_validity.json +++ b/erpnext/healthcare/doctype/fee_validity/fee_validity.json @@ -39,7 +39,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -70,7 +70,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -206,7 +206,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:36:52.108407", + "modified": "2017-10-05 11:26:35.292841", "modified_by": "Administrator", "module": "Healthcare", "name": "Fee Validity", diff --git a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py index 23458729832..53f82e034cd 100644 --- a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py +++ b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py @@ -19,13 +19,13 @@ class TestFeeValidity(unittest.TestCase): patient = frappe.new_doc("Patient") patient.patient_name = "Test Patient" patient.sex = "Male" - patient.save(ignore_permissions = True) + patient.save(ignore_permissions=True) patient = patient.name if not physician: physician = frappe.new_doc("Physician") - physician.first_name= "Amit Jain" - physician.save(ignore_permissions = True) + physician.first_name = "Amit Jain" + physician.save(ignore_permissions=True) physician = physician.name frappe.db.set_value("Healthcare Settings", None, "max_visit", 2) @@ -50,5 +50,5 @@ def create_appointment(patient, physician, appointment_date): appointment.patient = patient appointment.physician = physician appointment.appointment_date = appointment_date - appointment.save(ignore_permissions = True) + appointment.save(ignore_permissions=True) return appointment diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json index 8681641fde5..7d9f2c78513 100644 --- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json +++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json @@ -359,7 +359,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -421,7 +421,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -544,7 +544,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -942,7 +942,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1002,7 +1002,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1033,7 +1033,7 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:25:48.193218", + "modified": "2017-10-05 11:36:44.087182", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare Settings", diff --git a/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py b/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py new file mode 100644 index 00000000000..1b620d5f5da --- /dev/null +++ b/erpnext/healthcare/doctype/healthcare_settings/test_healthcare_settings.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals +import unittest + +class TestHealthcareSettings(unittest.TestCase): + pass diff --git a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json b/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json index 2d1a8d6b255..cd9943b76da 100644 --- a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json +++ b/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json @@ -20,7 +20,7 @@ "fieldname": "test_code", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -143,7 +143,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -180,14 +180,14 @@ "in_standard_filter": 0, "label": "Test Created", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -204,7 +204,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 13:47:22.789095", + "modified": "2017-10-04 17:42:32.976165", "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Prescription", diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.json b/erpnext/healthcare/doctype/lab_test/lab_test.json index 93e40ccb716..8677c82d077 100644 --- a/erpnext/healthcare/doctype/lab_test/lab_test.json +++ b/erpnext/healthcare/doctype/lab_test/lab_test.json @@ -38,7 +38,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 1, "search_index": 0, "set_only_once": 0, @@ -61,7 +61,7 @@ "in_standard_filter": 0, "label": "Invoice", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Sales Invoice", "permlevel": 0, "precision": "", @@ -84,12 +84,12 @@ "fieldname": "patient", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Patient", "length": 0, "no_copy": 0, @@ -131,7 +131,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -161,7 +161,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -192,7 +192,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 1, "search_index": 0, "set_only_once": 1, @@ -207,7 +207,7 @@ "fieldname": "physician", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -225,7 +225,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -253,7 +253,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -283,9 +283,9 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -314,7 +314,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -358,7 +358,7 @@ "fieldname": "department", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -376,7 +376,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -405,9 +405,9 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -435,7 +435,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -465,7 +465,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -480,7 +480,7 @@ "fieldname": "sample", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -496,7 +496,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -551,7 +551,7 @@ "in_standard_filter": 0, "label": "Lab Technician", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Employee", "permlevel": 0, "precision": "", @@ -559,7 +559,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -582,7 +582,7 @@ "in_standard_filter": 0, "label": "Technician Name", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "employee.employee_name", "permlevel": 0, "precision": "", @@ -590,7 +590,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -613,7 +613,7 @@ "in_standard_filter": 0, "label": "Designation", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "employee.designation", "permlevel": 0, "precision": "", @@ -621,7 +621,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -644,7 +644,7 @@ "in_standard_filter": 0, "label": "User", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "User", "permlevel": 0, "precision": "", @@ -652,7 +652,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -682,7 +682,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -731,7 +731,7 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Test Name", "length": 0, "no_copy": 1, @@ -741,9 +741,9 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -785,7 +785,7 @@ "fieldname": "template", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -801,7 +801,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 1, "search_index": 0, "set_only_once": 1, @@ -832,7 +832,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -950,7 +950,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1009,7 +1009,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1054,7 +1054,7 @@ "fieldtype": "Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1114,7 +1114,7 @@ "fieldtype": "Text Editor", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1158,7 +1158,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1189,7 +1189,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1219,7 +1219,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1249,7 +1249,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1279,7 +1279,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1309,7 +1309,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1339,7 +1339,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1362,7 +1362,7 @@ "in_standard_filter": 0, "label": "Prescription", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Lab Prescription", "permlevel": 0, "precision": "", @@ -1370,7 +1370,7 @@ "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -1388,7 +1388,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:52:14.180774", + "modified": "2017-10-05 12:14:57.078823", "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Test", diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py index 0daf9cba73d..6fd9535ecc3 100644 --- a/erpnext/healthcare/doctype/lab_test/lab_test.py +++ b/erpnext/healthcare/doctype/lab_test/lab_test.py @@ -291,5 +291,5 @@ def create_invoice(company, patient, lab_tests, prescriptions): @frappe.whitelist() def get_lab_test_prescribed(patient): - return frappe.db.sql(_("""select cp.name, cp.test_code, cp.parent, cp.invoice, ct.physician, ct.consultation_date from tabConsultation ct, - `tabLab Prescription` cp where ct.patient='{0}' and cp.parent=ct.name and cp.test_created=0""").format(patient)) + return frappe.db.sql("""select cp.name, cp.test_code, cp.parent, cp.invoice, ct.physician, ct.consultation_date from tabConsultation ct, + `tabLab Prescription` cp where ct.patient=%s and cp.parent=ct.name and cp.test_created=0""", (patient)) diff --git a/erpnext/healthcare/doctype/lab_test_groups/lab_test_groups.json b/erpnext/healthcare/doctype/lab_test_groups/lab_test_groups.json index d5607f05616..86be5443590 100644 --- a/erpnext/healthcare/doctype/lab_test_groups/lab_test_groups.json +++ b/erpnext/healthcare/doctype/lab_test_groups/lab_test_groups.json @@ -34,11 +34,11 @@ "options": "Add Test\nAdd new line", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -54,7 +54,7 @@ "fieldname": "test_template", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -97,11 +97,11 @@ "options": "test_template.test_rate", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -117,7 +117,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -149,7 +149,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -179,7 +179,7 @@ "fieldname": "group_test_uom", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -212,7 +212,7 @@ "fieldtype": "Long Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -272,7 +272,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 14:07:35.188661", + "modified": "2017-10-04 16:55:45.081003", "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Test Groups", diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json index 9e692d5418f..091e2f9a1ad 100644 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json +++ b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json @@ -26,7 +26,7 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Test Name", "length": 0, "no_copy": 1, @@ -69,7 +69,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -113,12 +113,12 @@ "fieldname": "test_group", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Item Group", "length": 0, "no_copy": 0, @@ -131,7 +131,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -144,12 +144,12 @@ "fieldname": "department", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Department", "length": 0, "no_copy": 0, @@ -211,7 +211,7 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Result Format", "length": 0, "no_copy": 0, @@ -257,7 +257,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -334,7 +334,7 @@ "fieldname": "test_uom", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -366,7 +366,7 @@ "fieldtype": "Long Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -670,7 +670,7 @@ "fieldtype": "Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -729,7 +729,7 @@ "fieldname": "sample", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -823,7 +823,7 @@ "fieldtype": "Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -861,14 +861,14 @@ "in_standard_filter": 0, "label": "Change In Item", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -895,11 +895,11 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -916,7 +916,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:45:27.655822", + "modified": "2017-10-05 12:12:11.918652", "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Test Template", diff --git a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.json b/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.json index daa533dfa6f..fab88e2268d 100644 --- a/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.json +++ b/erpnext/healthcare/doctype/lab_test_uom/lab_test_uom.json @@ -22,7 +22,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -52,7 +52,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -83,7 +83,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:41:40.186676", + "modified": "2017-10-05 11:24:15.687464", "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Test UOM", diff --git a/erpnext/healthcare/doctype/medical_code/medical_code.json b/erpnext/healthcare/doctype/medical_code/medical_code.json index 71a2278b071..a2e72475179 100644 --- a/erpnext/healthcare/doctype/medical_code/medical_code.json +++ b/erpnext/healthcare/doctype/medical_code/medical_code.json @@ -21,7 +21,7 @@ "fieldname": "medical_code_standard", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -53,7 +53,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -83,7 +83,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -114,7 +114,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 14:01:18.817484", + "modified": "2017-10-04 17:08:11.053418", "modified_by": "Administrator", "module": "Healthcare", "name": "Medical Code", diff --git a/erpnext/healthcare/doctype/normal_test_items/normal_test_items.json b/erpnext/healthcare/doctype/normal_test_items/normal_test_items.json index 9e754a74dc0..f53f001569f 100644 --- a/erpnext/healthcare/doctype/normal_test_items/normal_test_items.json +++ b/erpnext/healthcare/doctype/normal_test_items/normal_test_items.json @@ -21,7 +21,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -51,7 +51,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -82,7 +82,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -142,7 +142,7 @@ "fieldtype": "Long Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -182,11 +182,11 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -217,7 +217,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -248,7 +248,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -265,7 +265,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 13:59:33.202695", + "modified": "2017-10-04 17:13:06.376928", "modified_by": "Administrator", "module": "Healthcare", "name": "Normal Test Items", diff --git a/erpnext/healthcare/doctype/normal_test_template/normal_test_template.json b/erpnext/healthcare/doctype/normal_test_template/normal_test_template.json index ef5abd5652b..265c1163b75 100644 --- a/erpnext/healthcare/doctype/normal_test_template/normal_test_template.json +++ b/erpnext/healthcare/doctype/normal_test_template/normal_test_template.json @@ -21,7 +21,7 @@ "fieldtype": "Heading", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -51,7 +51,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -80,7 +80,7 @@ "fieldname": "test_uom", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -112,7 +112,7 @@ "fieldtype": "Long Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -172,7 +172,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 14:07:11.277187", + "modified": "2017-10-04 16:58:43.990804", "modified_by": "Administrator", "module": "Healthcare", "name": "Normal Test Template", diff --git a/erpnext/healthcare/doctype/patient/patient.json b/erpnext/healthcare/doctype/patient/patient.json index f5ce458f7d8..6f9f2fc5e92 100644 --- a/erpnext/healthcare/doctype/patient/patient.json +++ b/erpnext/healthcare/doctype/patient/patient.json @@ -67,11 +67,11 @@ "options": "PID-", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -91,7 +91,7 @@ "in_filter": 1, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Full Name", "length": 0, "no_copy": 1, @@ -217,14 +217,14 @@ "in_standard_filter": 0, "label": "Age", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -248,7 +248,7 @@ "in_standard_filter": 0, "label": "Status", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Active\nDormant\nOpen", "permlevel": 0, "precision": "", @@ -256,7 +256,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -279,14 +279,14 @@ "in_standard_filter": 0, "label": "Image", "length": 0, - "no_copy": 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, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -331,7 +331,7 @@ "fieldname": "customer", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -374,11 +374,11 @@ "options": "Company", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -429,7 +429,7 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Mobile", "length": 0, "no_copy": 0, @@ -459,7 +459,7 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Email", "length": 0, "no_copy": 0, @@ -524,14 +524,14 @@ "in_standard_filter": 0, "label": "Disabled", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -638,14 +638,14 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Allergies", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", "print_hide": 0, @@ -668,7 +668,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -727,7 +727,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -757,7 +757,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -817,11 +817,11 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Occupation", "length": 0, "no_copy": 0, @@ -937,7 +937,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -967,7 +967,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -997,7 +997,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1026,7 +1026,7 @@ "fieldname": "alcohol_current_use", "fieldtype": "Data", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -1086,7 +1086,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1116,7 +1116,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1180,7 +1180,7 @@ "fieldtype": "Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1240,7 +1240,7 @@ "fieldtype": "Link", "hidden": 1, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -1251,7 +1251,7 @@ "options": "Currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -1274,7 +1274,7 @@ "issingle": 0, "istable": 0, "max_attachments": 50, - "modified": "2017-08-31 13:50:25.474398", + "modified": "2017-10-04 17:41:03.219934", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient", diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py index 98526cc027e..f4d9a43ea3a 100644 --- a/erpnext/healthcare/doctype/patient/patient.py +++ b/erpnext/healthcare/doctype/patient/patient.py @@ -111,10 +111,10 @@ def make_invoice(patient, company): @frappe.whitelist() def get_patient_detail(patient, company=None): - patient_dict = frappe.db.sql(_("""select * from tabPatient where name='{0}'""").format(patient), as_dict=1) + patient_dict = frappe.db.sql("""select * from tabPatient where name=%s""", (patient), as_dict=1) if not patient_dict: frappe.throw("Patient not found") - vital_sign = frappe.db.sql(_("""select * from `tabVital Signs` where patient='{0}' order by signs_date desc limit 1""").format(patient), as_dict=1) + vital_sign = frappe.db.sql("""select * from `tabVital Signs` where patient=%s order by signs_date desc limit 1""", (patient), as_dict=1) details = patient_dict[0] if vital_sign: diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js index 86b18842cb6..1942b66f7b0 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js @@ -30,6 +30,14 @@ frappe.ui.form.on('Patient Appointment', { frm.add_custom_button(__('Cancel'), function() { btn_update_status(frm, "Cancelled"); }); + + frm.add_custom_button(__("Consultation"),function(){ + btn_create_consultation(frm); + },"Create"); + + frm.add_custom_button(__('Vital Signs'), function() { + btn_create_vital_signs(frm); + },"Create"); } if(frm.doc.status == "Pending"){ frm.add_custom_button(__('Set Open'), function() { @@ -40,14 +48,6 @@ frappe.ui.form.on('Patient Appointment', { }); } - frm.add_custom_button(__("Consultation"),function(){ - btn_create_consultation(frm); - },"Create"); - - frm.add_custom_button(__('Vital Signs'), function() { - btn_create_vital_signs(frm); - },"Create"); - if(!frm.doc.__islocal){ if(frm.doc.sales_invoice && frappe.user.has_role("Accounts User")){ frm.add_custom_button(__('Invoice'), function() { @@ -183,16 +183,20 @@ var btn_create_vital_signs = function (frm) { var btn_update_status = function(frm, status){ var doc = frm.doc; - frappe.call({ - method: - "erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_status", - args: {appointmentId: doc.name, status:status}, - callback: function(data){ - if(!data.exc){ - cur_frm.reload_doc(); - } + frappe.confirm(__('Are you sure you want to cancel this appointment?'), + function() { + frappe.call({ + method: + "erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_status", + args: {appointment_id: doc.name, status:status}, + callback: function(data){ + if(!data.exc){ + frm.reload_doc(); + } + } + }); } - }); + ); }; var btn_invoice_consultation = function(frm){ diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json index 9520e7766bd..1663c5b64f3 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json @@ -22,12 +22,12 @@ "fieldname": "patient", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Patient", "length": 0, "no_copy": 0, @@ -53,12 +53,12 @@ "fieldname": "physician", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Physician", "length": 0, "no_copy": 0, @@ -89,7 +89,7 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Date", "length": 0, "no_copy": 0, @@ -101,7 +101,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, - "search_index": 0, + "search_index": 1, "set_only_once": 1, "unique": 0 }, @@ -206,7 +206,7 @@ "fieldname": "appointment_type", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -234,6 +234,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:!doc.__islocal", "fieldname": "section_break_1", "fieldtype": "Section Break", "hidden": 0, @@ -338,11 +339,11 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 1, "set_only_once": 0, @@ -386,12 +387,12 @@ "fieldname": "department", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Department", "length": 0, "no_copy": 0, @@ -404,7 +405,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 1, "unique": 0 }, @@ -435,7 +436,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -546,15 +547,15 @@ "in_standard_filter": 0, "label": "Gender", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "patient.sex", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -608,15 +609,15 @@ "in_standard_filter": 0, "label": "Company", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Company", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -662,7 +663,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -691,7 +692,7 @@ "fieldname": "referring_physician", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -734,11 +735,11 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -755,7 +756,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:27:39.208298", + "modified": "2017-10-25 23:33:36.060803", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient Appointment", diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py index eab2f2d004f..4379986ddcb 100755 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py @@ -6,66 +6,100 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document import json -from frappe.utils import getdate +from frappe.utils import getdate, cint from frappe import _ import datetime from frappe.core.doctype.sms_settings.sms_settings import send_sms from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account,get_income_account + class PatientAppointment(Document): def on_update(self): today = datetime.date.today() appointment_date = getdate(self.appointment_date) - #If appointment created for today set as open - if(today == appointment_date): - frappe.db.set_value("Patient Appointment",self.name,"status","Open") + + # If appointment created for today set as open + if today == appointment_date: + frappe.db.set_value("Patient Appointment", self.name, "status", "Open") self.reload() def after_insert(self): - #Check fee validity exists + # Check fee validity exists appointment = self validity_exist = validity_exists(appointment.physician, appointment.patient) - if validity_exist : - fee_validity = frappe.get_doc("Fee Validity",validity_exist[0][0]) - #Check if the validity is valid + if validity_exist: + fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0]) + + # Check if the validity is valid appointment_date = getdate(appointment.appointment_date) - if((fee_validity.valid_till >= appointment_date) and (fee_validity.visited < fee_validity.max_visit)): + if (fee_validity.valid_till >= appointment_date) and (fee_validity.visited < fee_validity.max_visit): visited = fee_validity.visited + 1 - frappe.db.set_value("Fee Validity",fee_validity.name,"visited",visited) - if(fee_validity.ref_invoice): - frappe.db.set_value("Patient Appointment",appointment.name,"sales_invoice",fee_validity.ref_invoice) + frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited) + if fee_validity.ref_invoice: + frappe.db.set_value("Patient Appointment", appointment.name, "sales_invoice", fee_validity.ref_invoice) frappe.msgprint(_("{0} has fee validity till {1}").format(appointment.patient, fee_validity.valid_till)) confirm_sms(self) -def appointment_cancel(appointmentId): - appointment = frappe.get_doc("Patient Appointment",appointmentId) - #If invoice --> fee_validity update with -1 visit - if (appointment.sales_invoice): - validity = frappe.db.exists({"doctype": "Fee Validity","ref_invoice": appointment.sales_invoice}) - if(validity): - fee_validity = frappe.get_doc("Fee Validity",validity[0][0]) - visited = fee_validity.visited - 1 - frappe.db.set_value("Fee Validity",fee_validity.name,"visited",visited) - if visited <= 0: - frappe.msgprint(_("Appointment cancelled, Please review and cancel the invoice {0}".format(appointment.sales_invoice))) - else: - frappe.msgprint(_("Appointment cancelled")) + def save(self, *args, **kwargs): + # duration is the only changeable field in the document + if not self.is_new(): + self.db_set('duration', cint(self.duration)) + else: + super(PatientAppointment, self).save(*args, **kwargs) + + +def appointment_cancel(appointment_id): + appointment = frappe.get_doc("Patient Appointment", appointment_id) + + # If invoice --> fee_validity update with -1 visit + if appointment.sales_invoice: + validity = frappe.db.exists({"doctype": "Fee Validity", "ref_invoice": appointment.sales_invoice}) + if validity: + fee_validity = frappe.get_doc("Fee Validity", validity[0][0]) + visited = fee_validity.visited - 1 + frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited) + if visited <= 0: + frappe.msgprint( + _("Appointment cancelled, Please review and cancel the invoice {0}".format(appointment.sales_invoice)) + ) + else: + frappe.msgprint(_("Appointment cancelled")) + @frappe.whitelist() def get_availability_data(date, physician): - # get availability data of 'physician' on 'date' + """ + Get availability data of 'physician' on 'date' + :param date: Date to check in schedule + :param physician: Name of the physician + :return: dict containing a list of available slots, list of appointments and time of appointments + """ + date = getdate(date) weekday = date.strftime("%A") available_slots = [] + physician_schedule_name = None + physician_schedule = None + time_per_appointment = None + # get physicians schedule physician_schedule_name = frappe.db.get_value("Physician", physician, "physician_schedule") - physician_schedule = frappe.get_doc("Physician Schedule", physician_schedule_name) - time_per_appointment = frappe.db.get_value("Physician", physician, "time_per_appointment") + if physician_schedule_name: + physician_schedule = frappe.get_doc("Physician Schedule", physician_schedule_name) + time_per_appointment = frappe.db.get_value("Physician", physician, "time_per_appointment") + else: + frappe.throw(_("Dr {0} does not have a Physician Schedule. Add it in Physician master".format(physician))) - for t in physician_schedule.time_slots: - if weekday == t.day: - available_slots.append(t) + if physician_schedule: + for t in physician_schedule.time_slots: + if weekday == t.day: + available_slots.append(t) + + # `time_per_appointment` should never be None since validation in `Patient` is supposed to prevent + # that. However, it isn't impossible so we'll prepare for that. + if not time_per_appointment: + frappe.throw(_('"Time Per Appointment" hasn"t been set for Dr {0}. Add it in Physician master.').format(physician)) # if physician not available return if not available_slots: @@ -89,27 +123,36 @@ def get_availability_data(date, physician): "time_per_appointment": time_per_appointment } + @frappe.whitelist() -def update_status(appointmentId, status): - frappe.db.set_value("Patient Appointment",appointmentId,"status",status) - if(status=="Cancelled"): - appointment_cancel(appointmentId) +def update_status(appointment_id, status): + frappe.db.set_value("Patient Appointment", appointment_id, "status", status) + if status == "Cancelled": + appointment_cancel(appointment_id) + @frappe.whitelist() def set_open_appointments(): today = getdate() - frappe.db.sql("""update `tabPatient Appointment` set status='Open' where status = 'Scheduled' and appointment_date = %s""",(today)) + frappe.db.sql( + "update `tabPatient Appointment` set status='Open' where status = 'Scheduled'" + " and appointment_date = %s", today) + @frappe.whitelist() def set_pending_appointments(): today = getdate() - frappe.db.sql("""update `tabPatient Appointment` set status='Pending' where status in ('Scheduled','Open') and appointment_date < %s""",(today)) + frappe.db.sql( + "update `tabPatient Appointment` set status='Pending' where status in " + "('Scheduled','Open') and appointment_date < %s", today) + def confirm_sms(doc): - if (frappe.db.get_value("Healthcare Settings", None, "app_con")=='1'): + if frappe.db.get_value("Healthcare Settings", None, "app_con") == '1': message = frappe.db.get_value("Healthcare Settings", None, "app_con_msg") send_message(doc, message) + @frappe.whitelist() def create_invoice(company, physician, patient, appointment_id, appointment_date): if not appointment_id: @@ -125,7 +168,7 @@ def create_invoice(company, physician, patient, appointment_id, appointment_date create_invoice_items(appointment_id, physician, company, sales_invoice) sales_invoice.save(ignore_permissions=True) - frappe.db.sql(_("""update `tabPatient Appointment` set sales_invoice='{0}' where name='{1}'""").format(sales_invoice.name, appointment_id)) + frappe.db.sql("""update `tabPatient Appointment` set sales_invoice=%s where name=%s""", (sales_invoice.name, appointment_id)) frappe.db.set_value("Fee Validity", fee_validity.name, "ref_invoice", sales_invoice.name) consultation = frappe.db.exists({ "doctype": "Consultation", @@ -134,21 +177,24 @@ def create_invoice(company, physician, patient, appointment_id, appointment_date frappe.db.set_value("Consultation", consultation[0][0], "invoice", sales_invoice.name) return sales_invoice.name + def get_fee_validity(physician, patient, date): validity_exist = validity_exists(physician, patient) - if validity_exist : - fee_validity = frappe.get_doc("Fee Validity",validity_exist[0][0]) + if validity_exist: + fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0]) fee_validity = update_fee_validity(fee_validity, date) else: fee_validity = create_fee_validity(physician, patient, date) return fee_validity + def validity_exists(physician, patient): return frappe.db.exists({ "doctype": "Fee Validity", "physician": physician, "patient": patient}) + def update_fee_validity(fee_validity, date): max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") @@ -164,6 +210,7 @@ def update_fee_validity(fee_validity, date): fee_validity.save(ignore_permissions=True) return fee_validity + def create_fee_validity(physician, patient, date): fee_validity = frappe.new_doc("Fee Validity") fee_validity.physician = physician @@ -171,6 +218,7 @@ def create_fee_validity(physician, patient, date): fee_validity = update_fee_validity(fee_validity, date) return fee_validity + def create_invoice_items(appointment_id, physician, company, invoice): item_line = invoice.append("items") item_line.item_name = "Consulting Charges" @@ -178,16 +226,17 @@ def create_invoice_items(appointment_id, physician, company, invoice): item_line.qty = 1 item_line.uom = "Nos" item_line.conversion_factor = 1 - item_line.income_account = get_income_account(physician,company) + item_line.income_account = get_income_account(physician, company) op_consulting_charge = frappe.db.get_value("Physician", physician, "op_consulting_charge") if op_consulting_charge: item_line.rate = op_consulting_charge item_line.amount = op_consulting_charge return invoice + @frappe.whitelist() def create_consultation(appointment): - appointment = frappe.get_doc("Patient Appointment",appointment) + appointment = frappe.get_doc("Patient Appointment", appointment) consultation = frappe.new_doc("Consultation") consultation.appointment = appointment.name consultation.patient = appointment.patient @@ -199,29 +248,37 @@ def create_consultation(appointment): consultation.invoice = appointment.sales_invoice return consultation.as_dict() + def remind_appointment(): - if (frappe.db.get_value("Healthcare Settings", None, "app_rem")=='1'): + if frappe.db.get_value("Healthcare Settings", None, "app_rem") == '1': rem_before = datetime.datetime.strptime(frappe.get_value("Healthcare Settings", None, "rem_before"), "%H:%M:%S") - rem_dt = datetime.datetime.now() + datetime.timedelta(hours = rem_before.hour, minutes=rem_before.minute, seconds= rem_before.second) + rem_dt = datetime.datetime.now() + datetime.timedelta( + hours=rem_before.hour, minutes=rem_before.minute, seconds=rem_before.second) - appointment_list = frappe.db.sql("select name from `tabPatient Appointment` where start_dt between %s and %s and reminded = 0 ", (datetime.datetime.now(), rem_dt)) + appointment_list = frappe.db.sql( + "select name from `tabPatient Appointment` where start_dt between %s and %s and reminded = 0 ", + (datetime.datetime.now(), rem_dt) + ) - for i in range (0,len(appointment_list)): + for i in range(0, len(appointment_list)): doc = frappe.get_doc("Patient Appointment", appointment_list[i][0]) message = frappe.db.get_value("Healthcare Settings", None, "app_rem_msg") send_message(doc, message) - frappe.db.set_value("Patient Appointment",doc.name,"reminded",1) + frappe.db.set_value("Patient Appointment", doc.name, "reminded",1) + def send_message(doc, message): - patient = frappe.get_doc("Patient",doc.patient) - if(patient.mobile): + patient = frappe.get_doc("Patient", doc.patient) + if patient.mobile: context = {"doc": doc, "alert": doc, "comments": None} if doc.get("_comments"): context["comments"] = json.loads(doc.get("_comments")) - #jinja to string convertion happens here + + # jinja to string convertion happens here message = frappe.render_template(message, context) number = [patient.mobile] - send_sms(number,message) + send_sms(number, message) + @frappe.whitelist() def get_events(start, end, filters=None): diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json index 06149230e67..9cbcf7b9b75 100644 --- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json +++ b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json @@ -33,11 +33,11 @@ "options": "PMR-", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -52,7 +52,7 @@ "fieldname": "patient", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -171,7 +171,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -212,7 +212,7 @@ "options": "Open\nClose", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -332,15 +332,15 @@ "in_standard_filter": 0, "label": "Reference Owner", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "reference_name.owner", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -356,7 +356,7 @@ "fieldname": "user", "fieldtype": "Link", "hidden": 1, - "ignore_user_permissions": 1, + "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -368,11 +368,11 @@ "options": "User", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -389,7 +389,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-04 14:29:48.679751", + "modified": "2017-10-04 16:09:55.597866", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient Medical Record", diff --git a/erpnext/healthcare/doctype/patient_relation/patient_relation.json b/erpnext/healthcare/doctype/patient_relation/patient_relation.json index e97e1b24c03..209a3746a6e 100644 --- a/erpnext/healthcare/doctype/patient_relation/patient_relation.json +++ b/erpnext/healthcare/doctype/patient_relation/patient_relation.json @@ -39,7 +39,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -52,7 +52,7 @@ "fieldname": "patient", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -84,7 +84,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -115,7 +115,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 14:13:37.497114", + "modified": "2017-10-04 16:12:45.485333", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient Relation", diff --git a/erpnext/healthcare/doctype/physician/physician.json b/erpnext/healthcare/doctype/physician/physician.json index 565653b89c0..3edad0b827d 100644 --- a/erpnext/healthcare/doctype/physician/physician.json +++ b/erpnext/healthcare/doctype/physician/physician.json @@ -26,7 +26,7 @@ "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "First Name", "length": 0, "no_copy": 0, @@ -119,14 +119,14 @@ "in_standard_filter": 0, "label": "Image", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -203,12 +203,12 @@ "fieldname": "designation", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Designation", "length": 0, "no_copy": 0, @@ -234,12 +234,12 @@ "fieldname": "department", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Department", "length": 0, "no_copy": 0, @@ -444,7 +444,7 @@ "fieldname": "physician_schedule", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -501,6 +501,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "description": "In minutes", "fieldname": "time_per_appointment", "fieldtype": "Data", "hidden": 0, @@ -633,14 +634,14 @@ "in_standard_filter": 0, "label": "Address HTML", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -692,14 +693,14 @@ "in_standard_filter": 0, "label": "Contact HTML", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -783,15 +784,15 @@ "in_standard_filter": 0, "label": "Default Currency", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Currency", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -809,7 +810,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:51:28.975120", + "modified": "2017-10-05 16:08:24.624644", "modified_by": "Administrator", "module": "Healthcare", "name": "Physician", diff --git a/erpnext/healthcare/doctype/physician/physician.py b/erpnext/healthcare/doctype/physician/physician.py index 8680d5d1273..4d035d39f66 100644 --- a/erpnext/healthcare/doctype/physician/physician.py +++ b/erpnext/healthcare/doctype/physician/physician.py @@ -20,22 +20,32 @@ class Physician(Document): [cstr(self.get(f)).strip() for f in ["first_name","middle_name","last_name"]])) def validate(self): + self.validate_schedule_and_time() validate_party_accounts(self) + if self.user_id: self.validate_for_enabled_user_id() self.validate_duplicate_user_id() existing_user_id = frappe.db.get_value("Physician", self.name, "user_id") - if(self.user_id != existing_user_id): + if self.user_id != existing_user_id: frappe.permissions.remove_user_permission( "Physician", self.name, existing_user_id) - else: existing_user_id = frappe.db.get_value("Physician", self.name, "user_id") if existing_user_id: frappe.permissions.remove_user_permission( "Physician", self.name, existing_user_id) + def validate_schedule_and_time(self): + if (self.physician_schedule or self.time_per_appointment) and \ + not (self.physician_schedule and self.time_per_appointment): + frappe.msgprint( + _('Both "Physician Schedule" and Time Per Appointment" must be set for Dr {0}').format( + self.first_name), + title='Error', raise_exception=1, indicator='red' + ) + def on_update(self): if self.user_id: frappe.permissions.add_user_permission("Physician", self.name, self.user_id) diff --git a/erpnext/healthcare/doctype/physician/test_physician.py b/erpnext/healthcare/doctype/physician/test_physician.py index b6ea92cc720..4bd497a4e99 100644 --- a/erpnext/healthcare/doctype/physician/test_physician.py +++ b/erpnext/healthcare/doctype/physician/test_physician.py @@ -3,8 +3,35 @@ # See license.txt from __future__ import unicode_literals import unittest +import frappe + +test_dependencies = ['Physician Schedule'] -# test_records = frappe.get_test_records('Physician') class TestPhysician(unittest.TestCase): - pass + def tearDown(self): + frappe.delete_doc_if_exists('Physician', '_Testdoctor2', force=1) + + def test_schedule_and_time(self): + physician = frappe.new_doc('Physician') + physician.first_name = '_Testdoctor2' + physician.physician_schedule = '_Testdoctor2 Schedule' + + self.assertRaises(frappe.ValidationError, physician.insert) + + physician.physician_schedule = '' + physician.time_per_appointment = 15 + + self.assertRaises(frappe.ValidationError, physician.insert) + + physician.physician_schedule = '_Testdoctor2 Schedule' + physician.time_per_appointment = 15 + + physician.insert() + + def test_new_physician_without_schedule(self): + physician = frappe.new_doc('Physician') + physician.first_name = '_Testdoctor2' + + physician.insert() + self.assertEqual(frappe.get_value('Physician', '_Testdoctor2', 'first_name'), '_Testdoctor2') diff --git a/erpnext/healthcare/doctype/physician_schedule/physician_schedule.json b/erpnext/healthcare/doctype/physician_schedule/physician_schedule.json index bd8e539c539..b1b31290217 100644 --- a/erpnext/healthcare/doctype/physician_schedule/physician_schedule.json +++ b/erpnext/healthcare/doctype/physician_schedule/physician_schedule.json @@ -23,7 +23,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -94,11 +94,11 @@ "no_copy": 0, "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -115,7 +115,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:42:26.713507", + "modified": "2017-10-05 11:21:54.488194", "modified_by": "Administrator", "module": "Healthcare", "name": "Physician Schedule", diff --git a/erpnext/healthcare/doctype/physician_schedule/physician_schedule.py b/erpnext/healthcare/doctype/physician_schedule/physician_schedule.py index 5cbdd126a91..167e9cd4b82 100644 --- a/erpnext/healthcare/doctype/physician_schedule/physician_schedule.py +++ b/erpnext/healthcare/doctype/physician_schedule/physician_schedule.py @@ -5,5 +5,7 @@ from __future__ import unicode_literals from frappe.model.document import Document + class PhysicianSchedule(Document): - pass + def autoname(self): + self.name = self.schedule_name diff --git a/erpnext/healthcare/doctype/physician_schedule/test_records.json b/erpnext/healthcare/doctype/physician_schedule/test_records.json new file mode 100644 index 00000000000..1e6230dd98d --- /dev/null +++ b/erpnext/healthcare/doctype/physician_schedule/test_records.json @@ -0,0 +1,8 @@ +[ + { + "schedule_name": "_Testdoctor1 Schedule" + }, + { + "schedule_name": "_Testdoctor2 Schedule" + } +] \ No newline at end of file diff --git a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json index 9c095061931..9fb0dbc13ca 100644 --- a/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json +++ b/erpnext/healthcare/doctype/prescription_dosage/prescription_dosage.json @@ -22,7 +22,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -83,7 +83,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:42:40.305284", + "modified": "2017-10-05 11:20:47.558464", "modified_by": "Administrator", "module": "Healthcare", "name": "Prescription Dosage", diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.json b/erpnext/healthcare/doctype/sample_collection/sample_collection.json index ee2f83f01c7..39788fbd548 100644 --- a/erpnext/healthcare/doctype/sample_collection/sample_collection.json +++ b/erpnext/healthcare/doctype/sample_collection/sample_collection.json @@ -85,12 +85,12 @@ "fieldname": "patient", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Patient", "length": 0, "no_copy": 0, @@ -103,7 +103,7 @@ "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, - "search_index": 0, + "search_index": 1, "set_only_once": 0, "unique": 0 }, @@ -219,11 +219,11 @@ "options": "Company", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -267,12 +267,12 @@ "fieldname": "sample", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Sample", "length": 0, "no_copy": 0, @@ -389,7 +389,7 @@ "fieldname": "collected_by", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -466,7 +466,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -541,7 +541,7 @@ "fieldtype": "Long Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -572,7 +572,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:30:29.303026", + "modified": "2017-10-05 11:58:46.016097", "modified_by": "Administrator", "module": "Healthcare", "name": "Sample Collection", diff --git a/erpnext/healthcare/doctype/sensitivity/sensitivity.json b/erpnext/healthcare/doctype/sensitivity/sensitivity.json index 620f37a59aa..eddfda90566 100644 --- a/erpnext/healthcare/doctype/sensitivity/sensitivity.json +++ b/erpnext/healthcare/doctype/sensitivity/sensitivity.json @@ -22,7 +22,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -53,7 +53,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-31 13:44:07.147326", + "modified": "2017-10-05 11:19:12.110308", "modified_by": "Administrator", "module": "Healthcare", "name": "Sensitivity", diff --git a/erpnext/healthcare/doctype/sensitivity_test_items/sensitivity_test_items.json b/erpnext/healthcare/doctype/sensitivity_test_items/sensitivity_test_items.json index e656b512792..86f5e26f0a3 100644 --- a/erpnext/healthcare/doctype/sensitivity_test_items/sensitivity_test_items.json +++ b/erpnext/healthcare/doctype/sensitivity_test_items/sensitivity_test_items.json @@ -20,7 +20,7 @@ "fieldname": "antibiotic", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -51,7 +51,7 @@ "fieldname": "antibiotic_sensitivity", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, @@ -84,7 +84,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 13:46:40.609983", + "modified": "2017-10-05 11:08:06.327972", "modified_by": "Administrator", "module": "Healthcare", "name": "Sensitivity Test Items", diff --git a/erpnext/healthcare/doctype/special_test_items/special_test_items.json b/erpnext/healthcare/doctype/special_test_items/special_test_items.json index 89545e9acd1..4c97e41138c 100644 --- a/erpnext/healthcare/doctype/special_test_items/special_test_items.json +++ b/erpnext/healthcare/doctype/special_test_items/special_test_items.json @@ -22,7 +22,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -53,7 +53,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -99,7 +99,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -130,7 +130,7 @@ "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -147,7 +147,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 14:12:12.623714", + "modified": "2017-10-04 16:15:12.642699", "modified_by": "Administrator", "module": "Healthcare", "name": "Special Test Items", diff --git a/erpnext/healthcare/doctype/special_test_template/special_test_template.json b/erpnext/healthcare/doctype/special_test_template/special_test_template.json index 83f3cb6fd93..372af0a9594 100644 --- a/erpnext/healthcare/doctype/special_test_template/special_test_template.json +++ b/erpnext/healthcare/doctype/special_test_template/special_test_template.json @@ -21,7 +21,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -53,7 +53,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-31 14:08:18.833796", + "modified": "2017-10-04 16:20:09.565316", "modified_by": "Administrator", "module": "Healthcare", "name": "Special Test Template", diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.json b/erpnext/healthcare/doctype/vital_signs/vital_signs.json index e44af280082..bab80f554e1 100644 --- a/erpnext/healthcare/doctype/vital_signs/vital_signs.json +++ b/erpnext/healthcare/doctype/vital_signs/vital_signs.json @@ -21,12 +21,12 @@ "fieldname": "patient", "fieldtype": "Link", "hidden": 0, - "ignore_user_permissions": 0, + "ignore_user_permissions": 1, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Patient", "length": 0, "no_copy": 0, @@ -54,21 +54,21 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, + "in_filter": 1, "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Appointment", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Patient Appointment", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -85,21 +85,21 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, + "in_filter": 1, "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, "label": "Consultation", "length": 0, - "no_copy": 0, + "no_copy": 1, "options": "Consultation", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "print_hide_if_no_value": 0, "read_only": 1, "remember_last_selected_value": 0, - "report_hide": 0, + "report_hide": 1, "reqd": 0, "search_index": 0, "set_only_once": 0, @@ -266,7 +266,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -297,7 +297,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -328,7 +328,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -387,7 +387,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -418,7 +418,7 @@ "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 1, @@ -479,7 +479,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -659,7 +659,7 @@ "fieldtype": "Small Text", "hidden": 0, "ignore_user_permissions": 0, - "ignore_xss_filter": 0, + "ignore_xss_filter": 1, "in_filter": 0, "in_global_search": 0, "in_list_view": 0, @@ -751,7 +751,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-04 14:31:57.851546", + "modified": "2017-10-04 16:08:36.340607", "modified_by": "Administrator", "module": "Healthcare", "name": "Vital Signs", diff --git a/erpnext/setup/setup_wizard/healthcare.py b/erpnext/healthcare/setup.py similarity index 74% rename from erpnext/setup/setup_wizard/healthcare.py rename to erpnext/healthcare/setup.py index ebc644e87b7..69a92b348ba 100644 --- a/erpnext/setup/setup_wizard/healthcare.py +++ b/erpnext/healthcare/setup.py @@ -1,10 +1,12 @@ from __future__ import unicode_literals import frappe -from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe import _ def setup_healthcare(): + if frappe.db.exists('Medical Department', 'Cardiology'): + # already setup + return create_medical_departments() create_antibiotics() create_test_uom() @@ -14,63 +16,55 @@ def setup_healthcare(): create_lab_test_items() create_lab_test_template() create_sensitivity() - make_custom_fields() - -def make_custom_fields(): - custom_fields = { - 'Sales Invoice': [ - dict(fieldname='appointment', label='Patient Appointment', - fieldtype='Link', options='Patient Appointment', - insert_after='customer') - ] - } - - create_custom_fields(custom_fields) - def create_medical_departments(): - depts = ["Accident and emergency care" ,"Anaesthetics", "Biochemistry", "Cardiology", "Dermatology", - "Diagnostic imaging", "ENT", "Gastroenterology", "General Surgery", "Gynaecology", - "Haematology", "Maternity", "Microbiology", "Nephrology", "Neurology", "Oncology", - "Orthopaedics", "Pathology", "Physiotherapy", "Rheumatology", "Serology", "Urology"] - for d in depts: + departments = [ + "Accident And Emergency Care" ,"Anaesthetics", "Biochemistry", "Cardiology", "Dermatology", + "Diagnostic Imaging", "ENT", "Gastroenterology", "General Surgery", "Gynaecology", + "Haematology", "Maternity", "Microbiology", "Nephrology", "Neurology", "Oncology", + "Orthopaedics", "Pathology", "Physiotherapy", "Rheumatology", "Serology", "Urology" + ] + for department in departments: mediacal_department = frappe.new_doc("Medical Department") - mediacal_department.department = d + mediacal_department.department = _(department) try: mediacal_department.save() except frappe.DuplicateEntryError: pass def create_antibiotics(): - abt = ["Amoxicillin", "Ampicillin", "Bacampicillin", "Carbenicillin", "Cloxacillin", "Dicloxacillin", - "Flucloxacillin", "Mezlocillin", "Nafcillin", "Oxacillin", "Penicillin G", "Penicillin V", - "Piperacillin", "Pivampicillin", "Pivmecillinam", "Ticarcillin", "Cefacetrile (cephacetrile)", - "Cefadroxil (cefadroxyl)", "Cefalexin (cephalexin)", "Cefaloglycin (cephaloglycin)", - "Cefalonium (cephalonium)", "Cefaloridine (cephaloradine)", "Cefalotin (cephalothin)", - "Cefapirin (cephapirin)", "Cefatrizine", "Cefazaflur", "Cefazedone", "Cefazolin (cephazolin)", - "Cefradine (cephradine)", "Cefroxadine", "Ceftezole", "Cefaclor", "Cefamandole", "Cefmetazole", - "Cefonicid", "Cefotetan", "Cefoxitin", "Cefprozil (cefproxil)", "Cefuroxime", "Cefuzonam", - "Cefcapene", "Cefdaloxime", "Cefdinir", "Cefditoren", "Cefetamet", "Cefixime", "Cefmenoxime", - "Cefodizime", "Cefotaxime", "Cefpimizole", "Cefpodoxime", "Cefteram", "Ceftibuten", "Ceftiofur", - "Ceftiolene", "Ceftizoxime", "Ceftriaxone", "Cefoperazone", "Ceftazidime", "Cefclidine", "Cefepime", - "Cefluprenam", "Cefoselis", "Cefozopran", "Cefpirome", "Cefquinome", "Ceftobiprole", "Ceftaroline", - "Cefaclomezine","Cefaloram", "Cefaparole", "Cefcanel", "Cefedrolor", "Cefempidone", "Cefetrizole", - "Cefivitril", "Cefmatilen", "Cefmepidium", "Cefovecin", "Cefoxazole", "Cefrotil", "Cefsumide", - "Cefuracetime", "Ceftioxide", "Ceftazidime/Avibactam", "Ceftolozane/Tazobactam", "Aztreonam", - "Imipenem", "Imipenem/cilastatin", "Doripenem", "Meropenem", "Ertapenem", "Azithromycin", - "Erythromycin", "Clarithromycin", "Dirithromycin", "Roxithromycin", "Telithromycin", "Clindamycin", - "Lincomycin", "Pristinamycin", "Quinupristin/dalfopristin", "Amikacin", "Gentamicin", "Kanamycin", - "Neomycin", "Netilmicin", "Paromomycin", "Streptomycin", "Tobramycin", "Flumequine", "Nalidixic acid", - "Oxolinic acid", "Piromidic acid", "Pipemidic acid", "Rosoxacin", "Ciprofloxacin", "Enoxacin", - "Lomefloxacin", "Nadifloxacin", "Norfloxacin", "Ofloxacin", "Pefloxacin", "Rufloxacin", "Balofloxacin", - "Gatifloxacin", "Grepafloxacin", "Levofloxacin", "Moxifloxacin", "Pazufloxacin", "Sparfloxacin", - "Temafloxacin", "Tosufloxacin", "Besifloxacin", "Clinafloxacin", "Gemifloxacin", - "Sitafloxacin", "Trovafloxacin", "Prulifloxacin", "Sulfamethizole", "Sulfamethoxazole", - "Sulfisoxazole", "Trimethoprim-Sulfamethoxazole", "Demeclocycline", "Doxycycline", "Minocycline", - "Oxytetracycline", "Tetracycline", "Tigecycline", "Chloramphenicol", "Metronidazole", - "Tinidazole", "Nitrofurantoin", "Vancomycin", "Teicoplanin", "Telavancin", "Linezolid", - "Cycloserine 2", "Rifampin", "Rifabutin", "Rifapentine", "Rifalazil", "Bacitracin", "Polymyxin B", - "Viomycin", "Capreomycin"] + abt = [ + "Amoxicillin", "Ampicillin", "Bacampicillin", "Carbenicillin", "Cloxacillin", "Dicloxacillin", + "Flucloxacillin", "Mezlocillin", "Nafcillin", "Oxacillin", "Penicillin G", "Penicillin V", + "Piperacillin", "Pivampicillin", "Pivmecillinam", "Ticarcillin", "Cefacetrile (cephacetrile)", + "Cefadroxil (cefadroxyl)", "Cefalexin (cephalexin)", "Cefaloglycin (cephaloglycin)", + "Cefalonium (cephalonium)", "Cefaloridine (cephaloradine)", "Cefalotin (cephalothin)", + "Cefapirin (cephapirin)", "Cefatrizine", "Cefazaflur", "Cefazedone", "Cefazolin (cephazolin)", + "Cefradine (cephradine)", "Cefroxadine", "Ceftezole", "Cefaclor", "Cefamandole", "Cefmetazole", + "Cefonicid", "Cefotetan", "Cefoxitin", "Cefprozil (cefproxil)", "Cefuroxime", "Cefuzonam", + "Cefcapene", "Cefdaloxime", "Cefdinir", "Cefditoren", "Cefetamet", "Cefixime", "Cefmenoxime", + "Cefodizime", "Cefotaxime", "Cefpimizole", "Cefpodoxime", "Cefteram", "Ceftibuten", "Ceftiofur", + "Ceftiolene", "Ceftizoxime", "Ceftriaxone", "Cefoperazone", "Ceftazidime", "Cefclidine", "Cefepime", + "Cefluprenam", "Cefoselis", "Cefozopran", "Cefpirome", "Cefquinome", "Ceftobiprole", "Ceftaroline", + "Cefaclomezine","Cefaloram", "Cefaparole", "Cefcanel", "Cefedrolor", "Cefempidone", "Cefetrizole", + "Cefivitril", "Cefmatilen", "Cefmepidium", "Cefovecin", "Cefoxazole", "Cefrotil", "Cefsumide", + "Cefuracetime", "Ceftioxide", "Ceftazidime/Avibactam", "Ceftolozane/Tazobactam", "Aztreonam", + "Imipenem", "Imipenem/cilastatin", "Doripenem", "Meropenem", "Ertapenem", "Azithromycin", + "Erythromycin", "Clarithromycin", "Dirithromycin", "Roxithromycin", "Telithromycin", "Clindamycin", + "Lincomycin", "Pristinamycin", "Quinupristin/dalfopristin", "Amikacin", "Gentamicin", "Kanamycin", + "Neomycin", "Netilmicin", "Paromomycin", "Streptomycin", "Tobramycin", "Flumequine", "Nalidixic acid", + "Oxolinic acid", "Piromidic acid", "Pipemidic acid", "Rosoxacin", "Ciprofloxacin", "Enoxacin", + "Lomefloxacin", "Nadifloxacin", "Norfloxacin", "Ofloxacin", "Pefloxacin", "Rufloxacin", "Balofloxacin", + "Gatifloxacin", "Grepafloxacin", "Levofloxacin", "Moxifloxacin", "Pazufloxacin", "Sparfloxacin", + "Temafloxacin", "Tosufloxacin", "Besifloxacin", "Clinafloxacin", "Gemifloxacin", + "Sitafloxacin", "Trovafloxacin", "Prulifloxacin", "Sulfamethizole", "Sulfamethoxazole", + "Sulfisoxazole", "Trimethoprim-Sulfamethoxazole", "Demeclocycline", "Doxycycline", "Minocycline", + "Oxytetracycline", "Tetracycline", "Tigecycline", "Chloramphenicol", "Metronidazole", + "Tinidazole", "Nitrofurantoin", "Vancomycin", "Teicoplanin", "Telavancin", "Linezolid", + "Cycloserine 2", "Rifampin", "Rifabutin", "Rifapentine", "Rifalazil", "Bacitracin", "Polymyxin B", + "Viomycin", "Capreomycin" + ] + for a in abt: antibiotic = frappe.new_doc("Antibiotic") antibiotic.antibiotic_name = a @@ -190,65 +184,65 @@ def create_healthcare_item_groups(): def create_lab_test_items(): records = [ - {"doctype": "Item", "item_code": "MCH", "item_name": "MCH", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, - {"doctype": "Item", "item_code": "LDL", "item_name": "LDL", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, - {"doctype": "Item", "item_code": "GTT", "item_name": "GTT", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, - {"doctype": "Item", "item_code": "HDL", "item_name": "HDL", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, - {"doctype": "Item", "item_code": "BILT", "item_name": "BILT", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, - {"doctype": "Item", "item_code": "BILD", "item_name": "BILD", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, - {"doctype": "Item", "item_code": "BP", "item_name": "BP", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, - {"doctype": "Item", "item_code": "BS", "item_name": "BS", "item_group": "Laboratory", - "stock_uom": "Unit", "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1} + {"doctype": "Item", "item_code": "MCH", "item_name": "MCH", "item_group": _("Laboratory"), + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + {"doctype": "Item", "item_code": "LDL", "item_name": "LDL", "item_group": _("Laboratory"), + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + {"doctype": "Item", "item_code": "GTT", "item_name": "GTT", "item_group": _("Laboratory"), + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + {"doctype": "Item", "item_code": "HDL", "item_name": "HDL", "item_group": _("Laboratory"), + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + {"doctype": "Item", "item_code": "BILT", "item_name": "BILT", "item_group": _("Laboratory"), + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + {"doctype": "Item", "item_code": "BILD", "item_name": "BILD", "item_group": _("Laboratory"), + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + {"doctype": "Item", "item_code": "BP", "item_name": "BP", "item_group": _("Laboratory"), + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1}, + {"doctype": "Item", "item_code": "BS", "item_name": "BS", "item_group": _("Laboratory"), + "stock_uom": _("Unit"), "is_stock_item": 0, "is_purchase_item": 0, "is_sales_item": 1} ] insert_record(records) def create_lab_test_template(): records = [ {"doctype": "Lab Test Template", "name": "MCH","test_name": "MCH","test_code": "MCH", - "test_group": "Laboratory","department": "Haematology","item": "MCH", + "test_group": _("Laboratory"),"department": _("Haematology"),"item": "MCH", "test_template_type": "Single","is_billable": 1,"test_rate": 0.0,"test_uom": "Microgram", "test_normal_range": "27 - 32 Microgram", "sensitivity": 0,"test_description": "Mean Corpuscular Hemoglobin"}, {"doctype": "Lab Test Template", "name": "LDL","test_name": "LDL (Serum)","test_code": "LDL", - "test_group": "Laboratory","department": "Biochemistry", + "test_group": _("Laboratory"),"department": _("Biochemistry"), "item": "LDL","test_template_type": "Single", "is_billable": 1,"test_rate": 0.0,"test_uom": "mg / dl","test_normal_range": "70 - 160 mg/dlLow-density Lipoprotein (LDL)", "sensitivity": 0,"test_description": "Low-density Lipoprotein (LDL)"}, {"doctype": "Lab Test Template", "name": "GTT","test_name": "GTT","test_code": "GTT", - "test_group": "Laboratory","department": "Haematology", + "test_group": _("Laboratory"),"department": _("Haematology"), "item": "GTT","test_template_type": "Single", "is_billable": 1,"test_rate": 0.0,"test_uom": "mg / dl","test_normal_range": "Less than 85 mg/dl", "sensitivity": 0,"test_description": "Glucose Tolerance Test"}, {"doctype": "Lab Test Template", "name": "HDL","test_name": "HDL (Serum)","test_code": "HDL", - "test_group": "Laboratory","department": "Biochemistry", + "test_group": _("Laboratory"),"department": _("Biochemistry"), "item": "HDL","test_template_type": "Single", "is_billable": 1,"test_rate": 0.0,"test_uom": "mg / dl","test_normal_range": "35 - 65 mg/dl", "sensitivity": 0,"test_description": "High-density Lipoprotein (HDL)"}, {"doctype": "Lab Test Template", "name": "BILT","test_name": "Bilirubin Total","test_code": "BILT", - "test_group": "Laboratory","department": "Biochemistry", + "test_group": _("Laboratory"),"department": _("Biochemistry"), "item": "BILT","test_template_type": "Single", "is_billable": 1,"test_rate": 0.0,"test_uom": "mg / dl","test_normal_range": "0.2 - 1.2 mg / dl", "sensitivity": 0,"test_description": "Bilirubin Total"}, {"doctype": "Lab Test Template", "name": "BILD","test_name": "Bilirubin Direct","test_code": "BILD", - "test_group": "Laboratory","department": "Biochemistry", + "test_group": _("Laboratory"),"department": _("Biochemistry"), "item": "BILD","test_template_type": "Single", "is_billable": 1,"test_rate": 0.0,"test_uom": "mg / dl","test_normal_range": "0.4 mg / dl", "sensitivity": 0,"test_description": "Bilirubin Direct"}, {"doctype": "Lab Test Template", "name": "BP","test_name": "Bile Pigment","test_code": "BP", - "test_group": "Laboratory","department": "Pathology", + "test_group": _("Laboratory"),"department": _("Pathology"), "item": "BP","test_template_type": "Single", "is_billable": 1,"test_rate": 0.0,"test_uom": "","test_normal_range": "", "sensitivity": 0,"test_description": "Bile Pigment"}, {"doctype": "Lab Test Template", "name": "BS","test_name": "Bile Salt","test_code": "BS", - "test_group": "Laboratory","department": "Pathology", + "test_group": _("Laboratory"),"department": _("Pathology"), "item": "BS","test_template_type": "Single", "is_billable": 1,"test_rate": 0.0,"test_uom": "","test_normal_range": "", "sensitivity": 0,"test_description": "Bile Salt"} @@ -257,12 +251,12 @@ def create_lab_test_template(): def create_sensitivity(): records = [ - {"doctype": "Sensitivity", "sensitivity": "Low Sensitivity"}, - {"doctype": "Sensitivity", "sensitivity": "High Sensitivity"}, - {"doctype": "Sensitivity", "sensitivity": "Moderate Sensitivity"}, - {"doctype": "Sensitivity", "sensitivity": "Susceptible"}, - {"doctype": "Sensitivity", "sensitivity": "Resistant"}, - {"doctype": "Sensitivity", "sensitivity": "Intermediate"} + {"doctype": "Sensitivity", "sensitivity": _("Low Sensitivity")}, + {"doctype": "Sensitivity", "sensitivity": _("High Sensitivity")}, + {"doctype": "Sensitivity", "sensitivity": _("Moderate Sensitivity")}, + {"doctype": "Sensitivity", "sensitivity": _("Susceptible")}, + {"doctype": "Sensitivity", "sensitivity": _("Resistant")}, + {"doctype": "Sensitivity", "sensitivity": _("Intermediate")} ] insert_record(records) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 48ed7415d73..44a3b18f78d 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -11,7 +11,7 @@ app_email = "info@erpnext.com" app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" -develop_version = '8.x.x-beta' +develop_version = '9.x.x-develop' error_report_email = "support@erpnext.com" @@ -47,12 +47,22 @@ treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Grou update_website_context = "erpnext.shopping_cart.utils.update_website_context" my_account_context = "erpnext.shopping_cart.utils.update_my_account_context" -email_append_to = ["Job Applicant", "Opportunity", "Issue"] +email_append_to = ["Job Applicant", "Lead", "Opportunity", "Issue"] calendars = ["Task", "Production Order", "Leave Application", "Sales Order", "Holiday List"] fixtures = ["Web Form"] +domains = { + 'Distribution': 'erpnext.domains.distribution', + 'Education': 'erpnext.domains.education', + 'Healthcare': 'erpnext.domains.healthcare', + 'Hospitality': 'erpnext.domains.hospitality', + 'Manufacturing': 'erpnext.domains.manufacturing', + 'Retail': 'erpnext.domains.retail', + 'Services': 'erpnext.domains.services', +} + website_generators = ["Item Group", "Item", "BOM", "Sales Partner", "Job Opening", "Student Admission"] @@ -133,7 +143,8 @@ standard_portal_menu_items = [ {"title": _("Prescription"), "route": "/prescription", "reference_doctype": "Consultation", "role":"Patient"}, {"title": _("Patient Appointment"), "route": "/patient-appointments", "reference_doctype": "Patient Appointment", "role":"Patient"}, {"title": _("Fees"), "route": "/fees", "reference_doctype": "Fees", "role":"Student"}, - {"title": _("Newsletter"), "route": "/newsletters", "reference_doctype": "Newsletter"} + {"title": _("Newsletter"), "route": "/newsletters", "reference_doctype": "Newsletter"}, + {"title": _("Admission"), "route": "/admissions", "reference_doctype": "Student Admission"} ] default_roles = [ @@ -208,7 +219,7 @@ scheduler_events = { "erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status", "erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards", "erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history", - "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms", + "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms" ] } diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json index 87f05377cd4..227302c16c7 100644 --- a/erpnext/hr/doctype/employee/employee.json +++ b/erpnext/hr/doctype/employee/employee.json @@ -149,7 +149,7 @@ "in_filter": 0, "in_global_search": 1, "in_list_view": 1, - "in_standard_filter": 0, + "in_standard_filter": 1, "label": "Full Name", "length": 0, "no_copy": 0, @@ -431,7 +431,7 @@ "no_copy": 0, "oldfieldname": "gender", "oldfieldtype": "Select", - "options": "Gender", + "options": "Gender", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -2432,7 +2432,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-06-13 14:29:13.694009", + "modified": "2017-10-04 11:42:02.495731", "modified_by": "Administrator", "module": "HR", "name": "Employee", diff --git a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json index bafee91df24..99e79942bfa 100644 --- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json +++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, "beta": 0, @@ -10,16 +11,20 @@ "editable_grid": 1, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "expense_date", "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Expense Date", "length": 0, "no_copy": 0, @@ -30,6 +35,7 @@ "print_hide_if_no_value": 0, "print_width": "150px", "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -38,16 +44,20 @@ "width": "150px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "column_break_2", "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -55,6 +65,7 @@ "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, @@ -62,16 +73,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "expense_type", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Expense Claim Type", "length": 0, "no_copy": 0, @@ -83,6 +98,7 @@ "print_hide_if_no_value": 0, "print_width": "150px", "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, @@ -91,9 +107,11 @@ "width": "150px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "depends_on": "expense_type", "fieldname": "default_account", "fieldtype": "Link", @@ -101,7 +119,9 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Default Account", "length": 0, "no_copy": 0, @@ -111,6 +131,7 @@ "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -118,16 +139,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "section_break_4", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -135,6 +160,7 @@ "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, @@ -142,26 +168,32 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "description", "fieldtype": "Text Editor", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Description", "length": 0, "no_copy": 0, "oldfieldname": "description", "oldfieldtype": "Small Text", + "options": "expense_type.description", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, "print_width": "300px", "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -170,16 +202,20 @@ "width": "300px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "section_break_6", "fieldtype": "Section Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -187,6 +223,7 @@ "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, @@ -194,16 +231,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "claim_amount", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Claim Amount", "length": 0, "no_copy": 0, @@ -215,6 +256,7 @@ "print_hide_if_no_value": 0, "print_width": "150px", "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 1, "search_index": 0, @@ -223,16 +265,20 @@ "width": "150px" }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "column_break_8", "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -240,6 +286,7 @@ "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, @@ -247,16 +294,20 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "sanctioned_amount", "fieldtype": "Currency", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 1, + "in_standard_filter": 0, "label": "Sanctioned Amount", "length": 0, "no_copy": 1, @@ -268,6 +319,7 @@ "print_hide_if_no_value": 0, "print_width": "150px", "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -276,17 +328,17 @@ "width": "150px" } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "idx": 1, "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2016-07-11 03:28:00.406154", + "modified": "2017-10-11 12:50:48.606727", "modified_by": "Administrator", "module": "HR", "name": "Expense Claim Detail", @@ -295,7 +347,9 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", + "track_changes": 0, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/hr/doctype/job_opening/job_opening.py b/erpnext/hr/doctype/job_opening/job_opening.py index 3d935f55e6b..60c911a0161 100644 --- a/erpnext/hr/doctype/job_opening/job_opening.py +++ b/erpnext/hr/doctype/job_opening/job_opening.py @@ -21,7 +21,7 @@ class JobOpening(WebsiteGenerator): self.route = frappe.scrub(self.job_title).replace('_', '-') def get_context(self, context): - context.parents = [{'name': 'jobs', 'title': _('All Jobs') }] + context.parents = [{'route': 'jobs', 'title': _('All Jobs') }] def get_list_context(context): context.title = _("Jobs") diff --git a/erpnext/hr/doctype/offer_letter/test_offer_letter.js b/erpnext/hr/doctype/offer_letter/test_offer_letter.js index 20695326129..c9b08a6c50d 100644 --- a/erpnext/hr/doctype/offer_letter/test_offer_letter.js +++ b/erpnext/hr/doctype/offer_letter/test_offer_letter.js @@ -27,13 +27,13 @@ QUnit.test("Test: Offer Letter [HR]", function (assert) { ]}, ]); }, - () => frappe.timeout(8), + () => frappe.timeout(10), () => frappe.click_button('Submit'), () => frappe.timeout(2), () => frappe.click_button('Yes'), - () => frappe.timeout(8), + () => frappe.timeout(5), + // To check if the fields are correctly set () => { - // To check if the fields are correctly set assert.ok(cur_frm.get_field('status').value=='Accepted', 'Status of job offer is correct'); assert.ok(cur_frm.get_field('designation').value=='Software Developer', @@ -45,7 +45,7 @@ QUnit.test("Test: Offer Letter [HR]", function (assert) { () => { assert.ok(cur_list.data[0].docstatus==1,'Offer Letter Submitted successfully'); }, - () => frappe.timeout(4), + () => frappe.timeout(2), () => done() ]); }); \ No newline at end of file diff --git a/erpnext/hr/doctype/process_payroll/process_payroll.py b/erpnext/hr/doctype/process_payroll/process_payroll.py index 55c0cce59f6..0e329a7c19b 100644 --- a/erpnext/hr/doctype/process_payroll/process_payroll.py +++ b/erpnext/hr/doctype/process_payroll/process_payroll.py @@ -284,7 +284,7 @@ class ProcessPayroll(Document): }) # Deductions - for acc, amt in deductions.items(): + for acc, amount in deductions.items(): payable_amount -= flt(amount, precision) accounts.append({ "account": acc, diff --git a/erpnext/hr/doctype/salary_detail/salary_detail.json b/erpnext/hr/doctype/salary_detail/salary_detail.json index d1312957658..01d02779b79 100644 --- a/erpnext/hr/doctype/salary_detail/salary_detail.json +++ b/erpnext/hr/doctype/salary_detail/salary_detail.json @@ -12,6 +12,7 @@ "editable_grid": 1, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -42,6 +43,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -73,6 +75,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -101,6 +104,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -131,6 +135,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -159,6 +164,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -189,6 +195,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -221,6 +228,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -253,6 +261,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -284,6 +293,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -314,6 +324,37 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "do_not_include_in_total", + "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": "Do not include in total", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -345,6 +386,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -374,6 +416,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -415,8 +458,8 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-04-13 00:47:33.980646", - "modified_by": "chude.osiegbu@manqala.com", + "modified": "2017-10-02 13:57:22.769751", + "modified_by": "Administrator", "module": "HR", "name": "Salary Detail", "name_case": "", diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js index de3276c8e3f..24f2016bd62 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.js +++ b/erpnext/hr/doctype/salary_slip/salary_slip.js @@ -158,14 +158,18 @@ var calculate_earning_total = function(doc, dt, dn, reset_amount) { var total_earn = 0; for(var i = 0; i < tbl.length; i++){ if(cint(tbl[i].depends_on_lwp) == 1) { + tbl[i].amount = Math.round(tbl[i].default_amount)*(flt(doc.payment_days) / cint(doc.total_working_days)*100)/100; refresh_field('amount', tbl[i].name, 'earnings'); + } else if(reset_amount) { tbl[i].amount = tbl[i].default_amount; refresh_field('amount', tbl[i].name, 'earnings'); } - total_earn += flt(tbl[i].amount); + if(!tbl[i].do_not_include_in_total) { + total_earn += flt(tbl[i].amount); + } } doc.gross_pay = total_earn; refresh_many(['amount','gross_pay']); @@ -184,7 +188,9 @@ var calculate_ded_total = function(doc, dt, dn, reset_amount) { tbl[i].amount = tbl[i].default_amount; refresh_field('amount', tbl[i].name, 'deductions'); } - total_ded += flt(tbl[i].amount); + if(!tbl[i].do_not_include_in_total) { + total_ded += flt(tbl[i].amount); + } } doc.total_deduction = total_ded; refresh_field('total_deduction'); diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 356104e69c2..7581624bef7 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -69,7 +69,9 @@ class SalarySlip(TransactionBase): 'amount': amount, 'default_amount': amount, 'depends_on_lwp' : struct_row.depends_on_lwp, - 'salary_component' : struct_row.salary_component + 'salary_component' : struct_row.salary_component, + 'abbr' : struct_row.abbr, + 'do_not_include_in_total' : struct_row.do_not_include_in_total }) else: component_row.amount = amount @@ -345,11 +347,13 @@ class SalarySlip(TransactionBase): (flt(d.default_amount) * flt(self.payment_days) / cint(self.total_working_days)), self.precision("amount", component_type) ) + elif not self.payment_days and not self.salary_slip_based_on_timesheet: d.amount = 0 elif not d.amount: d.amount = d.default_amount - self.set(total_field, self.get(total_field) + flt(d.amount)) + if not d.do_not_include_in_total: + self.set(total_field, self.get(total_field) + flt(d.amount)) def calculate_net_pay(self): if self.salary_structure: diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.js b/erpnext/hr/doctype/salary_slip/test_salary_slip.js index a49c973d132..619e5300ca7 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.js +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.js @@ -15,7 +15,7 @@ QUnit.test("test salary slip", function(assert) { { employee: employee_name} ]); }, - () => frappe.timeout(1), + () => frappe.timeout(3), () => { // To check if all the calculations are correctly done if(ename === 'Test Employee 1') @@ -43,7 +43,7 @@ QUnit.test("test salary slip", function(assert) { () => salary_slip('Test Employee 1'), () => frappe.timeout(6), () => salary_slip('Test Employee 3'), - () => frappe.timeout(3), + () => frappe.timeout(5), () => done() ]); }); \ No newline at end of file diff --git a/erpnext/hr/doctype/salary_structure/test_salary_structure.js b/erpnext/hr/doctype/salary_structure/test_salary_structure.js index 8276a82cb79..542fa503549 100644 --- a/erpnext/hr/doctype/salary_structure/test_salary_structure.js +++ b/erpnext/hr/doctype/salary_structure/test_salary_structure.js @@ -1,5 +1,5 @@ QUnit.test("test Salary Structure", function(assert) { - assert.expect(6); + assert.expect(7); let done = assert.async(); let employee_name1; @@ -9,10 +9,12 @@ QUnit.test("test Salary Structure", function(assert) { employee_name1 = r.name; } ), + () => frappe.timeout(5), () => frappe.db.get_value('Employee', {'employee_name': "Test Employee 3"}, 'name', (r) => { // Creating Salary Structure for employees); return frappe.tests.make('Salary Structure', [ + { __newname: 'Test Salary Structure'}, { company: 'For Testing'}, { payroll_frequency: 'Monthly'}, { employees: [ @@ -47,16 +49,14 @@ QUnit.test("test Salary Structure", function(assert) { ]); } ), - () => frappe.timeout(18), - () => cur_dialog.set_value('value','Test Salary Structure'), - () => frappe.timeout(1), - () => frappe.click_button('Create'), - () => frappe.timeout(1), + () => frappe.timeout(15), () => { - // To check if all the fields are correctly set - assert.ok(cur_frm.doc.employees[0].employee_name.includes('Test Employee 1') && - cur_frm.doc.employees[1].employee_name.includes('Test Employee 3'), - 'Employee names are correctly set'); + // To check if all the fields are correctly set + assert.ok(cur_frm.doc.employees[0].employee_name=='Test Employee 1', + 'Employee 1 name correctly set'); + + assert.ok(cur_frm.doc.employees[1].employee_name=='Test Employee 3', + 'Employee 2 name correctly set'); assert.ok(cur_frm.doc.employees[0].base==25000, 'Base value for first employee is correctly set'); diff --git a/erpnext/hr/doctype/training_event/test_training_event.py b/erpnext/hr/doctype/training_event/test_training_event.py index 03416ee1f43..57123e304f5 100644 --- a/erpnext/hr/doctype/training_event/test_training_event.py +++ b/erpnext/hr/doctype/training_event/test_training_event.py @@ -5,8 +5,38 @@ from __future__ import unicode_literals import frappe import unittest - -# test_records = frappe.get_test_records('Training Event') +from frappe.utils import today, add_days +from erpnext.hr.doctype.salary_structure.test_salary_structure import make_employee class TestTrainingEvent(unittest.TestCase): - pass + def setUp(self): + create_training_program("Basic Training") + self.employee = make_employee("robert_loan@trainig.com") + self.employee2 = make_employee("suzie.tan@trainig.com") + + def test_create_training_event(self): + if not frappe.db.get_value("Training Event", "Basic Training Event"): + frappe.get_doc({ + "doctype": "Training Event", + "event_name": "Basic Training Event", + "training_program": "Basic Training", + "location": "Union Square", + "start_time": add_days(today(), 5), + "end_time": add_days(today(), 6), + "introduction": "Welcome to the Basic Training Event", + "employees": get_attendees(self.employee, self.employee2) + }).insert() + +def create_training_program(training_program): + if not frappe.db.get_value("Training Program", training_program): + frappe.get_doc({ + "doctype": "Training Program", + "training_program": training_program, + "description": training_program + }).insert() + +def get_attendees(employee, employee2): + return [ + {"employee": employee}, + {"employee": employee2} + ] \ No newline at end of file diff --git a/erpnext/hr/doctype/training_event/tests/test_training_event.js b/erpnext/hr/doctype/training_event/tests/test_training_event.js index a359af3329d..8ff4fecd6ee 100644 --- a/erpnext/hr/doctype/training_event/tests/test_training_event.js +++ b/erpnext/hr/doctype/training_event/tests/test_training_event.js @@ -1,7 +1,7 @@ QUnit.module('hr'); QUnit.test("Test: Training Event [HR]", function (assert) { - assert.expect(4); + assert.expect(5); let done = assert.async(); let employee_name; @@ -21,7 +21,8 @@ QUnit.test("Test: Training Event [HR]", function (assert) { { employees: [ [ {employee: employee_name}, - {employee_name: 'Test Employee 1'} + {employee_name: 'Test Employee 1'}, + {attendance: 'Optional'} ] ]}, ]); @@ -41,6 +42,9 @@ QUnit.test("Test: Training Event [HR]", function (assert) { assert.ok(cur_frm.doc.employees[0].employee_name=='Test Employee 1', 'Attendee Employee is correctly set'); + + assert.ok(cur_frm.doc.employees[0].attendance=='Optional', + 'Attendance is correctly set'); }, () => frappe.set_route('List','Training Event','List'), diff --git a/erpnext/hr/doctype/training_event/tests/test_training_event_attendance.js b/erpnext/hr/doctype/training_event/tests/test_training_event_attendance.js deleted file mode 100644 index 6364308f731..00000000000 --- a/erpnext/hr/doctype/training_event/tests/test_training_event_attendance.js +++ /dev/null @@ -1,40 +0,0 @@ -QUnit.module('hr'); - -QUnit.test("test: Training Event", function (assert) { - // number of asserts - assert.expect(1); - let done = assert.async(); - - frappe.run_serially([ - // insert a new Training Event - () => frappe.set_route("List", "Training Event", "List"), - () => frappe.new_doc("Training Event"), - () => frappe.timeout(1), - () => frappe.click_link('Edit in full page'), - () => cur_frm.set_value("event_name", "Test Event " + frappe.utils.get_random(10)), - () => cur_frm.set_value("start_time", "2017-07-26, 2:00 pm PDT"), - () => cur_frm.set_value("end_time", "2017-07-26, 2:30 pm PDT"), - () => cur_frm.set_value("introduction", "This is a test report"), - () => cur_frm.set_value("location", "Fake office"), - () => frappe.click_button('Add Row'), - () => frappe.db.get_value('Employee', {'employee_name':'Test Employee 1'}, 'name'), - (r) => { - console.log(r); - return cur_frm.fields_dict.employees.grid.grid_rows[0].doc.employee = r.message.name; - }, - () => { - return cur_frm.fields_dict.employees.grid.grid_rows[0].doc.attendance = "Optional"; - }, - () => frappe.click_button('Save'), - () => frappe.timeout(2), - () => frappe.click_button('Submit'), - () => frappe.timeout(2), - () => frappe.click_button('Yes'), - () => frappe.timeout(1), - () => { - assert.equal(cur_frm.doc.docstatus, 1); - }, - () => done() - ]); - -}); \ No newline at end of file diff --git a/erpnext/hr/doctype/training_event/training_event.js b/erpnext/hr/doctype/training_event/training_event.js index 6a6e8fe0a6a..12bc920b187 100644 --- a/erpnext/hr/doctype/training_event/training_event.js +++ b/erpnext/hr/doctype/training_event/training_event.js @@ -2,6 +2,9 @@ // For license information, please see license.txt frappe.ui.form.on('Training Event', { + onload_post_render: function(frm) { + frm.get_field("employees").grid.set_multiple_add("employee"); + }, refresh: function(frm) { if(!frm.doc.__islocal) { frm.add_custom_button(__("Training Result"), function() { @@ -18,4 +21,4 @@ frappe.ui.form.on('Training Event', { }); } } -}); \ No newline at end of file +}); diff --git a/erpnext/hr/doctype/training_event/training_event.json b/erpnext/hr/doctype/training_event/training_event.json index 7be9d974fe6..4b812a992e0 100644 --- a/erpnext/hr/doctype/training_event/training_event.json +++ b/erpnext/hr/doctype/training_event/training_event.json @@ -42,6 +42,37 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "training_program", + "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": "Training Program", + "length": 0, + "no_copy": 0, + "options": "Training Program", + "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": 1, @@ -73,6 +104,37 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.type == 'Seminar' || doc.type == 'Workshop' || doc.type == 'Conference' || doc.type == 'Exam'", + "fieldname": "has_certificate", + "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": "Has Certificate", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -133,6 +195,69 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.type == 'Seminar' || doc.type == 'Workshop' || doc.type == 'Exam'", + "fieldname": "level", + "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": "Level", + "length": 0, + "no_copy": 0, + "options": "\nBeginner\nExpert\nAdvance", + "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": "company", + "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": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "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, @@ -684,7 +809,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-11 03:11:25.768563", + "modified": "2017-10-23 06:13:29.065781", "modified_by": "Administrator", "module": "HR", "name": "Training Event", @@ -712,7 +837,7 @@ "write": 1 } ], - "quick_entry": 1, + "quick_entry": 0, "read_only": 0, "read_only_onload": 0, "search_fields": "event_name", diff --git a/erpnext/hr/doctype/training_event/training_event.py b/erpnext/hr/doctype/training_event/training_event.py index cc568414a03..19721005d14 100644 --- a/erpnext/hr/doctype/training_event/training_event.py +++ b/erpnext/hr/doctype/training_event/training_event.py @@ -3,6 +3,7 @@ # For license information, please see license.txt from __future__ import unicode_literals +import frappe from frappe.model.document import Document from erpnext.hr.doctype.employee.employee import get_employee_emails @@ -10,3 +11,29 @@ class TrainingEvent(Document): def validate(self): self.employee_emails = ', '.join(get_employee_emails([d.employee for d in self.employees])) + +@frappe.whitelist() +def get_events(start, end, filters=None): + """Returns events for Gantt / Calendar view rendering. + + :param start: Start date-time. + :param end: End date-time. + :param filters: Filters (JSON). + """ + from frappe.desk.calendar import get_event_conditions + conditions = get_event_conditions("Training Event", filters) + + data = frappe.db.sql(""" + select + name, event_name, event_status, start_time, end_time + from + `tabTraining Event` + where (ifnull(start_time, '0000-00-00')!= '0000-00-00') \ + and (start_time between %(start)s and %(end)s) + and docstatus < 2 + {conditions} + """.format(conditions=conditions), { + "start": start, + "end": end + }, as_dict=True, update={"allDay": 0}) + return data diff --git a/erpnext/hr/doctype/training_event/training_event_calendar.js b/erpnext/hr/doctype/training_event/training_event_calendar.js new file mode 100644 index 00000000000..cb938518a4b --- /dev/null +++ b/erpnext/hr/doctype/training_event/training_event_calendar.js @@ -0,0 +1,14 @@ +// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +frappe.views.calendar["Training Event"] = { + field_map: { + "start": "start_time", + "end": "end_time", + "id": "name", + "title": "event_name", + "allDay": "allDay" + }, + gantt: true, + get_events_method: "erpnext.hr.doctype.training_event.training_event.get_events", +} diff --git a/erpnext/hr/doctype/training_event_employee/training_event_employee.json b/erpnext/hr/doctype/training_event_employee/training_event_employee.json index a8a72b1a701..76adcb0ed22 100644 --- a/erpnext/hr/doctype/training_event_employee/training_event_employee.json +++ b/erpnext/hr/doctype/training_event_employee/training_event_employee.json @@ -147,7 +147,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, "label": "Attendance", "length": 0, @@ -176,7 +176,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-08-11 03:36:22.738253", + "modified": "2017-10-05 08:49:41.869998", "modified_by": "Administrator", "module": "HR", "name": "Training Event Employee", diff --git a/erpnext/hr/doctype/training_program/__init__.py b/erpnext/hr/doctype/training_program/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.js b/erpnext/hr/doctype/training_program/test_training_program.js similarity index 65% rename from erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.js rename to erpnext/hr/doctype/training_program/test_training_program.js index 7097a6dcb2b..3a62b2fa221 100644 --- a/erpnext/buying/doctype/supplier_quotation/test_supplier_quotation.js +++ b/erpnext/hr/doctype/training_program/test_training_program.js @@ -2,15 +2,15 @@ // rename this file from _test_[name] to test_[name] to activate // and remove above this line -QUnit.test("test: Supplier Quotation", function (assert) { +QUnit.test("test: Training Program", 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([ + frappe.run_serially([ + // insert a new Training Program + () => frappe.tests.make('Training Program', [ // values to be set {key: 'value'} ]), diff --git a/erpnext/hr/doctype/training_program/test_training_program.py b/erpnext/hr/doctype/training_program/test_training_program.py new file mode 100644 index 00000000000..9d5b28616b1 --- /dev/null +++ b/erpnext/hr/doctype/training_program/test_training_program.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import unittest + +class TestTrainingProgram(unittest.TestCase): + pass diff --git a/erpnext/hr/doctype/training_program/training_program.js b/erpnext/hr/doctype/training_program/training_program.js new file mode 100644 index 00000000000..7d85cab59dc --- /dev/null +++ b/erpnext/hr/doctype/training_program/training_program.js @@ -0,0 +1,5 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Training Program', { +}); \ No newline at end of file diff --git a/erpnext/hr/doctype/training_program/training_program.json b/erpnext/hr/doctype/training_program/training_program.json new file mode 100644 index 00000000000..d9b33d5de7d --- /dev/null +++ b/erpnext/hr/doctype/training_program/training_program.json @@ -0,0 +1,454 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "field:training_program", + "beta": 0, + "creation": "2017-10-11 04:43:17.230065", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "training_program", + "fieldtype": "Data", + "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": "Training Program", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 1, + "bold": 1, + "collapsible": 0, + "columns": 0, + "default": "Scheduled", + "fieldname": "status", + "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": "Status", + "length": 0, + "no_copy": 0, + "options": "Scheduled\nCompleted\nCancelled", + "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_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_5", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "trainer_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Trainer Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "trainer_email", + "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": "Trainer Email", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_8", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "supplier", + "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": "Supplier", + "length": 0, + "no_copy": 0, + "options": "Supplier", + "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": "contact_number", + "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": "Contact Number", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_11", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "description", + "fieldtype": "Text Editor", + "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": "Description", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amended_from", + "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": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Training Program", + "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 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-10-16 05:34:23.055153", + "modified_by": "Administrator", + "module": "HR", + "name": "Training Program", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "HR Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "training_program", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/hr/doctype/training_program/training_program.py b/erpnext/hr/doctype/training_program/training_program.py new file mode 100644 index 00000000000..7a3720b66b6 --- /dev/null +++ b/erpnext/hr/doctype/training_program/training_program.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from frappe.model.document import Document + +class TrainingProgram(Document): + pass diff --git a/erpnext/hr/doctype/training_program/training_program_dashboard.py b/erpnext/hr/doctype/training_program/training_program_dashboard.py new file mode 100644 index 00000000000..a314081c6b9 --- /dev/null +++ b/erpnext/hr/doctype/training_program/training_program_dashboard.py @@ -0,0 +1,12 @@ +from frappe import _ + +def get_data(): + return { + 'fieldname': 'training_program', + 'transactions': [ + { + 'label': _('Training Events'), + 'items': ['Training Event'] + }, + ] + } \ No newline at end of file diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.js b/erpnext/hr/doctype/upload_attendance/upload_attendance.js index f639898e27c..776fd3c13b0 100644 --- a/erpnext/hr/doctype/upload_attendance/upload_attendance.js +++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.js @@ -39,6 +39,7 @@ erpnext.hr.AttendanceControlPanel = frappe.ui.form.Controller.extend({ args: { method: 'erpnext.hr.doctype.upload_attendance.upload_attendance.upload' }, + no_socketio: true, sample_url: "e.g. http://example.com/somefile.csv", callback: function(attachment, r) { var $log_wrapper = $(cur_frm.fields_dict.import_log.wrapper).empty(); diff --git a/erpnext/hr/email_alert/training_scheduled/training_scheduled.json b/erpnext/hr/email_alert/training_scheduled/training_scheduled.json index e1631f86839..0782f0cfc11 100644 --- a/erpnext/hr/email_alert/training_scheduled/training_scheduled.json +++ b/erpnext/hr/email_alert/training_scheduled/training_scheduled.json @@ -10,8 +10,8 @@ "idx": 0, "is_standard": 1, "message": "

{{_(\"Training Event\")}}

\n\n

{{ doc.introduction }}

\n\n

{{_(\"Details\")}}

\n{{_(\"Event Name\")}}: {{ frappe.utils.get_link_to_form(doc.doctype, doc.name) }}\n
{{_(\"Event Location\")}}: {{ doc.location }}\n
{{_(\"Start Time\")}}: {{ doc.start_time }}\n
{{_(\"End Time\")}}: {{ doc.end_time }}\n", - "modified": "2017-08-13 22:49:42.338881", - "modified_by": "Administrator", + "modified": "2017-08-13 22:49:42.338881", + "modified_by": "Administrator", "module": "HR", "name": "Training Scheduled", "owner": "Administrator", diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py index bb200a997ed..698c4fbd7c9 100644 --- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py +++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py @@ -36,7 +36,7 @@ def execute(filters=None): status_map = {"Present": "P", "Absent": "A", "Half Day": "HD", "On Leave": "L", "None": "", "Holiday":"H"} if status == "None" and holiday_map: emp_holiday_list = emp_det.holiday_list if emp_det.holiday_list else default_holiday_list - if (day+1) in holiday_map[emp_holiday_list]: + if emp_holiday_list in holiday_map and (day+1) in holiday_map[emp_holiday_list]: status = "Holiday" row.append(status_map[status]) @@ -45,7 +45,7 @@ def execute(filters=None): elif status == "Absent": total_a += 1 elif status == "On Leave": - total_l += 1 + total_l += 1 elif status == "Half Day": total_p += 0.5 total_a += 0.5 diff --git a/erpnext/hr/report/salary_register/salary_register.html b/erpnext/hr/report/salary_register/salary_register.html index d7bf6a78bc7..4c7e1d1d3af 100644 --- a/erpnext/hr/report/salary_register/salary_register.html +++ b/erpnext/hr/report/salary_register/salary_register.html @@ -12,21 +12,21 @@ {% } %} - + {% for(var j=0, k=data.length; j {% for(var i=1, l=report.columns.length; i {% var fieldname = report.columns[i].field; %} - {% if (i > 10) { %} - {%= format_currency(row[fieldname]) %} - {% } else { %} - {% if (!is_null(row[fieldname])) { %} - {%= row[fieldname] %} - {% } %} + {% if (report.columns[i].fieldtype=='Currency' && !isNaN(row[fieldname])) { %} + {%= format_currency(row[fieldname]) %} + {% } else { %} + {% if (!is_null(row[fieldname])) { %} + {%= row[fieldname] %} + {% } %} {% } %} {% } %} diff --git a/erpnext/hr/report/salary_register/salary_register.py b/erpnext/hr/report/salary_register/salary_register.py index 88f6f470b1e..8b93182d34e 100644 --- a/erpnext/hr/report/salary_register/salary_register.py +++ b/erpnext/hr/report/salary_register/salary_register.py @@ -19,6 +19,12 @@ def execute(filters=None): row = [ss.name, ss.employee, ss.employee_name, ss.branch, ss.department, ss.designation, ss.company, ss.start_date, ss.end_date, ss.leave_withut_pay, ss.payment_days] + if not ss.branch == None:columns[3] = columns[3].replace('-1','120') + if not ss.department == None: columns[4] = columns[4].replace('-1','120') + if not ss.designation == None: columns[5] = columns[5].replace('-1','120') + if not ss.leave_withut_pay == None: columns[9] = columns[9].replace('-1','130') + + for e in earning_types: row.append(ss_earning_map.get(ss.name, {}).get(e)) @@ -34,12 +40,20 @@ def execute(filters=None): return columns, data def get_columns(salary_slips): + """ columns = [ _("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140", _("Branch") + ":Link/Branch:120", _("Department") + ":Link/Department:120", _("Designation") + ":Link/Designation:120", _("Company") + ":Link/Company:120", _("Start Date") + "::80", _("End Date") + "::80", _("Leave Without Pay") + ":Float:130", _("Payment Days") + ":Float:120" ] + """ + columns = [ + _("Salary Slip ID") + ":Link/Salary Slip:150",_("Employee") + ":Link/Employee:120", _("Employee Name") + "::140", _("Branch") + ":Link/Branch:-1", + _("Department") + ":Link/Department:-1", _("Designation") + ":Link/Designation:-1", + _("Company") + ":Link/Company:120", _("Start Date") + "::80", _("End Date") + "::80", _("Leave Without Pay") + ":Float:-1", + _("Payment Days") + ":Float:120" + ] salary_components = {_("Earning"): [], _("Deduction"): []} diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py index 63e5f3c0a43..93ea11c6404 100644 --- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py +++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py @@ -29,26 +29,26 @@ def get_columns(): def get_log_data(filters): fy = frappe.db.get_value('Fiscal Year', filters.get('fiscal_year'), ['year_start_date', 'year_end_date'], as_dict=True) - data = frappe.db.sql("""select + data = frappe.db.sql("""select vhcl.license_plate as "License", vhcl.make as "Make", vhcl.model as "Model", - vhcl.location as "Location", log.name as "Log", log.odometer as "Odometer", + vhcl.location as "Location", log.name as "Log", log.odometer as "Odometer", log.date as "Date", log.fuel_qty as "Fuel Qty", log.price as "Fuel Price" - from + from `tabVehicle` vhcl,`tabVehicle Log` log - where + where vhcl.license_plate = log.license_plate and log.docstatus = 1 and date between %s and %s order by date""" ,(fy.year_start_date, fy.year_end_date), as_dict=1) dl=list(data) for row in dl: row["Service Expense"]= get_service_expense(row["Log"]) return dl - + def get_service_expense(logname): - expense_amount = frappe.db.sql("""select sum(expense_amount) - from `tabVehicle Log` log,`tabVehicle Service` ser + expense_amount = frappe.db.sql("""select sum(expense_amount) + from `tabVehicle Log` log,`tabVehicle Service` ser where ser.parent=log.name and log.name=%s""",logname) return flt(expense_amount[0][0]) if expense_amount else 0 - + def get_chart_data(data,period_list): fuel_exp_data,service_exp_data,fueldata,servicedata = [],[],[],[] service_exp_data = [] @@ -63,19 +63,25 @@ def get_chart_data(data,period_list): fueldata.append([period.key,total_fuel_exp]) servicedata.append([period.key,total_ser_exp]) - x_intervals = ['x'] + [period.key for period in period_list] + labels = [period.key for period in period_list] fuel_exp_data= [row[1] for row in fueldata] service_exp_data= [row[1] for row in servicedata] - columns = [x_intervals] + datasets = [] if fuel_exp_data: - columns.append(["Fuel Expenses"]+ fuel_exp_data) + datasets.append({ + 'title': 'Fuel Expenses', + 'values': fuel_exp_data + }) if service_exp_data: - columns.append(["Service Expenses"]+ service_exp_data) + datasets.append({ + 'title': 'Service Expenses', + 'values': service_exp_data + }) chart = { "data": { - 'x': 'x', - 'columns': columns + 'labels': labels, + 'datasets': datasets } } - chart["chart_type"] = "line" + chart["type"] = "line" return chart \ No newline at end of file diff --git a/erpnext/hub/__init__.py b/erpnext/hub/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hub_node/__init__.py b/erpnext/hub_node/__init__.py index 1c9729955cb..3216f0d7533 100644 --- a/erpnext/hub_node/__init__.py +++ b/erpnext/hub_node/__init__.py @@ -2,16 +2,177 @@ # For license information, please see license.txt from __future__ import unicode_literals -import frappe, requests +import frappe, requests, json +from frappe.utils import now, nowdate, cint +from frappe.utils.nestedset import get_root_of +from frappe.contacts.doctype.contact.contact import get_default_contact @frappe.whitelist() -def get_items(text, start, limit): - hub = frappe.get_single("Hub Settings") - response = requests.get(hub.hub_url + "/api/method/hub.hub.api.get_items", params={ - "access_token": hub.access_token, - "text": text, - "start": start, - "limit": limit - }) - response.raise_for_status() - return response.json().get("message") +def enable_hub(): + hub_settings = frappe.get_doc('Hub Settings') + hub_settings.register() + frappe.db.commit() + return hub_settings + +@frappe.whitelist() +def get_items(start=0, limit=20, category=None, order_by=None, company=None, text=None): + connection = get_connection() + filters = { + 'hub_category': category, + } + if text: + filters.update({'item_name': ('like', '%' + text + '%')}) + if company: + filters.update({'company_name': company}) + + response = connection.get_list('Hub Item', + limit_start=start, limit_page_length=limit, + filters=filters) + return response + +@frappe.whitelist() +def get_categories(): + connection = get_connection() + response = connection.get_list('Hub Category') + return response + +@frappe.whitelist() +def get_item_details(hub_sync_id): + connection = get_connection() + return connection.get_doc('Hub Item', hub_sync_id) + +@frappe.whitelist() +def get_company_details(hub_sync_id): + connection = get_connection() + return connection.get_doc('Hub Company', hub_sync_id) + +def get_connection(): + hub_connector = frappe.get_doc( + 'Data Migration Connector', 'Hub Connector') + hub_connection = hub_connector.get_connection() + # frappeclient connection + return hub_connection.connection + +def make_opportunity(buyer_name, email_id): + buyer_name = "HUB-" + buyer_name + + if not frappe.db.exists('Lead', {'email_id': email_id}): + lead = frappe.new_doc("Lead") + lead.lead_name = buyer_name + lead.email_id = email_id + lead.save(ignore_permissions=True) + + o = frappe.new_doc("Opportunity") + o.enquiry_from = "Lead" + o.lead = frappe.get_all("Lead", filters={"email_id": email_id}, fields = ["name"])[0]["name"] + o.save(ignore_permissions=True) + +@frappe.whitelist() +def make_rfq_and_send_opportunity(item, supplier): + supplier = make_supplier(supplier) + contact = make_contact(supplier) + item = make_item(item) + rfq = make_rfq(item, supplier, contact) + status = send_opportunity(contact) + + return { + 'rfq': rfq, + 'hub_document_created': status + } + +def make_supplier(supplier): + # make supplier if not already exists + supplier = frappe._dict(json.loads(supplier)) + + if not frappe.db.exists('Supplier', {'supplier_name': supplier.supplier_name}): + supplier_doc = frappe.get_doc({ + 'doctype': 'Supplier', + 'supplier_name': supplier.supplier_name, + 'supplier_type': supplier.supplier_type, + 'supplier_email': supplier.supplier_email + }).insert() + else: + supplier_doc = frappe.get_doc('Supplier', supplier.supplier_name) + + return supplier_doc + +def make_contact(supplier): + contact_name = get_default_contact('Supplier', supplier.supplier_name) + # make contact if not already exists + if not contact_name: + contact = frappe.get_doc({ + 'doctype': 'Contact', + 'first_name': supplier.supplier_name, + 'email_id': supplier.supplier_email, + 'is_primary_contact': 1, + 'links': [ + {'link_doctype': 'Supplier', 'link_name': supplier.supplier_name} + ] + }).insert() + else: + contact = frappe.get_doc('Contact', contact_name) + + return contact + +def make_item(item): + # make item if not already exists + item = frappe._dict(json.loads(item)) + + if not frappe.db.exists('Item', {'item_code': item.item_code}): + item_doc = frappe.get_doc({ + 'doctype': 'Item', + 'item_code': item.item_code, + 'item_group': item.item_group, + 'is_item_from_hub': 1 + }).insert() + else: + item_doc = frappe.get_doc('Item', item.item_code) + + return item_doc + +def make_rfq(item, supplier, contact): + # make rfq + rfq = frappe.get_doc({ + 'doctype': 'Request for Quotation', + 'transaction_date': nowdate(), + 'status': 'Draft', + 'company': frappe.db.get_single_value('Hub Settings', 'company'), + 'message_for_supplier': 'Please supply the specified items at the best possible rates', + 'suppliers': [ + { 'supplier': supplier.name, 'contact': contact.name } + ], + 'items': [ + { + 'item_code': item.item_code, + 'qty': 1, + 'schedule_date': nowdate(), + 'warehouse': item.default_warehouse or get_root_of("Warehouse"), + 'description': item.description, + 'uom': item.stock_uom + } + ] + }).insert() + + rfq.save() + rfq.submit() + return rfq + +def send_opportunity(contact): + # Make Hub Message on Hub with lead data + doc = { + 'doctype': 'Lead', + 'lead_name': frappe.db.get_single_value('Hub Settings', 'company'), + 'email_id': frappe.db.get_single_value('Hub Settings', 'user') + } + + args = frappe._dict(dict( + doctype='Hub Message', + reference_doctype='Lead', + data=json.dumps(doc), + user=contact.email_id + )) + + connection = get_connection() + response = connection.insert('Hub Message', args) + + return response.ok diff --git a/erpnext/hub_node/data_migration_mapping/__init__.py b/erpnext/hub_node/data_migration_mapping/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hub_node/data_migration_mapping/company_to_hub_company/__init__.py b/erpnext/hub_node/data_migration_mapping/company_to_hub_company/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json b/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json new file mode 100644 index 00000000000..0a916dac3fd --- /dev/null +++ b/erpnext/hub_node/data_migration_mapping/company_to_hub_company/company_to_hub_company.json @@ -0,0 +1,45 @@ +{ + "condition": "{'name': ('=', frappe.db.get_single_value('Hub Settings', 'company'))}", + "creation": "2017-09-07 11:38:43.169065", + "docstatus": 0, + "doctype": "Data Migration Mapping", + "fields": [ + { + "is_child_table": 0, + "local_fieldname": "name", + "remote_fieldname": "company_name" + }, + { + "is_child_table": 0, + "local_fieldname": "country", + "remote_fieldname": "country" + }, + { + "is_child_table": 0, + "local_fieldname": "\"city\"", + "remote_fieldname": "seller_city" + }, + { + "is_child_table": 0, + "local_fieldname": "eval:frappe.local.site", + "remote_fieldname": "site_name" + }, + { + "is_child_table": 0, + "local_fieldname": "eval:frappe.session.user", + "remote_fieldname": "user" + } + ], + "idx": 2, + "local_doctype": "Company", + "mapping_name": "Company to Hub Company", + "mapping_type": "Push", + "migration_id_field": "hub_sync_id", + "modified": "2017-10-09 17:30:17.853929", + "modified_by": "Administrator", + "name": "Company to Hub Company", + "owner": "Administrator", + "page_length": 10, + "remote_objectname": "Hub Company", + "remote_primary_key": "name" +} \ No newline at end of file diff --git a/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/__init__.py b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/__init__.py new file mode 100644 index 00000000000..79769ee5f89 --- /dev/null +++ b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/__init__.py @@ -0,0 +1,29 @@ +import frappe, json + +def pre_process(doc): + return json.loads(doc['data']) + +def post_process(remote_doc=None, local_doc=None, **kwargs): + if not local_doc: + return + + hub_message = remote_doc + # update hub message on hub + hub_connector = frappe.get_doc('Data Migration Connector', 'Hub Connector') + connection = hub_connector.get_connection() + connection.update('Hub Message', dict( + status='Synced' + ), hub_message['name']) + + # make opportunity after lead is created + lead = local_doc + opportunity = frappe.get_doc({ + 'doctype': 'Opportunity', + 'naming_series': 'OPTY-', + 'enquiry_type': 'Sales', + 'enquiry_from': 'Lead', + 'status': 'Open', + 'lead': lead.name, + 'company': lead.company, + 'transaction_date': frappe.utils.today() + }).insert() diff --git a/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json new file mode 100644 index 00000000000..cd9fb693d3d --- /dev/null +++ b/erpnext/hub_node/data_migration_mapping/hub_message_to_lead/hub_message_to_lead.json @@ -0,0 +1,31 @@ +{ + "condition": "{'reference_doctype': 'Lead', 'user': frappe.db.get_single_value('Hub Settings', 'user'), 'status': 'Pending'}", + "creation": "2017-09-20 15:06:40.279930", + "docstatus": 0, + "doctype": "Data Migration Mapping", + "fields": [ + { + "is_child_table": 0, + "local_fieldname": "email_id", + "remote_fieldname": "email_id" + }, + { + "is_child_table": 0, + "local_fieldname": "lead_name", + "remote_fieldname": "lead_name" + } + ], + "idx": 0, + "local_doctype": "Lead", + "local_primary_key": "email_id", + "mapping_name": "Hub Message to Lead", + "mapping_type": "Pull", + "migration_id_field": "hub_sync_id", + "modified": "2017-10-09 17:30:17.908830", + "modified_by": "Administrator", + "name": "Hub Message to Lead", + "owner": "frappetest@gmail.com", + "page_length": 10, + "remote_objectname": "Hub Message", + "remote_primary_key": "name" +} \ No newline at end of file diff --git a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json new file mode 100644 index 00000000000..e4168c75b56 --- /dev/null +++ b/erpnext/hub_node/data_migration_mapping/item_to_hub_item/item_to_hub_item.json @@ -0,0 +1,55 @@ +{ + "condition": "{\"publish_in_hub\": 1}", + "creation": "2017-09-07 13:27:52.726350", + "docstatus": 0, + "doctype": "Data Migration Mapping", + "fields": [ + { + "is_child_table": 0, + "local_fieldname": "item_code", + "remote_fieldname": "item_code" + }, + { + "is_child_table": 0, + "local_fieldname": "item_name", + "remote_fieldname": "item_name" + }, + { + "is_child_table": 0, + "local_fieldname": "eval:frappe.db.get_default(\"company\")", + "remote_fieldname": "company_name" + }, + { + "is_child_table": 0, + "local_fieldname": "image", + "remote_fieldname": "image" + }, + { + "is_child_table": 0, + "local_fieldname": "item_group", + "remote_fieldname": "item_group" + }, + { + "is_child_table": 0, + "local_fieldname": "eval:frappe.session.user", + "remote_fieldname": "seller" + }, + { + "is_child_table": 0, + "local_fieldname": "eval:frappe.db.get_default(\"country\")", + "remote_fieldname": "country" + } + ], + "idx": 1, + "local_doctype": "Item", + "mapping_name": "Item to Hub Item", + "mapping_type": "Push", + "migration_id_field": "hub_sync_id", + "modified": "2017-10-09 17:30:17.890337", + "modified_by": "Administrator", + "name": "Item to Hub Item", + "owner": "Administrator", + "page_length": 10, + "remote_objectname": "Hub Item", + "remote_primary_key": "item_code" +} \ No newline at end of file diff --git a/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json b/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json new file mode 100644 index 00000000000..40513cd2501 --- /dev/null +++ b/erpnext/hub_node/data_migration_plan/hub_sync/hub_sync.json @@ -0,0 +1,26 @@ +{ + "creation": "2017-09-07 11:39:38.445902", + "docstatus": 0, + "doctype": "Data Migration Plan", + "idx": 1, + "mappings": [ + { + "enabled": 1, + "mapping": "Company to Hub Company" + }, + { + "enabled": 1, + "mapping": "Item to Hub Item" + }, + { + "enabled": 1, + "mapping": "Hub Message to Lead" + } + ], + "modified": "2017-10-09 17:30:17.680059", + "modified_by": "Administrator", + "module": "Hub Node", + "name": "Hub Sync", + "owner": "Administrator", + "plan_name": "Hub Sync" +} \ No newline at end of file diff --git a/erpnext/hub_node/doctype/hub_category/__init__.py b/erpnext/hub_node/doctype/hub_category/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/hub_node/doctype/hub_category/hub_category.js b/erpnext/hub_node/doctype/hub_category/hub_category.js new file mode 100644 index 00000000000..9f54166e143 --- /dev/null +++ b/erpnext/hub_node/doctype/hub_category/hub_category.js @@ -0,0 +1,8 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Hub Category', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/hub_node/doctype/hub_category/hub_category.json b/erpnext/hub_node/doctype/hub_category/hub_category.json new file mode 100644 index 00000000000..4f8d66ace03 --- /dev/null +++ b/erpnext/hub_node/doctype/hub_category/hub_category.json @@ -0,0 +1,275 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "field:hub_category_name", + "beta": 0, + "creation": "2017-08-22 11:31:10.410322", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "hub_category_name", + "fieldtype": "Data", + "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": "Category Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "parent_hub_category", + "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": "Parent Category", + "length": 0, + "no_copy": 0, + "options": "Hub Category", + "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": "is_group", + "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 Group", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "description", + "fieldtype": "Text Editor", + "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": "Description", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "lft", + "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": "Left", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "rgt", + "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": "Right", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "old_parent", + "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": "Old Parent", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-09-03 22:04:22.958831", + "modified_by": "Administrator", + "module": "Hub Node", + "name": "Hub Category", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "hub_category_name", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/hub_node/doctype/hub_category/hub_category.py b/erpnext/hub_node/doctype/hub_category/hub_category.py new file mode 100644 index 00000000000..5d19082324f --- /dev/null +++ b/erpnext/hub_node/doctype/hub_category/hub_category.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils.nestedset import NestedSet +from frappe.model.document import Document + +class HubCategory(NestedSet): + pass diff --git a/erpnext/hub_node/doctype/hub_category/hub_category_tree.js b/erpnext/hub_node/doctype/hub_category/hub_category_tree.js new file mode 100644 index 00000000000..d0309e3d983 --- /dev/null +++ b/erpnext/hub_node/doctype/hub_category/hub_category_tree.js @@ -0,0 +1,4 @@ +frappe.treeview_settings["Hub Category"] = { + title: __("Hub Category"), + breadcrumb: "Hub" +} \ No newline at end of file diff --git a/erpnext/hub_node/doctype/hub_category/test_hub_category.js b/erpnext/hub_node/doctype/hub_category/test_hub_category.js new file mode 100644 index 00000000000..73c06d5a92a --- /dev/null +++ b/erpnext/hub_node/doctype/hub_category/test_hub_category.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Hub Category", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Hub Category + () => frappe.tests.make('Hub Category', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/hub_node/doctype/hub_category/test_hub_category.py b/erpnext/hub_node/doctype/hub_category/test_hub_category.py new file mode 100644 index 00000000000..7df20889a72 --- /dev/null +++ b/erpnext/hub_node/doctype/hub_category/test_hub_category.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestHubCategory(unittest.TestCase): + pass diff --git a/erpnext/hub_node/doctype/hub_settings/hub_settings.js b/erpnext/hub_node/doctype/hub_settings/hub_settings.js index 95b6d62fd3a..ce0f8bc3520 100644 --- a/erpnext/hub_node/doctype/hub_settings/hub_settings.js +++ b/erpnext/hub_node/doctype/hub_settings/hub_settings.js @@ -1,17 +1,87 @@ -frappe.ui.form.on("Hub Settings", "onload", function(frm) { - if(!frm.doc.seller_country) { - frm.set_value("seller_country", frappe.defaults.get_default("Country")); - } - if(!frm.doc.seller_name) { - frm.set_value("seller_name", frappe.defaults.get_default("Company")); - } -}); +frappe.ui.form.on("Hub Settings", { + refresh: function(frm) { + frm.add_custom_button(__('Logs'), + () => frappe.set_route('List', 'Data Migration Run', { + data_migration_plan: 'Hub Sync' + })); -frappe.ui.form.on("Hub Settings", "refresh", function(frm) { - // make mandatory if published - frm.toggle_reqd(["seller_name", "seller_email", "seller_country"], frm.doc.publish); -}); + frm.trigger("enabled"); + if (frm.doc.enabled) { + frm.add_custom_button(__('View Hub'), + () => frappe.set_route('hub')); + frm.add_custom_button(__('Sync'), + () => frm.call('sync')); + } + }, + onload: function(frm) { + if(!frm.doc.country) { + frm.set_value("country", frappe.defaults.get_default("Country")); + } + if(!frm.doc.company) { + frm.set_value("company", frappe.defaults.get_default("Company")); + } + }, + onload_post_render: function(frm) { + if(frm.get_field("unregister_from_hub").$input) + frm.get_field("unregister_from_hub").$input.addClass("btn-danger"); + }, + on_update: function(frm) { + }, + enabled: function(frm) { + if(!frm.doc.enabled) { + frm.trigger("set_enable_hub_primary_button"); + } else { + frm.page.set_primary_action(__("Save Settings"), () => { + frm.save(); + }); + } + }, -frappe.ui.form.on("Hub Settings", "publish", function(frm) { - frm.trigger("refresh"); + hub_user_email: function(frm) { + if(frm.doc.hub_user_email){ + frm.set_value("hub_user_name", frappe.user.full_name(frm.doc.hub_user_email)); + } + }, + + set_enable_hub_primary_button: (frm) => { + frm.page.set_primary_action(__("Enable Hub"), () => { + if(frappe.session.user === "Administrator") { + frappe.msgprint("Please login as another user.") + } else { + frappe.verify_password(() => { + this.frm.call({ + doc: this.frm.doc, + method: "register", + args: {}, + freeze: true, + callback: function(r) {}, + onerror: function() { + frappe.msgprint(__("Wrong Password")); + frm.set_value("enabled", 0); + } + }); + } ); + } + }); + }, + + // update_hub: (frm) => { + // this.frm.call({ + // doc: this.frm.doc, + // method: "update_hub", + // args: {}, + // freeze: true, + // callback: function(r) { }, + // onerror: function() { } + // }); + // }, + + unregister_from_hub: (frm) => { + frappe.verify_password(() => { + var d = frappe.confirm(__('Are you sure you want to unregister?'), () => { + frm.call('unregister'); + }, () => {}, __('Confirm Action')); + d.get_primary_btn().addClass("btn-danger"); + }); + }, }); diff --git a/erpnext/hub_node/doctype/hub_settings/hub_settings.json b/erpnext/hub_node/doctype/hub_settings/hub_settings.json index 30cb81614cc..b96d6b36434 100644 --- a/erpnext/hub_node/doctype/hub_settings/hub_settings.json +++ b/erpnext/hub_node/doctype/hub_settings/hub_settings.json @@ -1,29 +1,41 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 0, + "beta": 1, "creation": "2015-02-18 00:59:34.560476", "custom": 0, + "description": "", "docstatus": 0, "doctype": "DocType", - "document_type": "System", + "document_type": "", + "editable_grid": 0, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "publish", + "columns": 0, + "fieldname": "enabled", "fieldtype": "Check", - "hidden": 0, + "hidden": 1, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, - "label": "Publish Items to Hub", + "in_standard_filter": 0, + "label": "Enabled", + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -31,43 +43,29 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "depends_on": "publish", - "fieldname": "section_break_2", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "publish_pricing", + "columns": 0, + "fieldname": "suspended", "fieldtype": "Check", - "hidden": 0, + "hidden": 1, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, - "label": "Publish Pricing", + "in_standard_filter": 0, + "label": "Suspended", + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -75,132 +73,124 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "publish_availability", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Publish Availability", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "column_break_5", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "sync_now", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Sync Now", - "no_copy": 0, - "options": "sync", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "depends_on": "publish", - "fieldname": "section_break_6", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "seller_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Seller Name", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "seller_country", + "columns": 0, + "fieldname": "user", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, - "label": "Seller Country", + "in_standard_filter": 0, + "label": "User", + "length": 0, + "no_copy": 0, + "options": "User", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "eval:(!doc.enabled)", + "columns": 0, + "depends_on": "", + "fieldname": "seller_profile_section", + "fieldtype": "Section 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": "Company and Seller Profile", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "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": "country", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Country", + "length": 0, "no_copy": 0, "options": "Country", "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, @@ -208,131 +198,29 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "seller_email", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Seller Email", - "no_copy": 0, - "options": "Email", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "column_break_10", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "seller_city", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Seller City", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "seller_website", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Seller Website", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "depends_on": "publish", - "fieldname": "section_break_13", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, + "columns": 0, "fieldname": "seller_description", "fieldtype": "Text Editor", "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, - "label": "Seller Description", + "in_standard_filter": 0, + "label": "Description", + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -340,21 +228,30 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "name_token", - "fieldtype": "Data", - "hidden": 1, + "columns": 0, + "depends_on": "enabled", + "fieldname": "publish_section", + "fieldtype": "Section Break", + "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, - "label": "Name Token", + "in_standard_filter": 0, + "label": "Publish", + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, - "read_only": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -362,21 +259,216 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "access_token", - "fieldtype": "Data", - "hidden": 1, + "columns": 0, + "fieldname": "publish", + "fieldtype": "Check", + "hidden": 0, "ignore_user_permissions": 0, + "ignore_xss_filter": 0, "in_filter": 0, + "in_global_search": 0, "in_list_view": 0, - "label": "Access Token", + "in_standard_filter": 0, + "label": "Publish Items to Hub", + "length": 0, "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "publish", + "fieldname": "publish_pricing", + "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": "Publish Pricing", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:(doc.publish && doc.publish_pricing)", + "fieldname": "selling_price_list", + "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": "Selling Price List", + "length": 0, + "no_copy": 0, + "options": "Price List", + "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, + "depends_on": "publish", + "fieldname": "publish_availability", + "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": "Publish Availability", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "publish", + "fieldname": "last_sync_datetime", + "fieldtype": "Datetime", + "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": "Last Sync On", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": "", + "columns": 0, + "depends_on": "enabled", + "fieldname": "unregister_section", + "fieldtype": "Section 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": "Unregister", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "unregister_from_hub", + "fieldtype": "Button", + "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": "Unregister from Hub", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, @@ -384,15 +476,18 @@ "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, + "idx": 0, + "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 1, "istable": 0, - "modified": "2015-02-18 08:14:46.140473", - "modified_by": "Administrator", + "max_attachments": 0, + "modified": "2017-09-21 12:13:50.841646", + "modified_by": "manas@erpnext.com", "module": "Hub Node", "name": "Hub Settings", "name_case": "", @@ -419,8 +514,12 @@ "write": 1 } ], + "quick_entry": 0, "read_only": 0, "read_only_onload": 0, + "show_name_in_global_search": 0, "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/hub_node/doctype/hub_settings/hub_settings.py b/erpnext/hub_node/doctype/hub_settings/hub_settings.py index 35f1f67114a..50b8e014619 100644 --- a/erpnext/hub_node/doctype/hub_settings/hub_settings.py +++ b/erpnext/hub_node/doctype/hub_settings/hub_settings.py @@ -3,94 +3,103 @@ from __future__ import unicode_literals import frappe, requests, json -from frappe.model.document import Document -from frappe.utils import cint, expand_relative_urls -from frappe import _ +from frappe.model.document import Document +from frappe.utils import add_years, now, get_datetime, get_datetime_str +from frappe import _ +from erpnext.utilities.product import get_price, get_qty_in_stock +from six import string_types + +# hub_url = "http://erpnext.hub:8000" +hub_url = "https://hub.erpnext.org" +# hub_url = "http://192.168.29.145:3000" + +class HubSetupError(frappe.ValidationError): pass class HubSettings(Document): - hub_url = "http://localhost:8001" - def validate(self): - if cint(self.publish): - if not self.name_token: - self.register() - else: - self.update_seller_details() - self.publish_selling_items() - else: - if self.name_token: - self.unpublish() - def publish_selling_items(self): - """Set `publish_in_hub`=1 for all Sales Items""" - for item in frappe.get_all("Item", fields=["name"], - filters={ "publish_in_hub": "0"}): - frappe.db.set_value("Item", item.name, "publish_in_hub", 1) + def validate(self): + if self.publish_pricing and not self.selling_price_list: + frappe.throw(_("Please select a Price List to publish pricing")) + + def get_hub_url(self): + return hub_url + + def sync(self): + """Create and execute Data Migration Run for Hub Sync plan""" + frappe.has_permission('Hub Settings', throw=True) + + doc = frappe.get_doc({ + 'doctype': 'Data Migration Run', + 'data_migration_plan': 'Hub Sync', + 'data_migration_connector': 'Hub Connector' + }).insert() + + doc.run() def register(self): - """Register at hub.erpnext.com, save `name_token` and `access_token`""" - response = requests.post(self.hub_url + "/api/method/hub.hub.api.register", data=self.get_args()) - response.raise_for_status() - response = response.json() - self.name_token = response.get("message").get("name") - self.access_token = response.get("message").get("access_token") - - def unpublish(self): - """Unpublish from hub.erpnext.com""" - response = requests.post(self.hub_url + "/api/method/hub.hub.api.unpublish", data={ - "access_token": self.access_token - }) - response.raise_for_status() - - def update_seller_details(self): - """Update details at hub.erpnext.com""" - args = self.get_args() - args["published"] = 1 - response = requests.post(self.hub_url + "/api/method/hub.hub.api.update_seller", data={ - "access_token": self.access_token, - "args": json.dumps(args) - }) - response.raise_for_status() - - def get_args(self): - return { - "seller_name": self.seller_name, - "seller_country": self.seller_country, - "seller_city": self.seller_city, - "seller_email": self.seller_email, - "seller_website": self.seller_website, - "seller_description": self.seller_description + """ Create a User on hub.erpnext.org and return username/password """ + data = { + 'email': frappe.session.user } + post_url = hub_url + '/api/method/hub.hub.api.register' - def sync(self, verbose=True): - """Sync items with hub.erpnext.com""" - if not self.publish: - if verbose: - frappe.msgprint(_("Publish to sync items")) + response = requests.post(post_url, data=data) + response.raise_for_status() + message = response.json().get('message') + + if message and message.get('password'): + self.user = frappe.session.user + self.create_hub_connector(message) + self.company = frappe.defaults.get_user_default('company') + self.enabled = 1 + self.save() + + def unregister(self): + """ Disable the User on hub.erpnext.org""" + + hub_connector = frappe.get_doc( + 'Data Migration Connector', 'Hub Connector') + + connection = hub_connector.get_connection() + response_doc = connection.update('User', frappe._dict({'enabled': 0}), hub_connector.username) + + if response_doc['enabled'] == 0: + self.enabled = 0 + self.save() + + def create_hub_connector(self, message): + if frappe.db.exists('Data Migration Connector', 'Hub Connector'): + hub_connector = frappe.get_doc('Data Migration Connector', 'Hub Connector') + hub_connector.username = message['email'] + hub_connector.password = message['password'] + hub_connector.save() return - items = frappe.db.get_all("Item", - fields=["name", "item_name", "description", "image", "item_group"], - filters={"publish_in_hub": 1, "synced_with_hub": 0}) + frappe.get_doc({ + 'doctype': 'Data Migration Connector', + 'connector_type': 'Frappe', + 'connector_name': 'Hub Connector', + 'hostname': hub_url, + 'username': message['email'], + 'password': message['password'] + }).insert() - for item in items: - item.item_code = item.name - if item.image: - item.image = expand_relative_urls(item.image) +def reset_hub_publishing_settings(last_sync_datetime = ""): + doc = frappe.get_doc("Hub Settings", "Hub Settings") + doc.reset_publishing_settings(last_sync_datetime) + doc.in_callback = 1 + doc.save() - item_list = frappe.db.sql_list("select name from tabItem where publish_in_hub=1") +def reset_hub_settings(last_sync_datetime = ""): + doc = frappe.get_doc("Hub Settings", "Hub Settings") + doc.reset_publishing_settings(last_sync_datetime) + doc.reset_enable() + doc.in_callback = 1 + doc.save() + frappe.msgprint(_("Successfully unregistered.")) - if items: - response = requests.post(self.hub_url + "/api/method/hub.hub.api.sync", data={ - "access_token": self.access_token, - "items": json.dumps(items), - "item_list": json.dumps(item_list) - }) - response.raise_for_status() - for item in items: - frappe.db.set_value("Item", item.name, "synced_with_hub", 1) - if verbose: - frappe.msgprint(_("{0} Items synced".format(len(items)))) - else: - if verbose: - frappe.msgprint(_("Items already synced")) +@frappe.whitelist() +def sync(): + hub_settings = frappe.get_doc('Hub Settings') + hub_settings.sync() \ No newline at end of file diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.js b/erpnext/hub_node/doctype/hub_settings/test_hub_settings.js similarity index 72% rename from erpnext/buying/doctype/purchase_order/test_purchase_order.js rename to erpnext/hub_node/doctype/hub_settings/test_hub_settings.js index e9db270b4fd..546ce1504cc 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.js +++ b/erpnext/hub_node/doctype/hub_settings/test_hub_settings.js @@ -2,14 +2,14 @@ // rename this file from _test_[name] to test_[name] to activate // and remove above this line -QUnit.test("test: Purchase Order", function (assert) { +QUnit.test("test: Hub Settings", function (assert) { let done = assert.async(); // number of asserts assert.expect(1); - frappe.run_serially('Purchase Order', [ - // insert a new Purchase Order + frappe.run_serially('Hub Settings', [ + // insert a new Hub Settings () => frappe.tests.make([ // values to be set {key: 'value'} diff --git a/erpnext/hub_node/doctype/hub_settings/test_hub_settings.py b/erpnext/hub_node/doctype/hub_settings/test_hub_settings.py new file mode 100644 index 00000000000..1299adc17eb --- /dev/null +++ b/erpnext/hub_node/doctype/hub_settings/test_hub_settings.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestHubSettings(unittest.TestCase): + pass diff --git a/erpnext/hub_node/page/hub/hub.js b/erpnext/hub_node/page/hub/hub.js index ad09b9d12a3..b065f0a197e 100644 --- a/erpnext/hub_node/page/hub/hub.js +++ b/erpnext/hub_node/page/hub/hub.js @@ -1,90 +1,872 @@ +/* globals Hub, HubList */ + +frappe.provide('erpnext.hub'); + frappe.pages['hub'].on_page_load = function(wrapper) { - var page = frappe.ui.make_app_page({ + const page = frappe.ui.make_app_page({ parent: wrapper, title: 'Hub', - single_column: true + single_col: false }); - frappe.hub = new frappe.Hub({page:page}); + wrapper.hub_page = new erpnext.hub.Hub({ page }); +}; +frappe.pages['hub'].on_page_show = function(wrapper) { + const hub_page = wrapper.hub_page; + const [hub, type, id] = frappe.get_route(); + + if (!(hub || type || id)) { + hub_page.go_to_home_page(); + return; + } + + if (type === "Products") { + hub_page.go_to_item_page(id); + } else if (type === "Company") { + hub_page.go_to_company_page(id); + } } -frappe.pages['hub'].on_page_show = function() { - frappe.hub.refresh(); -} +erpnext.hub.Hub = class Hub { + constructor({ page }) { + this.page = page; + frappe.require('/assets/erpnext/css/hub.css', () => { + this.setup(); + }); + } -frappe.Hub = Class.extend({ - init: function(args) { - $.extend(this, args); - this.render(); - }, - refresh: function() { - if(this.hub && this.hub.publish && !this.hub_list) { - this.setup_list(); - } - }, - render: function() { - this.page.main.empty(); - var me = this; - frappe.model.with_doc("Hub Settings", "Hub Settings", function() { - me.hub = locals["Hub Settings"]["Hub Settings"]; - if(!me.hub.publish) { - $(frappe.render_template("register_in_hub", {})).appendTo(me.page.main); + setup() { + this.setup_header(); + this.company_cache = {}; + this.item_cache = {}; + this.filters = {}; + this.order_by = ''; + + this.$hub_main_section = + $(`
`).appendTo(this.page.body); + this.bind_events(); + this.refresh(); + } + + refresh() { + this.$hub_main_section.empty(); + this.page.page_form.hide(); + + const $layout_main = this.page.wrapper.find('.layout-main'); + const $page_head = this.page.wrapper.find('.page-head'); + + frappe.model.with_doc('Hub Settings', 'Hub Settings', () => { + this.hub_settings = frappe.get_doc('Hub Settings'); + + if(this.hub_settings.enabled == 0) { + let $empty_state = this.page.get_empty_state( + __("Register for Hub"), + __(`Let other ERPNext users discover your products + and automate workflow with Supplier from within ERPNext.`), + __("Register") + ); + + $page_head.hide(); + $layout_main + .find('.layout-side-section, .layout-main-section-wrapper') + .hide(); + $layout_main.append($empty_state); + + $empty_state.find('.btn-primary').on('click', () => { + this.register_for_hub(); + }); } else { - me.setup_list(); + $page_head.show(); + $layout_main.find('.page-card-container').remove(); + $layout_main.find('.layout-side-section, .layout-main-section-wrapper').show(); + this.setup_live_state(); } }); - }, - setup_list: function() { - var me = this; - $(frappe.render_template("hub_body", {})).appendTo(this.page.main); - this.hub_list = this.page.main.find(".hub-list"); - this.search = this.page.main.find("input").on("keypress", function(e) { - if(e.which===13) { - me.reset(); - } + } + + register_for_hub() { + if (frappe.session.user.includes('Administrator')) { + frappe.throw(__('Please login as another user.')) + } + frappe.verify_password(() => { + frappe.call({ + method: 'erpnext.hub_node.enable_hub', + callback: (r) => { + if(r.message.enabled == 1) { + Object.assign(this.hub_settings, r.message); + this.refresh(); + this.prompt_for_item_sync(); + } + } + }); }); - this.loading = this.page.main.find(".loading"); - this.done = this.page.main.find(".done"); - this.more = this.page.main.find(".more") - this.more.find(".btn").on("click", function() { me.next_page() }); - this.reset(); - }, - reset: function() { - this.hub_list.empty(); - this.start = 0; - this.page_length = 20; - this.next_page(); - }, - next_page: function() { - var me = this; - this.loading.toggleClass("hide", false); + } + + prompt_for_item_sync() { frappe.call({ - method: "erpnext.hub_node.get_items", + method: 'frappe.client.get_list', args: { - text: this.get_text(), - start: this.start, - limit: this.page_length + doctype: 'Data Migration Run', + filters: { + 'data_migration_plan': 'Hub Sync' + }, + limit_page_length: 1 }, callback: function(r) { - me.loading.toggleClass("hide", true); - if(!r.message) - r.message = []; - me.start += r.message.length; - $(frappe.render_template("hub_list", {items: r.message})).appendTo(me.hub_list); - if(r.message.length && r.message.length===me.page_length) { - // more - me.more.removeClass("hide"); - me.done.addClass("hide"); - } else { - // done - me.more.addClass("hide"); - me.done.removeClass("hide"); + if (!r) { + frappe.confirm(__('Do you want to publish your Items to Hub ?'), () => { + this.sync_items_to_hub(); + }); } } + }) + } + + setup_header() { + this.page.page_title = this.page.wrapper.find('.page-title'); + this.tag_line = $(` +
+ + ${__('Product listing and discovery for ERPNext users')} + +
`) + .appendTo(this.page.page_title); + + this.bind_title(); + } + + setup_live_state() { + if(!this.$search) { + this.setup_filters(); + } + this.page.page_form.show(); + this.setup_menu(); + this.setup_sidebar(); + this.render_body(); + this.setup_lists(); + } + + setup_filters() { + + // frappe.call({ + // method: 'erpnext.hub_node.get_categories' + // }).then((r) => { + // if (r.message) { + // const categories = r.message; + // console.log("categories", categories); + // categories + // .map(c => c.hub_category_name) + // .map(c => this.sidebar.add_item({ + // label: c, + // on_click: () => { + // this.home_item_list && + // this.home_item_list.refresh({ + // text: '', + // start: 0, + // limit: 20, + // category: c && c !== 'All Categories' ? c : undefined + // }); + // } + // }, __('Hub Category'))); + + + // } + // }); + + // this.category_select = this.page.add_select(__('Category'), + // [ + // {label: __('Sort by Price ...'), value: '' }, + // {label: __('High to Low'), value: 'price desc' }, + // {label: __('Low to High'), value: 'price' }, + // ] + // ); + + this.price_sort_select = this.page.add_select(__('Sort by Price'), + [ + {label: __('Sort by Price ...'), value: '' }, + {label: __('High to Low'), value: 'price desc' }, + {label: __('Low to High'), value: 'price' }, + ] + ); + + this.criteria_select = this.page.add_select(__('Sort by Criteria'), + [ + {label: __('Most Popular'), value: 'request_count' }, + {label: __('Newest'), value: 'creation' }, + ] + ); + + this.price_sort_select.on('change', () => { + this.refresh_item_only_page(); }); - }, - get_text: function() { - return this.search.val(); - }, -}) + + this.criteria_select.on('change', () => { + this.refresh_item_only_page(); + }); + + this.setup_hub_category_filter(); + this.setup_search(); + } + + bind_events() { + const me = this; + this.$hub_main_section + .on('click', '.company-link a', function(e) { + e.preventDefault(); + const company_name = $(this).attr('data-company-name'); + frappe.set_route('hub', 'Company', company_name); + }) + .on('click', '.breadcrumb li', function(e) { + e.preventDefault(); + const $li = $(this); + if ($li.attr('data-route') === 'Home') { + me.go_to_home_page(); + } + }); + } + + update_filters() { + let price_sort = $(this.price_sort_select).val() || ''; + let criteria = $(this.criteria_select).val() || ''; + + let order_by_params = []; + let query_string = ''; + if(criteria) { + order_by_params.push(criteria); + // query_string += 'sort_by=' + criteria + } + if(price_sort) order_by_params.push(price_sort); + this.order_by = order_by_params.join(","); + // return query_string; + } + + reset_filters() { + this.order_by = ''; + $(this.category_select).val(''); + $(this.price_sort_select).val(''); + $(this.criteria_select).val('Most Popular'); + } + + refresh_item_only_page() { + this.reset_search(); + this.update_filters(); + this.go_to_items_only_page( + ['hub', 'Products'], + '', 'product-list' + ); + } + + bind_title() { + this.page.page_title.find('.title-text').on('click', () => { + this.go_to_home_page(); + }); + } + + render_body() { + this.$home_page = $(` +
+ +
+
+
+
+ `).appendTo(this.$hub_main_section); + + this.$banner = this.$hub_main_section.find('.banner'); + this.$listing_body = this.$hub_main_section.find('.listing-body'); + this.$main_list_section = this.$hub_main_section.find('.main-list-section'); + this.$side_list_section = this.$hub_main_section.find('.side-list-section'); + } + + setup_lists() { + this.home_item_list = new erpnext.hub.HubList({ + parent: this.$main_list_section, + title: 'New', + page_length: 20, + list_css_class: 'home-product-list', + method: 'erpnext.hub_node.get_items', + // order_by: 'request_count', + filters: {text: '', country: this.country}, // filters at the time of creation + on_item_click: (item_code) => { + frappe.set_route('hub', 'Products', item_code); + } + }); + + this.home_item_list.setup(); + } + + setup_hub_category_filter() { + const me = this; + + this.hub_category_field = this.page.add_field({ + fieldtype: 'Autocomplete', + label: 'Hub Category', + change() { + let value = this.get_value(); + let title = value; + if (value === 'All Categories') { + // show all items + value = null; + } + + me.home_item_list.title = title; + me.home_item_list.refresh({ + text: '', + start: 0, + limit: 20, + category: value + }); + } + }); + + frappe.call('erpnext.hub_node.get_categories') + .then((r) => { + if (r.message) { + const categories = r.message; + + this.hub_category_field.set_data( + categories.map(c => c.hub_category_name) + ); + } + }); + } + + setup_search() { + this.$search = this.page.add_data(__('Search')); + this.$search.on('keypress', (e) => { + if(e.which === 13) { + var search_term = ($(this.$search).val() || '').toLowerCase(); + this.go_to_items_only_page( + ['hub', 'search', search_term], + 'Search results for \'' + search_term + '\'', + 'search-product-list', + {text: search_term} + ); + } + }); + } + + go_to_items_only_page(route, title, class_name, filters = {text: ''}, by_item_codes=0) { + frappe.set_route(route); + this.$hub_main_section.empty(); + this.filtered_item_list = new erpnext.hub.HubList({ + parent: this.$hub_main_section, + title: title, + page_length: 20, + list_css_class: class_name, + method: 'erpnext.hub_node.get_items', + order_by: this.order_by, + filters: filters, + by_item_codes: by_item_codes + }); + this.filtered_item_list.on_item_click = (item_code) => { + frappe.set_route('hub', 'Products', item_code); + } + this.filtered_item_list.setup(); + } + + go_to_item_page(item_code) { + if(this.item_cache) { + let item = this.item_cache[item_code]; + if(item) { + this.render_item_page(item); + return; + } + } else { + this.item_cache = {}; + } + frappe.call({ + args:{ + hub_sync_id: item_code + }, + method: "erpnext.hub_node.get_item_details", + callback: (r) => { + let item = r.message; + this.item_cache[item_code] = item; + this.render_item_page(item); + } + }); + } + + render_item_page(item) { + this.$hub_main_section.empty(); + + + let $item_page = + $(this.get_item_page(item)) + .appendTo(this.$hub_main_section); + + let $company_items = $item_page.find('.company-items'); + + let company_item_list = new erpnext.hub.HubList({ + parent: $company_items, + title: 'More by ' + item.company_name, + page_length: 5, + list_css_class: 'company-item-list', + method: 'erpnext.hub_node.get_items', + // order_by: 'request_count', + filters: {text: '', company_name: item.company_name, country: this.country}, + paginated: 0, + img_size: 150 + }); + + company_item_list.on_item_click = (item_code) => { + frappe.set_route('hub', 'Products', item_code); + } + company_item_list.setup(); + + $item_page.find('.rfq-btn') + .click((e) => { + const $btn = $(e.target); + + this.show_rfq_modal(item) + .then(values => { + item.item_code = values.item_code; + delete values.item_code; + + const supplier = values; + return [item, supplier]; + }) + .then(([item, supplier]) => { + return this.make_rfq(item, supplier, $btn); + }) + .then(r => { + console.log(r); + if (r.message && r.message.rfq) { + $btn.addClass('disabled').html(` ${__('Quote Requested')}`); + } else { + throw r; + } + }) + .catch((e) => { + console.log(e); //eslint-disable-line + }); + }); + } + + show_rfq_modal(item) { + return new Promise(res => { + let fields = [ + { label: __('Item Code'), fieldtype: 'Data', fieldname: 'item_code', default: item.item_code }, + { fieldtype: 'Column Break' }, + { label: __('Item Group'), fieldtype: 'Link', fieldname: 'item_group', default: item.item_group }, + { label: __('Supplier Details'), fieldtype: 'Section Break' }, + { label: __('Supplier Name'), fieldtype: 'Data', fieldname: 'supplier_name', default: item.company_name }, + { label: __('Supplier Email'), fieldtype: 'Data', fieldname: 'supplier_email', default: item.seller }, + { fieldtype: 'Column Break' }, + { label: __('Supplier Type'), fieldname: 'supplier_type', + fieldtype: 'Link', options: 'Supplier Type' } + ]; + fields = fields.map(f => { f.reqd = 1; return f; }); + + const d = new frappe.ui.Dialog({ + title: __('Request for Quotation'), + fields: fields, + primary_action_label: __('Send'), + primary_action: (values) => { + res(values); + d.hide(); + } + }); + + d.show(); + }); + } + + get_company_details(company_id) { + this.company_cache = this.company_cache || {}; + + return new Promise(resolve => { + // get from cache if exists + let company_details = this.company_cache[company_id]; + if(company_details) { + resolve(company_details); + return; + } + frappe.call({ + method: 'erpnext.hub_node.get_company_details', + args: {hub_sync_id: company_id} + }).then((r) => { + if (r.message) { + const company_details = r.message; + this.company_cache[company_id] = company_details; + resolve(company_details) + } + }); + }) + } + + go_to_company_page(company_id) { + this.get_company_details(company_id) + .then(this.show_company_page.bind(this)); + } + + show_company_page(company_details) { + this.$hub_main_section.empty(); + + let $company_page = + $(this.get_company_page(company_details)) + .appendTo(this.$hub_main_section); + + let $company_items = $company_page.find('.company-items'); + + let company_item_list = new erpnext.hub.HubList({ + parent: $company_items, + title: 'More by ' + company_details.company_name, + page_length: 5, + list_css_class: 'company-item-list', + method: 'erpnext.hub_node.get_items', + // order_by: 'request_count', + filters: {text: '', company: company_details.company_name, country: this.country}, + paginated: 0, + img_size: 150 + }); + + company_item_list.on_item_click = (item_code) => { + frappe.set_route('hub', 'Products', item_code); + } + company_item_list.setup(); + } + + get_item_page(item) { + return ` +
+
+
+ ${ this.home_item_list.get_item_image(item) } +
+
+ +
+

${ item.item_name }

+
+
+ ${ item.company_name } +
+
+ Products +
+
+ ${ item.description ? item.description : "" } +
+
+ ${ item.formatted_price ? item.formatted_price : '' } +
+ +
+ +
+
+
+ +
+
+ `; + } + + get_company_page(company_details) { + return ` +
+
+
+ +
+

${ company_details.company_name }

+
+
+ ${ company_details.country } +
+
+ ${ company_details.site_name } +
+
+ +
+
+
+ +
+
+ `; + } + + get_breadcrumb(name, type) { + return ` + + `; + } + + go_to_home_page() { + frappe.set_route('hub'); + this.reset_filters(); + this.refresh(); + } + + setup_menu() { + if (this.menu_setup) return; + + this.page.add_menu_item(__('Hub Settings'), + () => frappe.set_route('Form', 'Hub Settings')); + this.page.add_menu_item(__('Refresh'), () => this.refresh()); + this.page.add_menu_item(__('Sync'), () => this.sync_items_to_hub()); + + this.menu_setup = true; + } + + sync_items_to_hub() { + frappe.call('erpnext.hub_node.doctype.hub_settings.hub_settings.sync') + } + + setup_sidebar() { + var me = this; + this.sidebar = new frappe.ui.Sidebar({ + wrapper: this.page.wrapper.find('.layout-side-section'), + css_class: 'hub-sidebar' + }); + + this.add_account_to_sidebar(); + } + + add_account_to_sidebar() { + this.sidebar.add_item({ + label: this.hub_settings.company, + on_click: () => frappe.set_route('Form', 'Company', this.hub_settings.company) + }, __("Account")); + + this.sidebar.add_item({ + label: __("My Orders"), + on_click: () => frappe.set_route('List', 'Request for Quotation') + }, __("Account")); + } + + get_search_term() { + return this.$search.val(); + } + + reset_search() { + this.$search.val(''); + } + + make_rfq(item, supplier, btn) { + console.log(supplier); + return new Promise((resolve, reject) => { + frappe.call({ + method: 'erpnext.hub_node.make_rfq_and_send_opportunity', + args: { item, supplier }, + callback: resolve, + btn, + }).fail(reject); + }); + } + + go_to_seen_items() { + this.go_to_items_only_page( + ['hub', 'Requested Products'], + __('Requested Products'), + 'requested-product-list', + {}, 1 + ); + } +} + +erpnext.hub.HubList = class HubList { + constructor({ + parent = null, + title = 'Products', + page_length = 20, + list_css_class = '', + method = 'erpnext.hub_node.get_items', + filters = {text: ''}, + order_by = '', + by_item_codes = 0, + paginated = 1, + on_item_click = null, + img_size = 200 + }) { + this.parent = parent; + this.title = title; + this.page_length = page_length; + this.list_css_class = list_css_class; + this.method = method; + this.filters = filters; + this.order_by = order_by; + this.by_item_codes = by_item_codes; + this.paginated = paginated; + + this.on_item_click = on_item_click; + this.img_size = img_size; + } + + // to be called on demand + setup() { + this.container = $(` +
+
+

${this.title}

+
+
+
+
+

${__('Loading...')}

+
+
+

${__('No more results')}

+
+
+
+
+
+
`) + .appendTo(this.parent); + + this.$item_list_title = this.container.find('.item-list-header h3'); + this.$list = this.container.find('.item-list'); + this.$loading = this.container.find('.loading').hide(); + this.$more = this.container.find('.more').hide(); + this.$done = this.container.find('.done'); + + this.$more.on('click', () => { + this.next_page(); + }); + + this.next_page(); + } + + refresh(filters = this.filters) { + this.reset(); + this.set_filters(filters); + this.next_page(); + } + + reset() { + this.$list.empty(); + } + + set_filters(filters) { + this.filters = filters; + } + + next_page() { + this.$item_list_title.html(this.title); + const start = this.$list.find('.hub-item-wrapper').length; + this.$loading.show(); + + // build args + let args = { + start: start, + // query one extra + limit: this.page_length + 1 + }; + Object.assign(args, this.filters); + console.log("filters: ", args); + args.order_by = this.order_by; + args.by_item_codes = this.by_item_codes; + + frappe.call({ + method: this.method, + args: args, + callback: (r) => { + let items = r.message; + console.log("items: ", items); + this.render_items(items); + } + }); + } + + render_items(items) { + if(items) { + // clear any filler divs + this.$list.find('.filler').remove(); + let done = 0; + console.log("items length", items.length); + if(items.length && items.length > this.page_length) { + // remove the extra queried + items.pop(); + } else { + done = 1; + } + items.forEach((item) => { + this.make_item_card(item).appendTo(this.$list); + }); + + const remainder = items.length % 4; + if (remainder > 0) { + // fill with filler divs to make flexbox happy + Array.from(Array(remainder)) + .map(r => $('
').css('width', '200px').appendTo(this.$list)); + } + this.update_list_state(done); + } else { + this.update_list_state(1); + } + } + + update_list_state(done=0) { + this.$loading.hide(); + if(done) { + this.$done.removeClass('hide'); + this.$more.hide(); + } else { + this.$more.show(); + this.$done.addClass('hide'); + } + } + + make_item_card(item) { + let $item_card = $(` + + `); + + $item_card.find(".item-link").click((e) => { + e.preventDefault(); + this.on_item_click && this.on_item_click(item.name); + }); + + return $item_card; + } + + get_item_image(item, size=this.img_size) { + const _size = size + 'px'; + const item_image = item.image ? + `` : + `
${item.item_name[0]}
`; + + return ` +
+ ${item_image} +
`; + } +} diff --git a/erpnext/hub_node/page/hub/hub_body.html b/erpnext/hub_node/page/hub/hub_body.html deleted file mode 100644 index e415f7e6898..00000000000 --- a/erpnext/hub_node/page/hub/hub_body.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
-
- -
-
-
-
- -
-
-

{%= __("Loading...") %}

-
-
-
-
-
-

{%= __("No more results.") %}

-
-
diff --git a/erpnext/hub_node/page/hub/hub_list.html b/erpnext/hub_node/page/hub/hub_list.html deleted file mode 100644 index 036ef2bf2ab..00000000000 --- a/erpnext/hub_node/page/hub/hub_list.html +++ /dev/null @@ -1,16 +0,0 @@ -{% for(var i=0, l=items.length; i < l; i++) { %} -
-
-
-
{%= items[i].item_name %}
-
-
-
{%= items[i].seller_name %}
-
-
-
{%= items[i].seller_country %}
-
-
-

{%= items[i].description %}

-
-{% } %} diff --git a/erpnext/hub_node/page/hub/register_in_hub.html b/erpnext/hub_node/page/hub/register_in_hub.html deleted file mode 100644 index 96b1fb3d05f..00000000000 --- a/erpnext/hub_node/page/hub/register_in_hub.html +++ /dev/null @@ -1,19 +0,0 @@ -
-

{%= __("Register For ERPNext Hub") %}

-
-
-
-
    -
  • Free listing of your products
  • -
  • Let other ERPNext users discover your products
  • -
  • Discover products quickly
  • -
  • Automate workflow with Supplier from within ERPNext (later)
  • -
-
-
-
- -
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json index 2558df35ea1..85a3f7e9b19 100644 --- a/erpnext/manufacturing/doctype/bom/bom.json +++ b/erpnext/manufacturing/doctype/bom/bom.json @@ -322,6 +322,36 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "currency_detail", + "fieldtype": "Section 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": "", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -359,8 +389,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "currency_detail", - "fieldtype": "Section Break", + "fieldname": "column_break_12", + "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -368,7 +398,6 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "", "length": 0, "no_copy": 0, "permlevel": 0, @@ -414,35 +443,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_12", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1322,7 +1322,7 @@ "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, - "collapsible": 1, + "collapsible": 0, "columns": 0, "depends_on": "eval:!doc.__islocal", "fieldname": "section_break0", @@ -1671,7 +1671,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-08-23 14:09:30.492628", + "modified": "2017-10-23 14:56:21.991160", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM", diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index b308e097ea4..b140bf591ec 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -95,8 +95,8 @@ class BOM(WebsiteGenerator): self.validate_bom_currecny(item) ret = self.get_bom_material_detail({ - "item_code": item.item_code, - "item_name": item.item_name, + "item_code": item.item_code, + "item_name": item.item_name, "bom_no": item.bom_no, "stock_qty": item.stock_qty }) @@ -128,7 +128,7 @@ class BOM(WebsiteGenerator): 'uom' : item and args['stock_uom'] or '', 'conversion_factor': 1, 'bom_no' : args['bom_no'], - 'rate' : rate / self.conversion_rate, + 'rate' : rate / self.conversion_rate if self.conversion_rate else rate, 'qty' : args.get("qty") or args.get("stock_qty") or 1, 'stock_qty' : args.get("qty") or args.get("stock_qty") or 1, 'base_rate' : rate @@ -147,22 +147,28 @@ class BOM(WebsiteGenerator): if arg.get('scrap_items'): rate = self.get_valuation_rate(arg) elif arg: - if self.rm_cost_as_per == 'Valuation Rate': - rate = self.get_valuation_rate(arg) - elif self.rm_cost_as_per == 'Last Purchase Rate': - rate = arg['last_purchase_rate'] \ - or frappe.db.get_value("Item", arg['item_code'], "last_purchase_rate") - elif self.rm_cost_as_per == "Price List": - if not self.buying_price_list: - frappe.throw(_("Please select Price List")) - rate = frappe.db.get_value("Item Price", - {"price_list": self.buying_price_list, "item_code": arg["item_code"]}, "price_list_rate") - price_list_currency = frappe.db.get_value("Price List", self.buying_price_list, "currency") - if price_list_currency != self.company_currency(): - rate = flt(rate * self.conversion_rate) - - if arg['bom_no'] and (not rate or self.set_rate_of_sub_assembly_item_based_on_bom): + if arg.get('bom_no') and self.set_rate_of_sub_assembly_item_based_on_bom: rate = self.get_bom_unitcost(arg['bom_no']) + else: + if self.rm_cost_as_per == 'Valuation Rate': + rate = self.get_valuation_rate(arg) + elif self.rm_cost_as_per == 'Last Purchase Rate': + rate = arg.get('last_purchase_rate') \ + or frappe.db.get_value("Item", arg['item_code'], "last_purchase_rate") + elif self.rm_cost_as_per == "Price List": + if not self.buying_price_list: + frappe.throw(_("Please select Price List")) + rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list, + "item_code": arg["item_code"]}, "price_list_rate") + + price_list_currency = frappe.db.get_value("Price List", + self.buying_price_list, "currency") + if price_list_currency != self.company_currency(): + rate = flt(rate * self.conversion_rate) + + if not rate: + frappe.msgprint(_("{0} not found for Item {1}") + .format(self.rm_cost_as_per, arg["item_code"])) return flt(rate) @@ -312,7 +318,7 @@ class BOM(WebsiteGenerator): li.append("{0} on row {1}".format(i.item_code, i.idx)) duplicate_list = '
' + '
'.join(li) - frappe.throw(_("Same item has been entered multiple times. {list}").format(list=duplicate_list)) + frappe.throw(_("Same item has been entered multiple times. {0}").format(duplicate_list)) def check_recursion(self): """ Check whether recursion occurs in any bom""" @@ -346,7 +352,7 @@ class BOM(WebsiteGenerator): count = 0 if not bom_list: bom_list = [] - + if self.name not in bom_list: bom_list.append(self.name) @@ -374,7 +380,7 @@ class BOM(WebsiteGenerator): if d.workstation: if not d.hour_rate: hour_rate = flt(frappe.db.get_value("Workstation", d.workstation, "hour_rate")) - d.hour_rate = hour_rate / flt(self.conversion_rate) + d.hour_rate = hour_rate / flt(self.conversion_rate) if self.conversion_rate else hour_rate if d.hour_rate and d.time_in_mins: d.base_hour_rate = flt(d.hour_rate) * flt(self.conversion_rate) diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py index 91b5070dbd9..e3c61ed5161 100644 --- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py +++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py @@ -30,12 +30,13 @@ class BOMUpdateTool(Document): frappe.throw(_("The selected BOMs are not for the same item")) def update_new_bom(self): - current_bom_unitcost = frappe.db.sql("""select total_cost/quantity - from `tabBOM` where name = %s""", self.current_bom) - current_bom_unitcost = current_bom_unitcost and flt(current_bom_unitcost[0][0]) or 0 + new_bom_unitcost = frappe.db.sql("""select total_cost/quantity + from `tabBOM` where name = %s""", self.new_bom) + new_bom_unitcost = flt(new_bom_unitcost[0][0]) if new_bom_unitcost else 0 + frappe.db.sql("""update `tabBOM Item` set bom_no=%s, rate=%s, amount=stock_qty*%s where bom_no = %s and docstatus < 2""", - (self.new_bom, current_bom_unitcost, current_bom_unitcost, self.current_bom)) + (self.new_bom, new_bom_unitcost, new_bom_unitcost, self.current_bom)) def get_parent_boms(self): return [d[0] for d in frappe.db.sql("""select distinct parent diff --git a/erpnext/manufacturing/doctype/operation/test_operation.js b/erpnext/manufacturing/doctype/operation/test_operation.js index 9fedaac720e..42553ce721f 100644 --- a/erpnext/manufacturing/doctype/operation/test_operation.js +++ b/erpnext/manufacturing/doctype/operation/test_operation.js @@ -1,13 +1,6 @@ QUnit.test("test: operation", function (assert) { assert.expect(2); let done = assert.async(); - let set_op_name = (text) => { - $(`input.input-with-feedback.form-control.bold:visible`).val(`${text}`); - }; - let click_create = () => { - $(`.btn-primary:contains("Create"):visible`).click(); - }; - frappe.run_serially([ // test operation creation () => frappe.set_route("List", "Operation"), @@ -16,15 +9,12 @@ QUnit.test("test: operation", function (assert) { () => { frappe.tests.make( "Operation", [ + {__newname: "Assemble Keyboard"}, {workstation: "Keyboard assembly workstation"} ] ); }, - () => frappe.timeout(4), - () => set_op_name("Assemble Keyboard"), - () => frappe.timeout(0.5), - () => click_create(), - () => frappe.timeout(1), + () => frappe.timeout(3), () => { assert.ok(cur_frm.docname.includes('Assemble Keyboard'), 'Assemble Keyboard created successfully'); @@ -36,29 +26,23 @@ QUnit.test("test: operation", function (assert) { () => { frappe.tests.make( "Operation", [ + {__newname: 'Assemble Screen'}, {workstation: "Screen assembly workstation"} ] ); }, - () => frappe.timeout(4), - () => set_op_name("Assemble Screen"), - () => frappe.timeout(0.5), - () => click_create(), - () => frappe.timeout(1), + () => frappe.timeout(3), // Create a CPU operation () => { frappe.tests.make( "Operation", [ + {__newname: 'Assemble CPU'}, {workstation: "CPU assembly workstation"} ] ); }, - () => frappe.timeout(4), - () => set_op_name("Assemble CPU"), - () => frappe.timeout(0.5), - () => click_create(), - () => frappe.timeout(1), + () => frappe.timeout(3), () => done() ]); diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index 31aedb38f06..89ecbe7ec5b 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -569,7 +569,7 @@ def get_events(start, end, filters=None): where ((ifnull(planned_start_date, '0000-00-00')!= '0000-00-00') \ and (planned_start_date <= %(end)s) \ and ((ifnull(planned_start_date, '0000-00-00')!= '0000-00-00') \ - and planned_end_date >= %(start)s)) {conditions} + and ifnull(planned_end_date, '2199-12-31 00:00:00') >= %(start)s)) {conditions} """.format(conditions=conditions), { "start": start, "end": end @@ -626,4 +626,4 @@ def stop_unstop(production_order, status): frappe.msgprint(_("Production Order has been {0}").format(status)) pro_order.notify_update() - return pro_order.status \ No newline at end of file + return pro_order.status diff --git a/erpnext/manufacturing/doctype/production_order/test_production_order.js b/erpnext/manufacturing/doctype/production_order/test_production_order.js index 7ce67ba4304..32cc3efd97a 100644 --- a/erpnext/manufacturing/doctype/production_order/test_production_order.js +++ b/erpnext/manufacturing/doctype/production_order/test_production_order.js @@ -59,8 +59,6 @@ QUnit.test("test: production order", function (assert) { // Confirm the production order timesheet, save and submit it () => frappe.click_link("TS-00"), () => frappe.timeout(1), - () => frappe.click_button("Save"), - () => frappe.timeout(1), () => frappe.click_button("Submit"), () => frappe.timeout(1), () => frappe.click_button("Yes"), diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py index 815e5044477..3ef7be14946 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -12,10 +12,6 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no from erpnext.manufacturing.doctype.production_order.production_order import get_item_details class ProductionPlanningTool(Document): - def __init__(self, arg1, arg2=None): - super(ProductionPlanningTool, self).__init__(arg1, arg2) - self.item_dict = {} - def clear_table(self, table_name): self.set(table_name, []) @@ -398,6 +394,9 @@ class ProductionPlanningTool(Document): return bom_wise_item_details def make_items_dict(self, item_list): + if not getattr(self, "item_dict", None): + self.item_dict = {} + for i in item_list: self.item_dict.setdefault(i[0], []).append([flt(i[1]), i[2], i[3], i[4], i[5]]) @@ -516,7 +515,8 @@ class ProductionPlanningTool(Document): "transaction_date": nowdate(), "status": "Draft", "company": self.company, - "requested_by": frappe.session.user + "requested_by": frappe.session.user, + "schedule_date": add_days(nowdate(), cint(item_wrapper.lead_time_days)), }) material_request.update({"material_request_type": item_wrapper.default_material_request_type}) diff --git a/erpnext/manufacturing/page/production_analytics/production_analytics.js b/erpnext/manufacturing/page/production_analytics/production_analytics.js index 1fb1ef22ebe..39168b7206e 100644 --- a/erpnext/manufacturing/page/production_analytics/production_analytics.js +++ b/erpnext/manufacturing/page/production_analytics/production_analytics.js @@ -53,7 +53,7 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({ this.show_zero_check() this.setup_chart_check(); - + }, init_filter_values: function() { this._super(); @@ -61,12 +61,13 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({ }, setup_chart: function() { var me = this; - + var chart_data = this.get_chart_data ? this.get_chart_data() : null; - this.chart = new frappe.ui.Chart({ - wrapper: this.chart_area, - data: chart_data + this.chart = new frappe.chart.FrappeChart({ + parent: ".chart", + data: chart_data, + type: 'line' }); }, set_default_values: function() { @@ -95,7 +96,7 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({ var pending = {name:"Pending", "id":"pending-pos", checked:true}; var completed = {name:"Completed", "id":"completed-pos", - checked:true}; + checked:true}; $.each(frappe.report_dump.data["Production Order"], function(i, d) { var dateobj = frappe.datetime.str_to_obj(d.creation); @@ -109,10 +110,10 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({ var planned_start_date = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(d.planned_start_date)); var aend_date = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(d.actual_end_date)); var modified = frappe.datetime.user_to_obj(frappe.datetime.str_to_user(d.modified)); - + if (dateobj <= start_period || dateobj <= end_period) { all_open_orders[col.field] = flt(all_open_orders[col.field]) + 1; - + if(d.status=="Completed") { if(aend_date < start_period || modified < start_period) { completed[col.field] = flt(completed[col.field]) + 1; @@ -140,7 +141,7 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({ }else{ not_started[col.field] = flt(not_started[col.field]) + 1; } - } + } } } }); @@ -151,6 +152,6 @@ erpnext.ProductionAnalytics = frappe.views.GridReportWithPlot.extend({ this.chart_area.toggle(false); } this.data = [all_open_orders, not_started, overdue, pending, completed]; - + } }); diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.html b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.html new file mode 100644 index 00000000000..119a4fc6292 --- /dev/null +++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.html @@ -0,0 +1,27 @@ +

{%= __("BOM Stock Report") %}

+
{%= filters.bom %}
+
{%= filters.warehouse %}
+
+ + + + + + + + + + + + + {% for(var i=0, l=data.length; i + + + + + + + {% } %} + +
{%= __("Item") %}{%= __("Description") %}{%= __("Required Qty") %}{%= __("In Stock Qty") %}{%= __("Enough Parts to Build") %}
{%= data[i][ __("Item")] %}{%= data[i][ __("Description")] %} {%= data[i][ __("Required Qty")] %} {%= data[i][ __("In Stock Qty")] %} {%= data[i][ __("Enough Parts to Build")] %}
\ No newline at end of file diff --git a/erpnext/modules.txt b/erpnext/modules.txt index 6449a4ad5ce..5e9f6c73d19 100644 --- a/erpnext/modules.txt +++ b/erpnext/modules.txt @@ -16,3 +16,4 @@ Maintenance Schools Regional Healthcare +Restaurant diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 1e9d529b302..5f5b46ba40e 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -449,3 +449,10 @@ erpnext.patches.v8_9.delete_gst_doctypes_for_outside_india_accounts erpnext.patches.v8_9.set_default_fields_in_variant_settings erpnext.patches.v8_9.update_billing_gstin_for_indian_account erpnext.patches.v9_0.add_user_to_child_table_in_pos_profile +erpnext.patches.v9_0.set_schedule_date_for_material_request_and_purchase_order +erpnext.patches.v9_0.student_admission_childtable_migrate +erpnext.patches.v9_0.fix_subscription_next_date #2017-10-23 +erpnext.patches.v9_0.add_healthcare_domain +erpnext.patches.v9_0.set_variant_item_description +erpnext.patches.v9_0.set_uoms_in_variant_field +erpnext.patches.v9_0.copy_old_fees_field_data diff --git a/erpnext/patches/v7_0/set_portal_settings.py b/erpnext/patches/v7_0/set_portal_settings.py index ddc86c6d33e..9bae1c54c03 100644 --- a/erpnext/patches/v7_0/set_portal_settings.py +++ b/erpnext/patches/v7_0/set_portal_settings.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals import frappe -from erpnext.setup.setup_wizard import domainify def execute(): frappe.reload_doctype('Role') @@ -19,6 +18,9 @@ def execute(): frappe.get_doc('Portal Settings').sync_menu() if 'schools' in frappe.get_installed_apps(): - domainify.setup_domain('Education') + domain = frappe.get_doc('Domain', 'Education') + domain.setup_domain() else: - domainify.setup_sidebar_items(domainify.get_domain('Manufacturing')) + domain = frappe.get_doc('Domain', 'Manufacturing') + domain.setup_data() + domain.setup_sidebar_items() diff --git a/erpnext/patches/v8_0/disable_instructor_role.py b/erpnext/patches/v8_0/disable_instructor_role.py index 94ebd9cac6b..4ba78d172cb 100644 --- a/erpnext/patches/v8_0/disable_instructor_role.py +++ b/erpnext/patches/v8_0/disable_instructor_role.py @@ -12,6 +12,7 @@ def execute(): domains = frappe.db.sql_list("select domain from tabCompany") if "Education" not in domains: - role = frappe.get_doc("Role", "Instructor") - role.disabled = 1 - role.save(ignore_permissions=True) \ No newline at end of file + if frappe.db.exists("Role", "Instructor"): + role = frappe.get_doc("Role", "Instructor") + role.disabled = 1 + role.save(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v8_0/merge_student_batch_and_student_group.py b/erpnext/patches/v8_0/merge_student_batch_and_student_group.py index aacd97b2d9b..ca71d36d090 100644 --- a/erpnext/patches/v8_0/merge_student_batch_and_student_group.py +++ b/erpnext/patches/v8_0/merge_student_batch_and_student_group.py @@ -9,7 +9,7 @@ from frappe.model.mapper import get_mapped_doc def execute(): # for converting student batch into student group - for doctype in ["Student Group", "Student Group Student", + for doctype in ["Student Group", "Student Group Student", 'Program Enrollment', "Student Group Instructor", "Student Attendance", "Student", "Student Batch Name"]: frappe.reload_doc("schools", "doctype", frappe.scrub(doctype)) diff --git a/erpnext/patches/v8_3/set_restrict_to_domain_for_module_def.py b/erpnext/patches/v8_3/set_restrict_to_domain_for_module_def.py index 2f97ccfe022..6c4c6d5bd8d 100644 --- a/erpnext/patches/v8_3/set_restrict_to_domain_for_module_def.py +++ b/erpnext/patches/v8_3/set_restrict_to_domain_for_module_def.py @@ -4,11 +4,6 @@ from __future__ import unicode_literals import frappe -from erpnext.setup.setup_wizard.domainify import update_module_def_restrict_to_domain - def execute(): """ set the restrict to domain in module def """ - - frappe.reload_doc("core", "doctype", "module_def") - if frappe.db.get_single_value('System Settings', 'setup_complete'): - update_module_def_restrict_to_domain() \ No newline at end of file + pass \ No newline at end of file diff --git a/erpnext/patches/v8_7/make_subscription_from_recurring_data.py b/erpnext/patches/v8_7/make_subscription_from_recurring_data.py index c5d7d7279a9..2932749116f 100644 --- a/erpnext/patches/v8_7/make_subscription_from_recurring_data.py +++ b/erpnext/patches/v8_7/make_subscription_from_recurring_data.py @@ -18,24 +18,33 @@ def execute(): frappe.reload_doc('accounts', 'doctype', 'journal_entry') frappe.reload_doc('accounts', 'doctype', 'payment_entry') - for doctype in ['Sales Order', 'Sales Invoice', - 'Purchase Invoice', 'Purchase Invoice']: - for data in get_data(doctype): - make_subscription(doctype, data) + for doctype in ['Sales Order', 'Sales Invoice', 'Purchase Order', 'Purchase Invoice']: + date_field = "transaction_date" + if doctype in ("Sales Invoice", "Purchase Invoice"): + date_field = "posting_date" -def get_data(doctype): - return frappe.db.sql(""" select name, from_date, end_date, recurring_type,recurring_id, + for data in get_data(doctype, date_field): + make_subscription(doctype, data, date_field) + +def get_data(doctype, date_field): + return frappe.db.sql(""" select name, from_date, end_date, recurring_type, recurring_id, next_date, notify_by_email, notification_email_address, recurring_print_format, - repeat_on_day_of_month, submit_on_creation, docstatus - from `tab{0}` where is_recurring = 1 and next_date >= %s and docstatus < 2 - """.format(doctype), today(), as_dict=1) + repeat_on_day_of_month, submit_on_creation, docstatus, {0} + from `tab{1}` where is_recurring = 1 and next_date >= %s and docstatus < 2 + order by next_date desc + """.format(date_field, doctype), today(), as_dict=1) + +def make_subscription(doctype, data, date_field): + if data.name == data.recurring_id: + start_date = data.get(date_field) + else: + start_date = frappe.db.get_value(doctype, data.recurring_id, date_field) -def make_subscription(doctype, data): doc = frappe.get_doc({ 'doctype': 'Subscription', 'reference_doctype': doctype, - 'reference_document': data.name, - 'start_date': data.from_date, + 'reference_document': data.recurring_id, + 'start_date': start_date, 'end_date': data.end_date, 'frequency': data.recurring_type, 'repeat_on_day': data.repeat_on_day_of_month, diff --git a/erpnext/patches/v8_9/set_print_zero_amount_taxes.py b/erpnext/patches/v8_9/set_print_zero_amount_taxes.py index 621b573744b..3c508eaa097 100644 --- a/erpnext/patches/v8_9/set_print_zero_amount_taxes.py +++ b/erpnext/patches/v8_9/set_print_zero_amount_taxes.py @@ -4,5 +4,6 @@ import frappe from erpnext.setup.install import create_print_zero_amount_taxes_custom_field def execute(): - frappe.reload_doc("printing", "doctype", "print_style") + frappe.reload_doc('printing', 'doctype', 'print_style') + frappe.reload_doc('printing', 'doctype', 'print_settings') create_print_zero_amount_taxes_custom_field() \ No newline at end of file diff --git a/erpnext/patches/v9_0/add_healthcare_domain.py b/erpnext/patches/v9_0/add_healthcare_domain.py new file mode 100644 index 00000000000..45fceb126f7 --- /dev/null +++ b/erpnext/patches/v9_0/add_healthcare_domain.py @@ -0,0 +1,14 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ + +def execute(): + domain = _('Healthcare') + if not frappe.db.exists('Domain', domain): + frappe.get_doc({ + 'doctype': 'Domain', + 'domain': domain + }).insert(ignore_permissions=True) \ No newline at end of file diff --git a/erpnext/patches/v9_0/copy_old_fees_field_data.py b/erpnext/patches/v9_0/copy_old_fees_field_data.py new file mode 100644 index 00000000000..c47137bc91c --- /dev/null +++ b/erpnext/patches/v9_0/copy_old_fees_field_data.py @@ -0,0 +1,12 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doctype('Fees') + if "total_amount" not in frappe.db.get_table_columns("Fees"): + return + + frappe.db.sql("""update tabFees set grand_total=total_amount where grand_total = 0.0""") \ No newline at end of file diff --git a/erpnext/patches/v9_0/fix_subscription_next_date.py b/erpnext/patches/v9_0/fix_subscription_next_date.py new file mode 100644 index 00000000000..07af7129f65 --- /dev/null +++ b/erpnext/patches/v9_0/fix_subscription_next_date.py @@ -0,0 +1,43 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils import getdate +from erpnext.accounts.doctype.subscription.subscription import get_next_schedule_date + +def execute(): + frappe.reload_doctype('Subscription') + + doctypes = ('Purchase Order', 'Sales Order', 'Purchase Invoice', 'Sales Invoice') + for data in frappe.get_all('Subscription', + fields = ["name", "reference_doctype", "reference_document", + "start_date", "frequency", "repeat_on_day"], + filters = {'reference_doctype': ('in', doctypes), 'docstatus': 1}): + + recurring_id = frappe.db.get_value(data.reference_doctype, data.reference_document, "recurring_id") + if recurring_id: + frappe.db.sql("update `tab{0}` set subscription=%s where recurring_id=%s" + .format(data.reference_doctype), (data.name, recurring_id)) + + date_field = 'transaction_date' + if data.reference_doctype in ['Sales Invoice', 'Purchase Invoice']: + date_field = 'posting_date' + + start_date = frappe.db.get_value(data.reference_doctype, data.reference_document, date_field) + + if start_date and getdate(start_date) != getdate(data.start_date): + last_ref_date = frappe.db.sql(""" + select {0} + from `tab{1}` + where subscription=%s and docstatus < 2 + order by creation desc + limit 1 + """.format(date_field, data.reference_doctype), data.name)[0][0] + + next_schedule_date = get_next_schedule_date(last_ref_date, data.frequency, data.repeat_on_day) + + frappe.db.set_value("Subscription", data.name, { + "start_date": start_date, + "next_schedule_date": next_schedule_date + }, None) \ No newline at end of file diff --git a/erpnext/patches/v9_0/set_schedule_date_for_material_request_and_purchase_order.py b/erpnext/patches/v9_0/set_schedule_date_for_material_request_and_purchase_order.py new file mode 100644 index 00000000000..3d012978fab --- /dev/null +++ b/erpnext/patches/v9_0/set_schedule_date_for_material_request_and_purchase_order.py @@ -0,0 +1,24 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for doctype in ("Material Request", "Purchase Order"): + frappe.reload_doctype(doctype) + frappe.reload_doctype(doctype + " Item") + + if not frappe.db.has_column(doctype, "schedule_date"): + continue + + #Update only submitted MR + for record in frappe.get_all(doctype, filters= [["docstatus", "=", 1]], fields=["name"]): + doc = frappe.get_doc(doctype, record) + if doc.items: + if not doc.schedule_date: + schedule_dates = [d.schedule_date for d in doc.items if d.schedule_date] + if len(schedule_dates) > 0: + min_schedule_date = min(schedule_dates) + frappe.db.set_value(doctype, record, + "schedule_date", min_schedule_date, update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v9_0/set_uoms_in_variant_field.py b/erpnext/patches/v9_0/set_uoms_in_variant_field.py new file mode 100644 index 00000000000..9e783d99beb --- /dev/null +++ b/erpnext/patches/v9_0/set_uoms_in_variant_field.py @@ -0,0 +1,14 @@ +from __future__ import unicode_literals +import frappe + + +def execute(): + doc = frappe.get_doc('Item Variant Settings') + variant_field_names = [vf.field_name for vf in doc.fields] + if 'uoms' not in variant_field_names: + doc.append( + 'fields', { + 'field_name': 'uoms' + } + ) + doc.save() diff --git a/erpnext/patches/v9_0/set_variant_item_description.py b/erpnext/patches/v9_0/set_variant_item_description.py new file mode 100644 index 00000000000..c8445715069 --- /dev/null +++ b/erpnext/patches/v9_0/set_variant_item_description.py @@ -0,0 +1,45 @@ +import frappe +from frappe.utils import cstr + +def execute(): + ''' + Issue: + While copying data from template item to variant item, + the system appending description multiple times to the respective variant. + + Purpose: + Check variant description, + if variant have user defined description remove all system appended descriptions + else replace multiple system generated descriptions with single description + + Steps: + 1. Get all variant items + 2. Create system generated variant description + 3. If variant have user defined description, remove all system generated descriptions + 4. If variant description only contains system generated description, + replace multiple descriptions by new description. + ''' + for item in frappe.db.sql(""" select name from tabItem + where ifnull(variant_of, '') != '' """,as_dict=1): + variant = frappe.get_doc("Item", item.name) + temp_variant_description = '\n' + + if variant.attributes: + for d in variant.attributes: + temp_variant_description += "
" + d.attribute + ": " + cstr(d.attribute_value) + "
" + + variant_description = variant.description.replace(temp_variant_description, '').rstrip() + if variant_description: + splitted_desc = variant.description.strip().split(temp_variant_description) + + if len(splitted_desc) > 2: + if splitted_desc[0] == '': + variant_description = temp_variant_description + variant_description + elif splitted_desc[1] == '' or splitted_desc[1] == '\n': + variant_description += temp_variant_description + variant.db_set('description', variant_description, update_modified=False) + else: + variant.db_set('description', variant_description, update_modified=False) + + else: + variant.db_set('description', temp_variant_description, update_modified=False) \ No newline at end of file diff --git a/erpnext/patches/v9_0/student_admission_childtable_migrate.py b/erpnext/patches/v9_0/student_admission_childtable_migrate.py new file mode 100644 index 00000000000..dcbbeebcaf7 --- /dev/null +++ b/erpnext/patches/v9_0/student_admission_childtable_migrate.py @@ -0,0 +1,28 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('schools', 'doctype', 'Student Admission Program') + frappe.reload_doctype('Student Admission') + + if "program" not in frappe.db.get_table_columns("Student Admission"): + return + + student_admissions = frappe.get_all("Student Admission", fields=["name", "application_fee", \ + "naming_series_for_student_applicant", "program", "introduction", "eligibility"]) + for student_admission in student_admissions: + doc = frappe.get_doc("Student Admission", student_admission.name) + doc.append("program_details", { + "program": student_admission.get("program"), + "application_fee": student_admission.get("application_fee"), + "applicant_naming_series": student_admission.get("naming_series_for_student_applicant"), + }) + if student_admission.eligibility and student_admission.introduction: + doc.introduction = student_admission.introduction + "
" + \ + student_admission.eligibility + "
" + doc.flags.ignore_validate = True + doc.flags.ignore_mandatory = True + doc.save() diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index 9f4c2b9c350..460ddc6210a 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -61,7 +61,7 @@ class Project(Document): self.send_welcome_email() def validate_project_name(self): - if frappe.db.exists("Project", self.project_name): + if self.get("__islocal") and frappe.db.exists("Project", self.project_name): frappe.throw(_("Project {0} already exists").format(self.project_name)) def validate_dates(self): diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py index 43240b20e72..52ae132078c 100644 --- a/erpnext/projects/doctype/task/task.py +++ b/erpnext/projects/doctype/task/task.py @@ -47,7 +47,7 @@ class Task(Document): from frappe.desk.form.assign_to import clear clear(self.doctype, self.name) - + def validate_progress(self): if self.progress > 100: frappe.throw(_("Progress % for a task cannot be more than 100.")) @@ -63,6 +63,12 @@ class Task(Document): self.check_recursion() self.reschedule_dependent_tasks() self.update_project() + self.unassign_todo() + + def unassign_todo(self): + if self.status == "Closed" or self.status == "Cancelled": + from frappe.desk.form.assign_to import clear + clear(self.doctype, self.name) def update_total_expense_claim(self): self.total_expense_claim = frappe.db.sql("""select sum(total_sanctioned_amount) from `tabExpense Claim` @@ -120,7 +126,7 @@ class Task(Document): def has_webform_permission(doc): project_user = frappe.db.get_value("Project User", {"parent": doc.project, "user":frappe.session.user} , "user") if project_user: - return True + return True @frappe.whitelist() def get_events(start, end, filters=None): @@ -154,7 +160,7 @@ def get_project(doctype, txt, searchfield, start, page_len, filters): order by name limit %(start)s, %(page_len)s """ % {'key': searchfield, 'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype), - 'start': start, 'page_len': page_len}) + 'start': start, 'page_len': page_len}) @frappe.whitelist() @@ -170,4 +176,5 @@ def set_tasks_as_overdue(): where exp_end_date is not null and exp_end_date < CURDATE() and `status` not in ('Closed', 'Cancelled')""") - + + diff --git a/erpnext/projects/doctype/timesheet/timesheet.js b/erpnext/projects/doctype/timesheet/timesheet.js index ba1414cf2a6..43f5705e820 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.js +++ b/erpnext/projects/doctype/timesheet/timesheet.js @@ -159,9 +159,14 @@ frappe.ui.form.on("Timesheet Detail", { }); var calculate_end_time = function(frm, cdt, cdn) { - var child = locals[cdt][cdn]; + let child = locals[cdt][cdn]; - var d = moment(child.from_time); + if(!child.from_time) { + // if from_time value is not available then set the current datetime + frappe.model.set_value(cdt, cdn, "from_time", frappe.datetime.get_datetime_as_string()); + } + + let d = moment(child.from_time); if(child.hours) { d.add(child.hours, "hours"); frm._setting_hours = true; @@ -186,7 +191,6 @@ var update_time_rates = function(frm, cdt, cdn){ var child = locals[cdt][cdn]; if(!child.billable){ frappe.model.set_value(cdt, cdn, 'billing_rate', 0.0); - frappe.model.set_value(cdt, cdn, 'costing_rate', 0.0); } } @@ -197,9 +201,8 @@ var calculate_billing_costing_amount = function(frm, cdt, cdn){ if(child.billing_hours && child.billable){ billing_amount = (child.billing_hours * child.billing_rate); - costing_amount = flt(child.costing_rate * child.billing_hours); } - + costing_amount = flt(child.costing_rate * child.hours); frappe.model.set_value(cdt, cdn, 'billing_amount', billing_amount); frappe.model.set_value(cdt, cdn, 'costing_amount', costing_amount); calculate_time_and_amount(frm); diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index ad566d5ac11..01552a50c9e 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -49,10 +49,10 @@ class Timesheet(Document): self.update_time_rates(d) self.total_hours += flt(d.hours) + self.total_costing_amount += flt(d.costing_amount) if d.billable: self.total_billable_hours += flt(d.billing_hours) self.total_billable_amount += flt(d.billing_amount) - self.total_costing_amount += flt(d.costing_amount) self.total_billed_amount += flt(d.billing_amount) if d.sales_invoice else 0.0 self.total_billed_hours += flt(d.billing_hours) if d.sales_invoice else 0.0 @@ -265,19 +265,19 @@ class Timesheet(Document): def update_cost(self): for data in self.time_logs: - if data.activity_type and data.billable: + if data.activity_type or data.billable: rate = get_activity_cost(self.employee, data.activity_type) hours = data.billing_hours or 0 + costing_hours = data.billing_hours or data.hours or 0 if rate: data.billing_rate = flt(rate.get('billing_rate')) if flt(data.billing_rate) == 0 else data.billing_rate data.costing_rate = flt(rate.get('costing_rate')) if flt(data.costing_rate) == 0 else data.costing_rate data.billing_amount = data.billing_rate * hours - data.costing_amount = data.costing_rate * hours + data.costing_amount = data.costing_rate * costing_hours def update_time_rates(self, ts_detail): if not ts_detail.billable: ts_detail.billing_rate = 0.0 - ts_detail.costing_rate = 0.0 @frappe.whitelist() def get_projectwise_timesheet_data(project, parent=None): diff --git a/erpnext/public/css/hub.css b/erpnext/public/css/hub.css new file mode 100644 index 00000000000..559c2039793 --- /dev/null +++ b/erpnext/public/css/hub.css @@ -0,0 +1,104 @@ +/* hub */ +div[data-page-route="hub"] .page-head { + height: 80px; +} +div[data-page-route="hub"] .page-head .title-text { + cursor: pointer; +} +div[data-page-route="hub"] .page-content { + margin-top: 80px; +} +div[data-page-route="hub"] .page-title h1 { + margin-bottom: 0px; +} +div[data-page-route="hub"] .account-details { + margin-top: 20px; +} +div[data-page-route="hub"] [data-original-title="Search"] { + float: right; + width: 220px; +} +div[data-page-route="hub"] .hub-main-section { + padding: 30px; +} +div[data-page-route="hub"] .listing-body { + margin: 0; +} +div[data-page-route="hub"] .main-list-section { + padding: 0; +} +div[data-page-route="hub"] .side-list-section { + padding: 0; +} +div[data-page-route="hub"] .item-list-header h3 { + font-weight: normal; +} +div[data-page-route="hub"] .hub-item-page h2 { + margin-top: 10px; +} +div[data-page-route="hub"] .hub-item-page .item-header { + display: flex; +} +div[data-page-route="hub"] .hub-item-page .item-page-image { + flex: 1; +} +div[data-page-route="hub"] .hub-item-page .title-content { + flex: 3; +} +div[data-page-route="hub"] .hub-item-page .title-content .description { + margin: 30px 0px; +} +div[data-page-route="hub"] .hub-item-page .title-content .actions { + margin-top: 30px; +} +div[data-page-route="hub"] .hub-item-page .title-content .actions .rfq-btn.disabled { + background-color: #b1bdca; + color: #fff; + border-color: #b1bdca; +} +div[data-page-route="hub"] .hub-item-page .company-items { + margin-top: 40px; +} +div[data-page-route="hub"] .company-header { + display: flex; +} +div[data-page-route="hub"] .item-list { + display: flex; + flex-wrap: wrap; + justify-content: space-between; +} +div[data-page-route="hub"] .hub-item-wrapper { + margin-bottom: 20px; +} +div[data-page-route="hub"] .img-wrapper { + border: 1px solid #d1d8dd; + border-radius: 3px; + padding: 12px; + overflow: hidden; + text-align: center; + white-space: nowrap; +} +div[data-page-route="hub"] .img-wrapper img { + max-width: 100%; + max-height: 100%; + display: inline-block; + vertical-align: middle; +} +div[data-page-route="hub"] .img-wrapper .helper { + height: 100%; + display: inline-block; + vertical-align: middle; +} +div[data-page-route="hub"] .img-wrapper .standard-image { + font-size: 72px; + border: none; + background-color: #fafbfc; +} +div[data-page-route="hub"] .hub-item-title { + width: 100%; +} +div[data-page-route="hub"] .breadcrumb { + padding-left: 0; + padding-top: 0; + margin-bottom: 10px; +} diff --git a/erpnext/public/images/hub_logo.svg b/erpnext/public/images/hub_logo.svg new file mode 100644 index 00000000000..23630906009 --- /dev/null +++ b/erpnext/public/images/hub_logo.svg @@ -0,0 +1,76 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/erpnext/public/js/communication.js b/erpnext/public/js/communication.js index 5ce57b67df3..bb2eaefc44b 100644 --- a/erpnext/public/js/communication.js +++ b/erpnext/public/js/communication.js @@ -1,39 +1,45 @@ frappe.ui.form.on("Communication", { - refresh: function(frm) { + refresh: (frm) => { + // setup custom Make button only if Communication is Email + if(frm.doc.communication_medium == "Email" && frm.doc.sent_or_received == "Received") { + frm.events.setup_custom_buttons(frm); + } + }, + + setup_custom_buttons: (frm) => { + let confirm_msg = "Are you sure you want to create {0} from this email"; if(frm.doc.reference_doctype !== "Issue") { - frm.add_custom_button(__("Issue"), function() { - frappe.confirm("Are you sure you want to create Issue from this email", function(){ + frm.add_custom_button(__("Issue"), () => { + frappe.confirm(__(confirm_msg, [__("Issue")]), () => { frm.trigger('make_issue_from_communication'); }) }, "Make"); } if(!in_list(["Lead", "Opportunity"], frm.doc.reference_doctype)) { - frm.add_custom_button(__("Lead"), function() { - frappe.confirm("Are you sure you want to create Lead from this email", function(){ + frm.add_custom_button(__("Lead"), () => { + frappe.confirm(__(confirm_msg, [__("Lead")]), () => { frm.trigger('make_lead_from_communication'); }) }, "Make"); - frm.add_custom_button(__("Opportunity"), function() { - frappe.confirm("Are you sure you want to create Opportunity from this email", function(){ + frm.add_custom_button(__("Opportunity"), () => { + frappe.confirm(__(confirm_msg, [__("Opportunity")]), () => { frm.trigger('make_opportunity_from_communication'); }) }, "Make"); } - - frm.page.set_inner_btn_group_as_primary(__("Make")); }, - make_lead_from_communication: function(frm) { + make_lead_from_communication: (frm) => { return frappe.call({ method: "frappe.email.inbox.make_lead_from_communication", args: { communication: frm.doc.name }, freeze: true, - callback: function(r) { + callback: (r) => { if(r.message) { frm.reload_doc() } @@ -41,14 +47,14 @@ frappe.ui.form.on("Communication", { }) }, - make_issue_from_communication: function(frm) { + make_issue_from_communication: (frm) => { return frappe.call({ method: "frappe.email.inbox.make_issue_from_communication", args: { communication: frm.doc.name }, freeze: true, - callback: function(r) { + callback: (r) => { if(r.message) { frm.reload_doc() } @@ -56,14 +62,14 @@ frappe.ui.form.on("Communication", { }) }, - make_opportunity_from_communication: function(frm) { + make_opportunity_from_communication: (frm) => { return frappe.call({ method: "frappe.email.inbox.make_opportunity_from_communication", args: { communication: frm.doc.name }, freeze: true, - callback: function(r) { + callback: (r) => { if(r.message) { frm.reload_doc() } diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 5f35ea44de8..41fdc6e6462 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -101,27 +101,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ return me.set_query_for_batch(doc, cdt, cdn) }); } - }, - onload: function() { - var me = this; - if(this.frm.doc.__islocal) { - var today = frappe.datetime.get_today(), - currency = frappe.defaults.get_user_default("currency"); - - $.each({ - currency: currency, - price_list_currency: currency, - status: "Draft", - is_subcontracted: "No", - }, function(fieldname, value) { - if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) - me.frm.set_value(fieldname, value); - }); - - if(this.frm.doc.company && !this.frm.doc.amended_from) { - this.frm.trigger("company"); - } - } if(this.frm.fields_dict["taxes"]) { this["taxes_remove"] = this.calculate_taxes_and_totals; @@ -153,11 +132,36 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ return { filters: filters - } + }; }); } + }, + onload: function() { + var me = this; this.setup_quality_inspection(); + + if(this.frm.doc.__islocal) { + var currency = frappe.defaults.get_user_default("currency"); + + let set_value = (fieldname, value) => { + if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) { + return me.frm.set_value(fieldname, value); + } + }; + + return frappe.run_serially([ + () => set_value('currency', currency), + () => set_value('price_list_currency', currency), + () => set_value('status', 'Draft'), + () => set_value('is_subcontracted', 'No'), + () => { + if(this.frm.doc.company && !this.frm.doc.amended_from) { + this.frm.trigger("company"); + } + } + ]); + } }, setup_quality_inspection: function() { @@ -195,13 +199,12 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }, onload_post_render: function() { - var me = this; if(this.frm.doc.__islocal && !(this.frm.doc.taxes || []).length && !(this.frm.doc.__onload ? this.frm.doc.__onload.load_after_mapping : false)) { - this.apply_default_taxes(); + frappe.after_ajax(() => this.apply_default_taxes()); } else if(this.frm.doc.__islocal && this.frm.doc.company && this.frm.doc["items"] && !this.frm.doc.is_pos) { - me.calculate_taxes_and_totals(); + frappe.after_ajax(() => this.calculate_taxes_and_totals()); } if(frappe.meta.get_docfield(this.frm.doc.doctype + " Item", "item_code")) { this.setup_item_selector(); @@ -378,6 +381,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ if(me.frm.doc.company && me.frm.fields_dict.currency) { var company_currency = me.get_company_currency(); var company_doc = frappe.get_doc(":Company", me.frm.doc.company); + if (!me.frm.doc.currency) { me.frm.set_value("currency", company_currency); } @@ -538,11 +542,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } // Make read only if Accounts Settings doesn't allow stale rates - frappe.model.get_value("Accounts Settings", null, "allow_stale", - function(d){ - me.set_df_property("conversion_rate", "read_only", cint(d.allow_stale) ? 0 : 1); - } - ); + this.frm.set_df_property("conversion_rate", "read_only", erpnext.stale_rate_allowed()); }, set_actual_charges_based_on_currency: function() { diff --git a/erpnext/public/js/pos/pos.html b/erpnext/public/js/pos/pos.html index 485a94584e7..1d9fd7c20f4 100644 --- a/erpnext/public/js/pos/pos.html +++ b/erpnext/public/js/pos/pos.html @@ -37,7 +37,6 @@
- {% if (apply_discount_on) { %}
{%= __("Discount") %}
@@ -52,7 +51,6 @@
- {% } %}
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index 88178f42ce4..7c274f18db2 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -86,6 +86,10 @@ erpnext.setup.slides_settings = [ }); }, validate: function() { + if ((this.values.company_name || "").toLowerCase() == "company") { + frappe.msgprint(__("Company Name cannot be Company")); + return false; + } if (!this.values.company_abbr) { return false; } @@ -135,10 +139,6 @@ erpnext.setup.slides_settings = [ frappe.msgprint(__("Please enter valid Financial Year Start and End Dates")); return false; } - if ((this.values.company_name || "").toLowerCase() == "company") { - frappe.msgprint(__("Company Name cannot be Company")); - return false; - } return true; }, diff --git a/erpnext/public/js/templates/item_selector.html b/erpnext/public/js/templates/item_selector.html index 89171f87751..58fb26c0e4c 100644 --- a/erpnext/public/js/templates/item_selector.html +++ b/erpnext/public/js/templates/item_selector.html @@ -1,16 +1,37 @@ -
+
{% for (var i=0; i < data.length; i++) { var item = data[i]; %} -
-
- \ No newline at end of file diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js index 721f216888b..efb04d1c093 100644 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -37,6 +37,10 @@ $.extend(erpnext, { } }, + stale_rate_allowed: () => { + return cint(frappe.boot.sysdefaults.allow_stale) || 1; + }, + setup_serial_no: function() { var grid_row = cur_frm.open_grid_row(); if(!grid_row || !grid_row.grid_form.fields_dict.serial_no || diff --git a/erpnext/public/js/utils/item_selector.js b/erpnext/public/js/utils/item_selector.js index 98a17f289fd..d04c488a59d 100644 --- a/erpnext/public/js/utils/item_selector.js +++ b/erpnext/public/js/utils/item_selector.js @@ -2,6 +2,14 @@ erpnext.ItemSelector = Class.extend({ init: function(opts) { $.extend(this, opts); + if (!this.item_field) { + this.item_field = 'item_code'; + } + + if (!this.item_query) { + this.item_query = erpnext.queries.item().query; + } + this.grid = this.frm.get_field("items").grid; this.setup(); }, @@ -32,8 +40,8 @@ erpnext.ItemSelector = Class.extend({ this.dialog.results = body.find('.results'); var me = this; - this.dialog.results.on('click', '.pos-item', function() { - me.add_item($(this).attr('data-name')) + this.dialog.results.on('click', '.image-view-item', function() { + me.add_item($(this).attr('data-name')); }); this.dialog.input.on('keyup', function() { @@ -52,35 +60,42 @@ erpnext.ItemSelector = Class.extend({ var added = false; // find row with item if exists - $.each(this.frm.doc.items || [], function(i, d) { - if(d.item_code===item_code) { + $.each(this.frm.doc.items || [], (i, d) => { + if(d[this.item_field]===item_code) { frappe.model.set_value(d.doctype, d.name, 'qty', d.qty + 1); - frappe.show_alert(__("Added {0} ({1})", [item_code, d.qty])); + frappe.show_alert({message: __("Added {0} ({1})", [item_code, d.qty]), indicator: 'green'}); added = true; return false; } }); if(!added) { - var d = this.grid.add_new_row(); - frappe.model.set_value(d.doctype, d.name, 'item_code', item_code); - - // after item fetch - frappe.after_ajax(function() { - setTimeout(function() { + var d = null; + frappe.run_serially([ + () => { d = this.grid.add_new_row(); }, + () => frappe.model.set_value(d.doctype, d.name, this.item_field, item_code), + () => frappe.timeout(0.1), + () => { frappe.model.set_value(d.doctype, d.name, 'qty', 1); - frappe.show_alert(__("Added {0} ({1})", [item_code, 1])); - }, 100); - }); + frappe.show_alert({message: __("Added {0} ({1})", [item_code, 1]), indicator: 'green'}); + } + ]); } }, render_items: function() { - var args = erpnext.queries.item(); + let args = { + query: this.item_query, + filters: {} + }; args.txt = this.dialog.input.val(); args.as_dict = 1; + if (this.get_filters) { + $.extend(args.filters, this.get_filters() || {}); + } + var me = this; frappe.link_search("Item", args, function(r) { $.each(r.values, function(i, d) { @@ -92,4 +107,4 @@ erpnext.ItemSelector = Class.extend({ me.dialog.results.html(frappe.render_template('item_selector', {'data':r.values})); }); } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/erpnext/public/js/utils/serial_no_batch_selector.js b/erpnext/public/js/utils/serial_no_batch_selector.js index 3e2414e665b..69e3d2fb9fa 100644 --- a/erpnext/public/js/utils/serial_no_batch_selector.js +++ b/erpnext/public/js/utils/serial_no_batch_selector.js @@ -96,7 +96,17 @@ erpnext.SerialNoBatchSelector = Class.extend({ if(this.show_dialog) { let d = this.item; - this.dialog.set_value('serial_no', d.serial_no); + if (d.has_serial_no && d.serial_no) { + this.dialog.set_value('serial_no', d.serial_no); + } else if (d.batch_no) { + this.dialog.fields_dict.batches.df.data.push({ + 'batch_no': d.batch_no, + 'actual_qty': d.actual_qty, + 'selected_qty': d.qty + }); + + this.dialog.fields_dict.batches.grid.refresh(); + } } this.dialog.show(); @@ -116,8 +126,10 @@ erpnext.SerialNoBatchSelector = Class.extend({ } values.batches.map((batch, i) => { if(!batch.selected_qty || batch.selected_qty === 0 ) { - frappe.throw(__("Please select quantity on row " + (i+1))); - return false; + if (!this.show_dialog) { + frappe.throw(__("Please select quantity on row " + (i+1))); + return false; + } } }); return true; @@ -125,9 +137,11 @@ erpnext.SerialNoBatchSelector = Class.extend({ } else { let serial_nos = values.serial_no || ''; if (!serial_nos || !serial_nos.replace(/\s/g, '').length) { - frappe.throw(__("Please enter serial numbers for serialized item " - + values.item_code)); - return false; + if (!this.show_dialog) { + frappe.throw(__("Please enter serial numbers for serialized item " + + values.item_code)); + return false; + } } return true; } diff --git a/erpnext/public/less/erpnext.less b/erpnext/public/less/erpnext.less index d0c4841cc4f..262b0c308cd 100644 --- a/erpnext/public/less/erpnext.less +++ b/erpnext/public/less/erpnext.less @@ -438,4 +438,4 @@ body[data-route="pos"] { .list-item_content { padding-right: 45px; } -} \ No newline at end of file +} diff --git a/erpnext/public/less/hub.less b/erpnext/public/less/hub.less new file mode 100644 index 00000000000..1cae692d7dd --- /dev/null +++ b/erpnext/public/less/hub.less @@ -0,0 +1,140 @@ +@import "../../../../frappe/frappe/public/less/variables.less"; + +/* hub */ +div[data-page-route="hub"] { + .page-head { + height: 80px; + + .title-text { + cursor: pointer; + } + } + + .page-content { + margin-top: 80px; + } + + .page-title h1 { + margin-bottom: 0px; + } + + .account-details { + margin-top: 20px; + } + + [data-original-title="Search"] { + float: right; + width: 220px; + } + + .hub-main-section { + padding: 30px; + } + + .listing-body { + margin: 0; + } + + .main-list-section { + padding: 0; + // border-right: 1px solid #d1d8dd; + } + + .side-list-section { + padding: 0; + } + + .item-list-header h3 { + font-weight: normal; + } + + .hub-item-page { + + h2 { + margin-top: 10px; + } + + .item-header { + display: flex; + } + + .item-page-image { + flex: 1; + } + + .title-content { + flex: 3; + + .description { + margin: 30px 0px; + } + + .actions { + margin-top: 30px; + + .rfq-btn.disabled { + background-color: #b1bdca; + color: #fff; + border-color: #b1bdca; + } + } + } + + .company-items { + margin-top: 40px; + } + } + + .company-header { + display: flex; + } + + .item-list { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + } + + .hub-item-wrapper { + margin-bottom: 20px; + } + + .img-wrapper { + border: 1px solid @border-color; + border-radius: 3px; + padding: 12px; + overflow: hidden; + text-align: center; + white-space: nowrap; + + img { + max-width: 100%; + max-height: 100%; + display: inline-block; + vertical-align: middle; + } + + .helper { + height: 100%; + display: inline-block; + vertical-align: middle; + } + + .standard-image { + font-size: 72px; + border: none; + background-color: @light-bg; + } + } + + .hub-item-title { + width: 100%; + } + + .breadcrumb { + padding-left: 0; + padding-top: 0; + margin-bottom: 10px; + } + +} \ No newline at end of file diff --git a/erpnext/restaurant/__init__.py b/erpnext/restaurant/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/__init__.py b/erpnext/restaurant/doctype/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/restaurant/__init__.py b/erpnext/restaurant/doctype/restaurant/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.js b/erpnext/restaurant/doctype/restaurant/restaurant.js new file mode 100644 index 00000000000..13fda73922a --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant/restaurant.js @@ -0,0 +1,10 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Restaurant', { + refresh: function(frm) { + frm.add_custom_button(__('Order Entry'), () => { + frappe.set_route('Form', 'Restaurant Order Entry'); + }); + } +}); diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.json b/erpnext/restaurant/doctype/restaurant/restaurant.json new file mode 100644 index 00000000000..f4ecba79452 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant/restaurant.json @@ -0,0 +1,309 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "prompt", + "beta": 0, + "creation": "2017-09-15 12:40:41.546933", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "image", + "fieldtype": "Attach Image", + "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": "Image", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "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": "Company", + "length": 0, + "no_copy": 0, + "options": "Company", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_customer", + "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": "Default Customer", + "length": 0, + "no_copy": 0, + "options": "Customer", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "invoice_series_prefix", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Invoice Series Prefix", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_4", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "active_menu", + "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": "Active Menu", + "length": 0, + "no_copy": 0, + "options": "Restaurant Menu", + "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": "default_tax_template", + "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": "Default Tax Template", + "length": 0, + "no_copy": 0, + "options": "Sales Taxes and Charges Template", + "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": "address", + "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": "Address", + "length": 0, + "no_copy": 0, + "options": "Address", + "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 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_field": "image", + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-10-05 17:41:14.422242", + "modified_by": "Administrator", + "module": "Restaurant", + "name": "Restaurant", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Hospitality", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.py b/erpnext/restaurant/doctype/restaurant/restaurant.py new file mode 100644 index 00000000000..0bb7b692c75 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant/restaurant.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class Restaurant(Document): + pass diff --git a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py new file mode 100644 index 00000000000..1f84ccf1d8d --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py @@ -0,0 +1,16 @@ +from frappe import _ + +def get_data(): + return { + 'fieldname': 'restaurant', + 'transactions': [ + { + 'label': _('Setup'), + 'items': ['Restaurant Menu', 'Restaurant Table'] + }, + { + 'label': _('Operations'), + 'items': ['Restaurant Reservation', 'Sales Invoice'] + } + ] + } \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.js b/erpnext/restaurant/doctype/restaurant/test_restaurant.js new file mode 100644 index 00000000000..f4a13432e25 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant/test_restaurant.js @@ -0,0 +1,41 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Restaurant", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(2); + + frappe.run_serially([ + // insert a new Restaurant + () => { + return frappe.tests.make('Restaurant', [ + // values to be set + {__newname: 'Test Restaurant 1'}, + {company: 'Test Company'}, + {invoice_series_prefix: 'Test-Rest-1-Inv-'}, + {default_customer: 'Test Customer 1'} + ]) + }, + () => frappe.timeout(3), + () => { + assert.equal(cur_frm.doc.company, 'Test Company'); + }, + () => { + return frappe.tests.make('Restaurant', [ + // values to be set + {__newname: 'Test Restaurant 2'}, + {company: 'Test Company'}, + {invoice_series_prefix: 'Test-Rest-3-Inv-'}, + {default_customer: 'Test Customer 2'} + ]); + }, + () => frappe.timeout(3), + () => { + assert.equal(cur_frm.doc.company, 'Test Company'); + }, + () => done() + ]); +}); diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.py b/erpnext/restaurant/doctype/restaurant/test_restaurant.py new file mode 100644 index 00000000000..3ba7f5785eb --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant/test_restaurant.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +test_records = [ + dict(doctype='Restaurant', name='Test Restaurant 1', company='_Test Company 1', + invoice_series_prefix='Test-Rest-1-Inv-', default_customer='_Test Customer 1'), + dict(doctype='Restaurant', name='Test Restaurant 2', company='_Test Company 1', + invoice_series_prefix='Test-Rest-2-Inv-', default_customer='_Test Customer 1'), +] + +class TestRestaurant(unittest.TestCase): + pass diff --git a/erpnext/restaurant/doctype/restaurant_menu/__init__.py b/erpnext/restaurant/doctype/restaurant_menu/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js new file mode 100644 index 00000000000..da7d43f8a3e --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js @@ -0,0 +1,8 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Restaurant Menu', { + setup: function(frm) { + frm.add_fetch('item', 'standard_rate', 'rate'); + }, +}); diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json new file mode 100644 index 00000000000..264634b0f6f --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json @@ -0,0 +1,247 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "prompt", + "beta": 0, + "creation": "2017-09-15 12:48:29.818715", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "restaurant", + "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": "Restaurant", + "length": 0, + "no_copy": 0, + "options": "Restaurant", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "1", + "fieldname": "enabled", + "fieldtype": "Check", + "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": "Enabled", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "price_list", + "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": "Price List (Auto created)", + "length": 0, + "no_copy": 0, + "options": "Price List", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "items_section", + "fieldtype": "Section 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": "Items", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "items", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Items", + "length": 0, + "no_copy": 0, + "options": "Restaurant Menu Item", + "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 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-09-21 11:04:20.671542", + "modified_by": "Administrator", + "module": "Restaurant", + "name": "Restaurant Menu", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Restaurant Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Hospitality", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py new file mode 100644 index 00000000000..83020b6cca8 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class RestaurantMenu(Document): + def validate(self): + for d in self.items: + if not d.rate: + d.rate = frappe.db.get_value('Item', d.item, 'standard_rate') + + def on_update(self): + '''Sync Price List''' + self.make_price_list() + + def on_trash(self): + '''clear prices''' + self.clear_item_price() + + def clear_item_price(self, price_list=None): + '''clear all item prices for this menu''' + if not price_list: + price_list = self.get_price_list().name + frappe.db.sql('delete from `tabItem Price` where price_list = %s', price_list) + + def make_price_list(self): + # create price list for menu + price_list = self.get_price_list() + self.db_set('price_list', price_list.name) + + # delete old items + self.clear_item_price(price_list.name) + + for d in self.items: + frappe.get_doc(dict( + doctype = 'Item Price', + price_list = price_list.name, + item_code = d.item, + price_list_rate = d.rate + )).insert() + + def get_price_list(self): + '''Create price list for menu if missing''' + price_list_name = frappe.db.get_value('Price List', dict(restaurant_menu=self.name)) + if price_list_name: + price_list = frappe.get_doc('Price List', price_list_name) + else: + price_list = frappe.new_doc('Price List') + price_list.restaurant_menu = self.name + price_list.price_list_name = self.name + + price_list.enabled = 1 + price_list.selling = 1 + price_list.save() + + return price_list + + diff --git a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js new file mode 100644 index 00000000000..f5ab9f09012 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.js @@ -0,0 +1,77 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Restaurant Menu", function (assert) { + let done = assert.async(); + + let items = { + "Food Item 1": [ + {item_code: "Food Item 1"}, + {item_group: "Products"}, + {is_stock_item: 1}, + ], + "Food Item 2": [ + {item_code: "Food Item 2"}, + {item_group: "Products"}, + {is_stock_item: 1}, + ], + "Food Item 3": [ + {item_code: "Food Item 3"}, + {item_group: "Products"}, + {is_stock_item: 1}, + ] + }; + + + // number of asserts + assert.expect(0); + + frappe.run_serially([ + // insert a new Restaurant Menu + () => frappe.tests.setup_doctype('Item', items), + () => { + return frappe.tests.make("Restaurant Menu", [ + {__newname: 'Restaurant Menu 1'}, + {restaurant: "Test Restaurant 1"}, + {items: [ + [ + {"item": "Food Item 1"}, + {"rate": 100} + ], + [ + {"item": "Food Item 2"}, + {"rate": 90} + ], + [ + {"item": "Food Item 3"}, + {"rate": 80} + ] + ]} + ]); + }, + () => frappe.timeout(2), + () => { + return frappe.tests.make("Restaurant Menu", [ + {__newname: 'Restaurant Menu 2'}, + {restaurant: "Test Restaurant 2"}, + {items: [ + [ + {"item": "Food Item 1"}, + {"rate": 105} + ], + [ + {"item": "Food Item 3"}, + {"rate": 85} + ] + ]} + ]); + }, + () => frappe.timeout(2), + () => frappe.set_route('Form', 'Restaurant', 'Test Restaurant 1'), + () => cur_frm.set_value('active_menu', 'Restaurant Menu 1'), + () => cur_frm.save(), + () => done() + ]); + +}); diff --git a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py new file mode 100644 index 00000000000..99766f7b017 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +test_records = [ + dict(doctype='Item', item_code='Food Item 1', + item_group='Products', is_stock_item=0), + dict(doctype='Item', item_code='Food Item 2', + item_group='Products', is_stock_item=0), + dict(doctype='Item', item_code='Food Item 3', + item_group='Products', is_stock_item=0), + dict(doctype='Item', item_code='Food Item 4', + item_group='Products', is_stock_item=0), + dict(doctype='Restaurant Menu', restaurant='Test Restaurant 1', name='Test Restaurant 1 Menu 1', + items = [ + dict(item='Food Item 1', rate=400), + dict(item='Food Item 2', rate=300), + dict(item='Food Item 3', rate=200), + dict(item='Food Item 4', rate=100), + ]), + dict(doctype='Restaurant Menu', restaurant='Test Restaurant 1', name='Test Restaurant 1 Menu 2', + items = [ + dict(item='Food Item 1', rate=450), + dict(item='Food Item 2', rate=350), + ]) +] + +class TestRestaurantMenu(unittest.TestCase): + def test_price_list_creation_and_editing(self): + menu1 = frappe.get_doc('Restaurant Menu', 'Test Restaurant 1 Menu 1') + menu1.save() + + menu2 = frappe.get_doc('Restaurant Menu', 'Test Restaurant 1 Menu 2') + menu2.save() + + self.assertTrue(frappe.db.get_value('Price List', 'Test Restaurant 1 Menu 1')) + self.assertEquals(frappe.db.get_value('Item Price', + dict(price_list = 'Test Restaurant 1 Menu 1', item_code='Food Item 1'), 'price_list_rate'), 400) + self.assertEquals(frappe.db.get_value('Item Price', + dict(price_list = 'Test Restaurant 1 Menu 2', item_code='Food Item 1'), 'price_list_rate'), 450) + + menu1.items[0].rate = 401 + menu1.save() + + self.assertEquals(frappe.db.get_value('Item Price', + dict(price_list = 'Test Restaurant 1 Menu 1', item_code='Food Item 1'), 'price_list_rate'), 401) + + menu1.items[0].rate = 400 + menu1.save() diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/__init__.py b/erpnext/restaurant/doctype/restaurant_menu_item/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json new file mode 100644 index 00000000000..87568bf9818 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json @@ -0,0 +1,105 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "", + "beta": 0, + "creation": "2017-09-15 12:49:36.072636", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "item", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Item", + "length": 0, + "no_copy": 0, + "options": "Item", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "rate", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Rate", + "length": 0, + "no_copy": 0, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2017-09-15 14:18:55.145088", + "modified_by": "Administrator", + "module": "Restaurant", + "name": "Restaurant Menu Item", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Hospitality", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py new file mode 100644 index 00000000000..cc86bb3165e --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class RestaurantMenuItem(Document): + pass diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/__init__.py b/erpnext/restaurant/doctype/restaurant_order_entry/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js new file mode 100644 index 00000000000..8867e7d707b --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js @@ -0,0 +1,162 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Restaurant Order Entry', { + setup: function(frm) { + let get_item_query = () => { + return { + query: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.item_query_restaurant', + filters: { + 'table': frm.doc.restaurant_table + } + }; + }; + frm.set_query('item', 'items', get_item_query); + frm.set_query('add_item', get_item_query); + }, + onload_post_render: function(frm) { + if(!this.item_selector) { + this.item_selector = new erpnext.ItemSelector({ + frm: frm, + item_field: 'item', + item_query: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.item_query_restaurant', + get_filters: () => { + return {table: frm.doc.restaurant_table}; + } + }); + } + + let $input = frm.get_field('add_item').$input; + + $input.on('keyup', function(e) { + if (e.which===13) { + if (frm.clear_item_timeout) { + clearTimeout (frm.clear_item_timeout); + } + + // clear the item input so user can enter a new item + frm.clear_item_timeout = setTimeout (() => { + frm.set_value('add_item', ''); + }, 1000); + + let item = $input.val(); + + if (!item) return; + + var added = false; + (frm.doc.items || []).forEach((d) => { + if (d.item===item) { + d.qty += 1; + added = true; + } + }); + + return frappe.run_serially([ + () => { + if (!added) { + return frm.add_child('items', {item: item, qty: 1}); + } + }, + () => frm.get_field("items").refresh() + ]); + } + }); + }, + refresh: function(frm) { + frm.disable_save(); + frm.add_custom_button(__('Update'), () => { + return frm.trigger('sync'); + }); + frm.add_custom_button(__('Clear'), () => { + return frm.trigger('clear'); + }); + frm.add_custom_button(__('Bill'), () => { + return frm.trigger('make_invoice'); + }); + }, + clear: function(frm) { + frm.doc.add_item = ''; + frm.doc.grand_total = 0; + frm.doc.items = []; + frm.refresh(); + frm.get_field('add_item').$input.focus(); + }, + restaurant_table: function(frm) { + // select the open sales order items for this table + if (!frm.doc.restaurant_table) { + return; + } + return frappe.call({ + method: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.get_invoice', + args: { + table: frm.doc.restaurant_table + }, + callback: (r) => { + frm.events.set_invoice_items(frm, r); + } + }); + }, + sync: function(frm) { + return frappe.call({ + method: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.sync', + args: { + table: frm.doc.restaurant_table, + items: frm.doc.items + }, + callback: (r) => { + frm.events.set_invoice_items(frm, r); + frappe.show_alert({message: __('Saved'), indicator: 'green'}); + } + }); + + }, + make_invoice: function(frm) { + frm.trigger('sync').then(() => { + frappe.prompt([ + { + fieldname: 'customer', + label: __('Customer'), + fieldtype: 'Link', + reqd: 1, + options: 'Customer', + 'default': frm.invoice.customer + }, + { + fieldname: 'mode_of_payment', + label: __('Mode of Payment'), + fieldtype: 'Link', + reqd: 1, + options: 'Mode of Payment', + 'default': frm.mode_of_payment || '' + } + ], (data) => { + // cache this for next entry + frm.mode_of_payment = data.mode_of_payment; + return frappe.call({ + method: 'erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry.make_invoice', + args: { + table: frm.doc.restaurant_table, + customer: data.customer, + mode_of_payment: data.mode_of_payment + }, + callback: (r) => { + frm.set_value('last_sales_invoice', r.message); + frm.trigger('clear'); + } + }); + }, + __("Select Customer")); + }); + }, + set_invoice_items: function(frm, r) { + let invoice = r.message; + frm.doc.items = []; + (invoice.items || []).forEach((d) => { + frm.add_child('items', {item: d.item_code, qty: d.qty, rate: d.rate}); + }); + frm.set_value('grand_total', invoice.grand_total); + frm.set_value('last_sales_invoice', invoice.name); + frm.invoice = invoice; + frm.refresh(); + } +}); diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.json b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.json new file mode 100644 index 00000000000..3e4d593d5b6 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.json @@ -0,0 +1,280 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 1, + "creation": "2017-09-15 15:10:24.530365", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "restaurant_table", + "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": "Restaurant Table", + "length": 0, + "no_copy": 0, + "options": "Restaurant Table", + "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, + "depends_on": "restaurant_table", + "description": "Click Enter To Add", + "fieldname": "add_item", + "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": "Add Item", + "length": 0, + "no_copy": 0, + "options": "Item", + "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_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "grand_total", + "fieldtype": "Currency", + "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": "Grand Total", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "last_sales_invoice", + "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": "Last Sales Invoice", + "length": 0, + "no_copy": 0, + "options": "Sales Invoice", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "restaurant_table", + "fieldname": "current_order", + "fieldtype": "Section 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": "Current Order", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "restaurant_table", + "fieldname": "items", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Items", + "length": 0, + "no_copy": 0, + "options": "Restaurant Order Entry Item", + "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 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 1, + "istable": 0, + "max_attachments": 0, + "modified": "2017-10-04 17:06:20.926999", + "modified_by": "Administrator", + "module": "Restaurant", + "name": "Restaurant Order Entry", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 0, + "role": "Restaurant Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Hospitality", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py new file mode 100644 index 00000000000..a748f9a0075 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe, json +from frappe.model.document import Document +from frappe import _ +from erpnext.controllers.queries import item_query + +class RestaurantOrderEntry(Document): + pass + +@frappe.whitelist() +def get_invoice(table): + '''returns the active invoice linked to the given table''' + invoice_name = frappe.get_value('Sales Invoice', dict(restaurant_table = table, docstatus=0)) + restaurant, menu_name = get_restaurant_and_menu_name(table) + if invoice_name: + invoice = frappe.get_doc('Sales Invoice', invoice_name) + else: + invoice = frappe.new_doc('Sales Invoice') + invoice.naming_series = frappe.db.get_value('Restaurant', restaurant, 'invoice_series_prefix') + invoice.is_pos = 1 + default_customer = frappe.db.get_value('Restaurant', restaurant, 'default_customer') + if not default_customer: + frappe.throw(_('Please set default customer in Restaurant Settings')) + invoice.customer = default_customer + + invoice.taxes_and_charges = frappe.db.get_value('Restaurant', restaurant, 'default_tax_template') + invoice.selling_price_list = frappe.db.get_value('Price List', dict(restaurant_menu=menu_name, enabled=1)) + + return invoice + +@frappe.whitelist() +def sync(table, items): + '''Sync the sales order related to the table''' + invoice = get_invoice(table) + items = json.loads(items) + + invoice.items = [] + invoice.restaurant_table = table + for d in items: + invoice.append('items', dict( + item_code = d.get('item'), + qty = d.get('qty') + )) + + invoice.save() + return invoice.as_dict() + +@frappe.whitelist() +def make_invoice(table, customer, mode_of_payment): + '''Make table based on Sales Order''' + restaurant, menu = get_restaurant_and_menu_name(table) + invoice = get_invoice(table) + invoice.customer = customer + invoice.restaurant = restaurant + invoice.calculate_taxes_and_totals() + invoice.append('payments', dict(mode_of_payment=mode_of_payment, amount=invoice.grand_total)) + invoice.save() + invoice.submit() + + frappe.msgprint(_('Invoice Created'), indicator='green', alert=True) + + return invoice.name + +def item_query_restaurant(doctype='Item', txt='', searchfield='name', start=0, page_len=20, filters=None, as_dict=False): + '''Return items that are selected in active menu of the restaurant''' + restaurant, menu = get_restaurant_and_menu_name(filters['table']) + items = frappe.db.get_all('Restaurant Menu Item', ['item'], dict(parent = menu)) + del filters['table'] + filters['name'] = ('in', [d.item for d in items]) + + return item_query('Item', txt, searchfield, start, page_len, filters, as_dict) + +def get_restaurant_and_menu_name(table): + if not table: + frappe.throw(_('Please select a table')) + + restaurant = frappe.db.get_value('Restaurant Table', table, 'restaurant') + menu = frappe.db.get_value('Restaurant', restaurant, 'active_menu') + + if not menu: + frappe.throw(_('Please set an active menu for Restaurant {0}').format(restaurant)) + + return restaurant, menu \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.js b/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.js new file mode 100644 index 00000000000..fec2a2153be --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.js @@ -0,0 +1,53 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Restaurant Order Entry", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(5); + + frappe.run_serially([ + // insert a new Restaurant Order Entry + () => frappe.set_route('Form', 'Restaurant Settings'), + () => cur_frm.set_value('default_customer', 'Test Customer 1'), + () => cur_frm.save(), + () => frappe.set_route('Form', 'Restaurant Order Entry'), + () => frappe.click_button('Clear'), + () => frappe.timeout(2), + () => cur_frm.set_value('restaurant_table', 'Test-Restaurant-1-01'), + () => cur_frm.set_value('add_item', 'Food Item 1'), + () => frappe.timeout(0.5), + () => { + var e = $.Event( "keyup", {which: 13} ); + $('input[data-fieldname="add_item"]').trigger(e); + return frappe.timeout(0.5); + }, + () => cur_frm.set_value('add_item', 'Food Item 1'), + () => { + var e = $.Event( "keyup", {which: 13} ); + $('input[data-fieldname="add_item"]').trigger(e); + return frappe.timeout(0.5); + }, + () => cur_frm.set_value('add_item', 'Food Item 2'), + () => { + var e = $.Event( "keyup", {which: 13} ); + $('input[data-fieldname="add_item"]').trigger(e); + return frappe.timeout(0.5); + }, + () => { + assert.equal(cur_frm.doc.items[0].item, 'Food Item 1'); + assert.equal(cur_frm.doc.items[0].qty, 2); + assert.equal(cur_frm.doc.items[1].item, 'Food Item 2'); + assert.equal(cur_frm.doc.items[1].qty, 1); + }, + () => frappe.click_button('Update'), + () => frappe.timeout(2), + () => { + assert.equal(cur_frm.doc.grand_total, 290); + } + () => done() + ]); + +}); diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.py b/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.py new file mode 100644 index 00000000000..59605b150b3 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_order_entry/test_restaurant_order_entry.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe, json +import unittest + +from erpnext.restaurant.doctype.restaurant_order_entry.restaurant_order_entry \ + import (sync, make_invoice, item_query_restaurant) + +class TestRestaurantOrderEntry(unittest.TestCase): + def setUp(self): + # save the menus as Price List is deleted before tests... + frappe.get_doc('Restaurant Menu', 'Test Restaurant 1 Menu 1').save() + frappe.get_doc('Restaurant Menu', 'Test Restaurant 1 Menu 2').save() + + if not frappe.db.get_value('Restaurant', 'Test Restaurant 1', 'active_menu'): + restaurant = frappe.get_doc('Restaurant', 'Test Restaurant 1') + restaurant.active_menu = 'Test Restaurant 1 Menu 1' + restaurant.save() + + def test_update_order(self): + table = frappe.db.get_value('Restaurant Table', dict(restaurant = 'Test Restaurant 1')) + invoice = sync(table, + json.dumps([dict(item='Food Item 1', qty = 10), dict(item='Food Item 2', qty = 2)])) + + self.assertEquals(invoice.get('restaurant_table'), table) + self.assertEquals(invoice.get('items')[0].get('item_code'), 'Food Item 1') + self.assertEquals(invoice.get('items')[1].get('item_code'), 'Food Item 2') + self.assertEquals(invoice.get('net_total'), 4600) + + return table + + def test_billing(self): + table = self.test_update_order() + invoice_name = make_invoice(table, '_Test Customer', 'Cash') + + sales_invoice = frappe.get_doc('Sales Invoice', invoice_name) + + self.assertEquals(sales_invoice.grand_total, 4600) + self.assertEquals(sales_invoice.items[0].item_code, 'Food Item 1') + self.assertEquals(sales_invoice.items[1].item_code, 'Food Item 2') + self.assertEquals(sales_invoice.payments[0].mode_of_payment, 'Cash') + self.assertEquals(sales_invoice.payments[0].amount, 4600) + + def test_item_query(self): + table = frappe.db.get_value('Restaurant Table', dict(restaurant = 'Test Restaurant 1')) + result = item_query_restaurant(filters=dict(table=table)) + items = [d[0] for d in result] + self.assertTrue('Food Item 1' in items) + self.assertTrue('_Test Item 1' not in items) diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/__init__.py b/erpnext/restaurant/doctype/restaurant_order_entry_item/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.json b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.json new file mode 100644 index 00000000000..0240013c784 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.json @@ -0,0 +1,163 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2017-09-15 15:11:50.313241", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "item", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Item", + "length": 0, + "no_copy": 0, + "options": "Item", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "qty", + "fieldtype": "Int", + "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": "Qty", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "served", + "fieldtype": "Int", + "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": "Served", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "rate", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Rate", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2017-09-21 08:39:27.232175", + "modified_by": "Administrator", + "module": "Restaurant", + "name": "Restaurant Order Entry Item", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Hospitality", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py new file mode 100644 index 00000000000..e0c051b1ad7 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class RestaurantOrderEntryItem(Document): + pass diff --git a/erpnext/restaurant/doctype/restaurant_reservation/__init__.py b/erpnext/restaurant/doctype/restaurant_reservation/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js new file mode 100644 index 00000000000..92183384d39 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js @@ -0,0 +1,8 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Restaurant Reservation', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json new file mode 100644 index 00000000000..6a2ffa13277 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json @@ -0,0 +1,337 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "REST.######", + "beta": 0, + "creation": "2017-09-15 13:05:51.063661", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "status", + "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": "Status", + "length": 0, + "no_copy": 0, + "options": "Open\nWaitlisted\nCancelled\nNo Show\nSuccess", + "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": "restaurant", + "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": "Restaurant", + "length": 0, + "no_copy": 0, + "options": "Restaurant", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "no_of_people", + "fieldtype": "Int", + "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": "No of People", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reservation_time", + "fieldtype": "Datetime", + "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": "Reservation Time", + "length": 0, + "no_copy": 0, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "reservation_end_time", + "fieldtype": "Datetime", + "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": "Reservation End Time", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_4", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "customer", + "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": "Customer", + "length": 0, + "no_copy": 0, + "options": "Customer", + "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": "customer_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Customer Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "contact_number", + "fieldtype": "Data", + "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": "Contact Number", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-09-15 14:40:56.759315", + "modified_by": "Administrator", + "module": "Restaurant", + "name": "Restaurant Reservation", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Restaurant Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Hospitality", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py new file mode 100644 index 00000000000..63a36f0a6d2 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document +from datetime import timedelta +from frappe.utils import get_datetime + +class RestaurantReservation(Document): + def validate(self): + if not self.reservation_end_time: + self.reservation_end_time = get_datetime(self.reservation_time) + timedelta(hours=1) + +@frappe.whitelist() +def get_events(start, end, filters=None): + """Returns events for Gantt / Calendar view rendering. + + :param start: Start date-time. + :param end: End date-time. + :param filters: Filters (JSON). + """ + from frappe.desk.calendar import get_event_conditions + conditions = get_event_conditions("Restaurant Reservation", filters) + + data = frappe.db.sql("""select name, reservation_time, + reservation_end_time, customer_name, status, no_of_people + from + `tabRestaurant Reservation` + where + ((ifnull(reservation_time, '0000-00-00')!= '0000-00-00') \ + and (reservation_time <= %(end)s) \ + or ((ifnull(reservation_end_time, '0000-00-00')!= '0000-00-00') \ + and reservation_end_time >= %(start)s)) + {conditions}""".format(conditions=conditions), { + "start": start, + "end": end + }, as_dict=True, update={"allDay": 0}) + + return data diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js new file mode 100644 index 00000000000..09e8f8d937b --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js @@ -0,0 +1,18 @@ +frappe.views.calendar["Restaurant Reservation"] = { + field_map: { + "start": "reservation_time", + "end": "reservation_end_time", + "id": "name", + "title": "customer_name", + "allDay": "allDay", + }, + gantt: true, + filters: [ + { + "fieldtype": "Data", + "fieldname": "customer_name", + "label": __("Customer Name") + } + ], + get_events_method: "erpnext.restaurant.doctype.restaurant_reservation.restaurant_reservation.get_events" +}; diff --git a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.js b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.js new file mode 100644 index 00000000000..eeea5a9f0b2 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.js @@ -0,0 +1,27 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Restaurant Reservation", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Restaurant Reservation + () => frappe.tests.make('Restaurant Reservation', [ + // values to be set + {restaurant: 'Gokul - JP Nagar'}, + {customer_name: 'test customer'}, + {reservation_time: frappe.datetime.now_date() + " 19:00:00"}, + {no_of_people: 4}, + ]), + () => { + assert.equal(cur_frm.doc.reservation_end_time, + frappe.datetime.now_date() + ' 20:00:00'); + }, + () => done() + ]); + +}); diff --git a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py new file mode 100644 index 00000000000..71681b2f183 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestRestaurantReservation(unittest.TestCase): + pass diff --git a/erpnext/restaurant/doctype/restaurant_table/__init__.py b/erpnext/restaurant/doctype/restaurant_table/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js new file mode 100644 index 00000000000..a55605c90bf --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js @@ -0,0 +1,8 @@ +// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Restaurant Table', { + refresh: function(frm) { + + } +}); diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json new file mode 100644 index 00000000000..da1bcde4046 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json @@ -0,0 +1,156 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "", + "beta": 0, + "creation": "2017-09-15 12:45:24.717355", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "restaurant", + "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": "Restaurant", + "length": 0, + "no_copy": 0, + "options": "Restaurant", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "no_of_seats", + "fieldtype": "Int", + "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": "No of Seats", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "1", + "fieldname": "minimum_seating", + "fieldtype": "Int", + "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": "Minimum Seating", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2017-09-15 13:18:05.254106", + "modified_by": "Administrator", + "module": "Restaurant", + "name": "Restaurant Table", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Restaurant Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Hospitality", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py new file mode 100644 index 00000000000..d5ea9d53981 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe, re +from frappe.model.document import Document +from frappe.model.naming import make_autoname + +class RestaurantTable(Document): + def autoname(self): + prefix = re.sub('-+', '-', self.restaurant.replace(' ', '-')) + self.name = make_autoname(prefix + '-.##') diff --git a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.js b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.js new file mode 100644 index 00000000000..16035f0c892 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.js @@ -0,0 +1,41 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Restaurant Table", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(0); + + frappe.run_serially([ + // insert a new Restaurant Table + () => frappe.tests.make('Restaurant Table', [ + // values to be set + {restaurant: 'Test Restaurant 1'}, + {no_of_seats: 4}, + ]), + () => frappe.tests.make('Restaurant Table', [ + // values to be set + {restaurant: 'Test Restaurant 1'}, + {no_of_seats: 5}, + ]), + () => frappe.tests.make('Restaurant Table', [ + // values to be set + {restaurant: 'Test Restaurant 1'}, + {no_of_seats: 2}, + ]), + () => frappe.tests.make('Restaurant Table', [ + // values to be set + {restaurant: 'Test Restaurant 1'}, + {no_of_seats: 2}, + ]), + () => frappe.tests.make('Restaurant Table', [ + // values to be set + {restaurant: 'Test Restaurant 1'}, + {no_of_seats: 6}, + ]), + () => done() + ]); + +}); diff --git a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py new file mode 100644 index 00000000000..ffdb6f742a3 --- /dev/null +++ b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +test_records = [ + dict(restaurant='Test Restaurant 1', no_of_seats=5, minimum_seating=1), + dict(restaurant='Test Restaurant 1', no_of_seats=5, minimum_seating=1), + dict(restaurant='Test Restaurant 1', no_of_seats=5, minimum_seating=1), + dict(restaurant='Test Restaurant 1', no_of_seats=5, minimum_seating=1), +] + +class TestRestaurantTable(unittest.TestCase): + pass diff --git a/erpnext/schools/doctype/fees/fees.py b/erpnext/schools/doctype/fees/fees.py index a2fcecc0aa5..bfe6af4bdbb 100644 --- a/erpnext/schools/doctype/fees/fees.py +++ b/erpnext/schools/doctype/fees/fees.py @@ -50,6 +50,7 @@ class Fees(AccountsController): select g.email_address from `tabGuardian` g, `tabStudent Guardian` sg where g.name = sg.guardian and sg.parent = %s and sg.parenttype = 'Student' + and ifnull(g.email_address, '')!='' """, self.student) student_email_id = frappe.db.get_value("Student", self.student, "student_email_id") @@ -111,7 +112,7 @@ def get_fee_list(doctype, txt, filters, limit_start, limit_page_length=20, order user = frappe.session.user student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user) if student: - return frappe. db.sql('''select name, program, due_date, paid_amount, outstanding_amount, total_amount from `tabFees` + return frappe. db.sql('''select name, program, due_date, paid_amount, outstanding_amount, grand_total from `tabFees` where student= %s and docstatus=1 order by due_date asc limit {0} , {1}''' .format(limit_start, limit_page_length), student, as_dict = True) diff --git a/erpnext/schools/doctype/student_admission/student_admission.json b/erpnext/schools/doctype/student_admission/student_admission.json index 4801e511637..c35d5be3932 100644 --- a/erpnext/schools/doctype/student_admission/student_admission.json +++ b/erpnext/schools/doctype/student_admission/student_admission.json @@ -1,6 +1,6 @@ { "allow_copy": 0, - "allow_guest_to_view": 0, + "allow_guest_to_view": 1, "allow_import": 0, "allow_rename": 1, "autoname": "", @@ -12,97 +12,6 @@ "document_type": "Document", "editable_grid": 1, "fields": [ - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "academic_year", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Academic Year", - "length": 0, - "no_copy": 0, - "options": "Academic Year", - "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "admission_start_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": "Admission Start 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, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "admission_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": "Admission End 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, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -139,7 +48,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "naming_series_for_student_applicant", + "depends_on": "", + "fieldname": "route", "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, @@ -148,9 +58,9 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Naming Series (for Student Applicant)", + "label": "Route", "length": 0, - "no_copy": 0, + "no_copy": 1, "permlevel": 0, "precision": "", "print_hide": 0, @@ -161,7 +71,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "unique": 0 + "unique": 1 }, { "allow_bulk_edit": 0, @@ -169,8 +79,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "publish", - "fieldtype": "Check", + "fieldname": "application_form_route", + "fieldtype": "Data", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -178,7 +88,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Publish on website", + "label": "Application Form Route", "length": 0, "no_copy": 0, "permlevel": 0, @@ -188,7 +98,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -228,112 +138,19 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "program", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Program", - "length": 0, - "no_copy": 0, - "options": "Program", - "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": "application_fee", - "fieldtype": "Currency", - "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": "Application Fee", - "length": 0, - "no_copy": 0, - "options": "currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 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": "currency", + "fieldname": "academic_year", "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": "Currency", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Academic Year", "length": 0, - "no_copy": 0, - "options": "Currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 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": "", - "fieldname": "route", - "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": "Route", - "length": 0, - "no_copy": 0, + "no_copy": 1, + "options": "Academic Year", "permlevel": 0, "precision": "", "print_hide": 0, @@ -344,7 +161,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, - "unique": 1 + "unique": 0 }, { "allow_bulk_edit": 0, @@ -352,8 +169,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "application_form_route", - "fieldtype": "Data", + "fieldname": "admission_start_date", + "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -361,7 +178,67 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Application Form Route", + "label": "Admission Start Date", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 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": "admission_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": "Admission End Date", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 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": "published", + "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": "Publish on website", "length": 0, "no_copy": 0, "permlevel": 0, @@ -391,6 +268,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, + "label": "Eligibility and Details", "length": 0, "no_copy": 0, "permlevel": 0, @@ -405,6 +283,37 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "program_details", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Eligibility and Details", + "length": 0, + "no_copy": 0, + "options": "Student Admission Program", + "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, @@ -434,49 +343,20 @@ "search_index": 0, "set_only_once": 0, "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "eligibility", - "fieldtype": "Text Editor", - "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": "Eligibility", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 } ], - "has_web_view": 0, + "has_web_view": 1, "hide_heading": 0, "hide_toolbar": 0, "idx": 0, "image_view": 0, "in_create": 0, + "is_published_field": "published", "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-06-30 08:21:50.722286", + "modified": "2017-10-02 15:16:44.386000", "modified_by": "Administrator", "module": "Schools", "name": "Student Admission", @@ -504,10 +384,11 @@ "write": 1 } ], - "quick_entry": 1, + "quick_entry": 0, "read_only": 0, "read_only_onload": 0, "restrict_to_domain": "Education", + "route": "admissions", "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/schools/doctype/student_admission/student_admission.py b/erpnext/schools/doctype/student_admission/student_admission.py index a849d65d7b6..e166b9b5e80 100644 --- a/erpnext/schools/doctype/student_admission/student_admission.py +++ b/erpnext/schools/doctype/student_admission/student_admission.py @@ -4,26 +4,41 @@ from __future__ import unicode_literals import frappe -from frappe.website.website_generator import WebsiteGenerator from frappe import _ +from frappe.utils import nowdate +from frappe.website.website_generator import WebsiteGenerator + class StudentAdmission(WebsiteGenerator): - website = frappe._dict( - template = "templates/generators/student_admission.html", - condition_field = "publish", - page_title_field = "title" - ) - def autoname(self): if not self.title: self.title = self.get_title() self.name = self.title + def validate(self): + if not self.route: #pylint: disable=E0203 + self.route = "admissions/" + "-".join(self.title.split(" ")) + def get_context(self, context): - context.parents = [{'name': 'admissions', 'title': _('All Student Admissions') }] + context.no_cache = 1 + context.show_sidebar = True + context.title = self.title + context.parents = [{'name': 'admissions', 'title': _('All Student Admissions'), 'route': 'admissions' }] def get_title(self): return _("Admissions for {0}").format(self.academic_year) -def get_list_context(context): - context.title = _("Student Admissions") + +def get_list_context(context=None): + context.update({ + "show_sidebar": True, + "title": _("Student Admissions"), + "get_list": get_admission_list, + "row_template": "schools/doctype/student_admission/templates/student_admission_row.html", + }) + +def get_admission_list(doctype, txt, filters, limit_start, limit_page_length=20, order_by="modified"): + return frappe.db.sql('''select name, title, academic_year, modified, admission_start_date, route, + admission_end_date from `tabStudent Admission` where published=1 and admission_end_date >= %s + order by admission_end_date asc limit {0}, {1} + '''.format(limit_start, limit_page_length), [nowdate()], as_dict=1) diff --git a/erpnext/schools/doctype/student_admission/templates/student_admission.html b/erpnext/schools/doctype/student_admission/templates/student_admission.html new file mode 100644 index 00000000000..25afaca84dc --- /dev/null +++ b/erpnext/schools/doctype/student_admission/templates/student_admission.html @@ -0,0 +1,74 @@ + +{% extends "templates/web.html" %} + +{% block breadcrumbs %} + {% include "templates/includes/breadcrumbs.html" %} +{% endblock %} + +{% block header %} +

{{ title }}

+{% endblock %} + +{% block page_content %} + {% set today = frappe.utils.getdate(frappe.utils.nowdate()) %} +
+
+ Application will be closed soon + {% elif frappe.utils.getdate(doc.admission_end_date) > today >= frappe.utils.getdate(doc.admission_start_date)%} + green"> Application open + {% elif frappe.utils.getdate(doc.admission_start_date) > today %} + blue"> Application will open + {% else %} + darkgrey + {% endif %} + +
+
+ {{ _("Start on") }}: {{ frappe.format_date(admission_start_date) }}
+ {{ _("End on") }}: {{ frappe.format_date(admission_end_date) }} +
+

+ + {%- if introduction -%} +
{{ introduction }}
+ {% endif %} + + {% if program_details %} +
+
+

Eligibility and Other Details:

+ + + + + + + + + + + {% for row in program_details %} + + + + + + + {% endfor %} + +
Program/Std.Minumum Age(DOB)Maximum Age(DOB)Application Fee
{{ row.program }}{{ row.minimum_age }}{{ row.maximum_age }}{{ row.application_fee }}
+
+ {% endif %} + + {%- if application_form_route -%} +
+

+ + {{ _("Apply Now") }} +

+ {% endif %} + +{% endblock %} diff --git a/erpnext/schools/doctype/student_admission/templates/student_admission_row.html b/erpnext/schools/doctype/student_admission/templates/student_admission_row.html new file mode 100644 index 00000000000..e0497730377 --- /dev/null +++ b/erpnext/schools/doctype/student_admission/templates/student_admission_row.html @@ -0,0 +1,36 @@ + \ No newline at end of file diff --git a/erpnext/schools/doctype/student_admission/test_student_admission.js b/erpnext/schools/doctype/student_admission/test_student_admission.js index 0d7c997adb6..767f237f959 100644 --- a/erpnext/schools/doctype/student_admission/test_student_admission.js +++ b/erpnext/schools/doctype/student_admission/test_student_admission.js @@ -2,7 +2,7 @@ QUnit.module('schools'); QUnit.test('Test: Student Admission', function(assert) { - assert.expect(9); + assert.expect(10); let done = assert.async(); frappe.run_serially([ () => { @@ -11,23 +11,29 @@ QUnit.test('Test: Student Admission', function(assert) { {admission_start_date: '2016-04-20'}, {admission_end_date: '2016-05-31'}, {title: '2016-17 Admissions'}, - {program: 'Standard Test'}, - {application_fee: 1000}, - {naming_series_for_student_applicant: 'AP'}, + {application_form_route: 'student-applicant'}, {introduction: 'Test intro'}, - {eligibility: 'Test eligibility'} + {program_details: [ + [ + {'program': 'Standard Test'}, + {'application_fee': 1000}, + {'applicant_naming_series': 'AP'}, + ] + ]} ]); }, + () => cur_frm.save(), () => { assert.ok(cur_frm.doc.academic_year == '2016-17'); assert.ok(cur_frm.doc.admission_start_date == '2016-04-20'); assert.ok(cur_frm.doc.admission_end_date == '2016-05-31'); assert.ok(cur_frm.doc.title == '2016-17 Admissions'); - assert.ok(cur_frm.doc.program == 'Standard Test', 'Program correctly selected'); - assert.ok(cur_frm.doc.application_fee == 1000); - assert.ok(cur_frm.doc.naming_series_for_student_applicant == 'AP'); + assert.ok(cur_frm.doc.application_form_route == 'student-applicant'); assert.ok(cur_frm.doc.introduction == 'Test intro'); - assert.ok(cur_frm.doc.eligibility == 'Test eligibility'); + assert.ok(cur_frm.doc.program_details[0].program == 'Standard Test', 'Program correctly selected'); + assert.ok(cur_frm.doc.program_details[0].application_fee == 1000); + assert.ok(cur_frm.doc.program_details[0].applicant_naming_series == 'AP'); + assert.ok(cur_frm.doc.route == 'admissions/2016-17-Admissions', "Route successfully set"); }, () => done() ]); diff --git a/erpnext/schools/doctype/student_admission_program/__init__.py b/erpnext/schools/doctype/student_admission_program/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/schools/doctype/student_admission_program/student_admission_program.json b/erpnext/schools/doctype/student_admission_program/student_admission_program.json new file mode 100644 index 00000000000..29bb57fbd5f --- /dev/null +++ b/erpnext/schools/doctype/student_admission_program/student_admission_program.json @@ -0,0 +1,222 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "", + "beta": 0, + "creation": "2017-09-15 12:59:43.207923", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "program", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Program", + "length": 0, + "no_copy": 0, + "options": "Program", + "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": "minimum_age", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Minimum Age", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "maximum_age", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Maximum Age", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_4", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "application_fee", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Application Fee", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "applicant_naming_series", + "fieldtype": "Data", + "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": "Naming Series (for Student Applicant)", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 1, + "max_attachments": 0, + "modified": "2017-10-02 17:13:52.586218", + "modified_by": "Administrator", + "module": "Schools", + "name": "Student Admission Program", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/schools/doctype/student_admission_program/student_admission_program.py b/erpnext/schools/doctype/student_admission_program/student_admission_program.py new file mode 100644 index 00000000000..406027ca2cb --- /dev/null +++ b/erpnext/schools/doctype/student_admission_program/student_admission_program.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from frappe.model.document import Document + +class StudentAdmissionProgram(Document): + pass diff --git a/erpnext/schools/doctype/student_applicant/student_applicant.py b/erpnext/schools/doctype/student_applicant/student_applicant.py index 081fa065db8..465b4e474ab 100644 --- a/erpnext/schools/doctype/student_applicant/student_applicant.py +++ b/erpnext/schools/doctype/student_applicant/student_applicant.py @@ -6,14 +6,18 @@ from __future__ import print_function, unicode_literals import frappe from frappe import _ from frappe.model.document import Document +from frappe.utils import getdate class StudentApplicant(Document): def autoname(self): from frappe.model.naming import set_name_by_naming_series if self.student_admission: - naming_series = frappe.db.get_value('Student Admission', self.student_admission, - 'naming_series_for_student_applicant') - print(naming_series) + if self.program: + student_admission = get_student_admission_data(self.student_admission, self.program) + if student_admission: + naming_series = student_admission.get("applicant_naming_series") + else: + frappe.throw(_("Select the program first")) if naming_series: self.naming_series = naming_series @@ -22,11 +26,40 @@ class StudentApplicant(Document): def validate(self): self.title = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name])) + if self.student_admission and self.program and self.date_of_birth: + self.validation_from_student_admission() def on_update_after_submit(self): student = frappe.get_list("Student", filters= {"student_applicant": self.name}) if student: frappe.throw(_("Cannot change status as student {0} is linked with student application {1}").format(student[0].name, self.name)) + def on_submit(self): + if self.paid and not self.student_admission: + frappe.throw(_("Please select Student Admission which is mandatory for the paid student applicant")) + + def validation_from_student_admission(self): + student_admission = get_student_admission_data(self.student_admission, self.program) + if student_admission: + if (( + student_admission.minimum_age + and getdate(student_admission.minimum_age) > getdate(self.date_of_birth) + ) or ( + student_admission.maximum_age + and getdate(student_admission.maximum_age) < getdate(self.date_of_birth) + )): + frappe.throw(_("Not eligible for the admission in this program as per DOB")) + def on_payment_authorized(self, *args, **kwargs): self.db_set('paid', 1) + + +def get_student_admission_data(student_admission, program): + student_admission = frappe.db.sql("""select sa.admission_start_date, sa.admission_end_date, + sap.program, sap.minimum_age, sap.maximum_age, sap.applicant_naming_series + from `tabStudent Admission` sa, `tabStudent Admission Program` sap + where sa.name = sap.parent and sa.name = %s and sap.program = %s""", (student_admission, program), as_dict=1) + if student_admission: + return student_admission[0] + else: + return None diff --git a/erpnext/schools/doctype/student_group/test_student_group.js b/erpnext/schools/doctype/student_group/test_student_group.js index 634ad18254d..bee5067d9b8 100644 --- a/erpnext/schools/doctype/student_group/test_student_group.js +++ b/erpnext/schools/doctype/student_group/test_student_group.js @@ -4,15 +4,10 @@ QUnit.module('schools'); QUnit.test('Test: Student Group', function(assert){ assert.expect(2); let done = assert.async(); - let instructor_code; let group_based_on = ["test-batch-wise-group", "test-course-wise-group"]; let tasks = []; frappe.run_serially([ - // Saving Instructor code beforehand - () => frappe.db.get_value('Instructor', {'instructor_name': 'Instructor 1'}, 'name'), - (instructor) => {instructor_code = instructor.message.name;}, - // Creating a Batch and Course based group () => { return frappe.tests.make('Student Group', [ @@ -22,12 +17,7 @@ QUnit.test('Test: Student Group', function(assert){ {group_based_on: 'Batch'}, {student_group_name: group_based_on[0]}, {max_strength: 10}, - {batch: 'A'}, - {instructors: [ - [ - {instructor: instructor_code} - ] - ]} + {batch: 'A'} ]); }, () => { @@ -40,11 +30,6 @@ QUnit.test('Test: Student Group', function(assert){ {max_strength: 10}, {batch: 'A'}, {course: 'Test_Sub'}, - {instructors: [ - [ - {instructor: instructor_code} - ] - ]} ]); }, diff --git a/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.py b/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.py index 2b407c7987c..9bdf621a611 100644 --- a/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.py +++ b/erpnext/schools/report/course_wise_assessment_report/course_wise_assessment_report.py @@ -172,20 +172,19 @@ def get_column(assessment_criteria, total_maximum_score): def get_chart_data(grades, assessment_criteria_list, kounter): grades = sorted(grades) - chart_data = [] - chart_data.append(["x"] + assessment_criteria_list) + datasets = [] for grade in grades: - tmp = [grade] + tmp = [] for ac in assessment_criteria_list: if grade in kounter[ac]: tmp.append(kounter[ac][grade]) else: tmp.append(0) - chart_data.append(tmp) + datasets.append(tmp) return { "data": { - "x": "x", - "columns": chart_data + "labels": assessment_criteria_list, + "datasets": datasets }, - "chart_type": 'bar', + "type": 'bar', } diff --git a/erpnext/schools/report/student_fee_collection/student_fee_collection.json b/erpnext/schools/report/student_fee_collection/student_fee_collection.json index 264638f8216..5c63765cf8f 100644 --- a/erpnext/schools/report/student_fee_collection/student_fee_collection.json +++ b/erpnext/schools/report/student_fee_collection/student_fee_collection.json @@ -5,14 +5,14 @@ "disabled": 0, "docstatus": 0, "doctype": "Report", - "idx": 2, + "idx": 3, "is_standard": "Yes", - "modified": "2017-02-24 20:05:08.514320", + "modified": "2017-10-25 11:59:26.003899", "modified_by": "Administrator", "module": "Schools", "name": "Student Fee Collection", "owner": "Administrator", - "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(paid_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(total_amount) as \"Total Amount:Currency:150\"\nFROM\n `tabFees` \nGROUP BY\n student", + "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(paid_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(grand_total) as \"Grand Total:Currency:150\"\nFROM\n `tabFees` \nGROUP BY\n student", "ref_doctype": "Fees", "report_name": "Student Fee Collection", "report_type": "Query Report", diff --git a/erpnext/selling/doctype/installation_note/installation_note.py b/erpnext/selling/doctype/installation_note/installation_note.py index 720247da56b..9f730f4878c 100644 --- a/erpnext/selling/doctype/installation_note/installation_note.py +++ b/erpnext/selling/doctype/installation_note/installation_note.py @@ -12,8 +12,8 @@ from erpnext.stock.utils import get_valid_serial_nos from erpnext.utilities.transaction_base import TransactionBase class InstallationNote(TransactionBase): - def __init__(self, arg1, arg2=None): - super(InstallationNote, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(InstallationNote, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Installation Note Item', 'target_dt': 'Delivery Note Item', diff --git a/erpnext/selling/doctype/product_bundle/product_bundle.json b/erpnext/selling/doctype/product_bundle/product_bundle.json index 5a1aeb4eb5c..b63fb4bdcfc 100644 --- a/erpnext/selling/doctype/product_bundle/product_bundle.json +++ b/erpnext/selling/doctype/product_bundle/product_bundle.json @@ -1,5 +1,6 @@ { "allow_copy": 0, + "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 0, "beta": 0, @@ -12,6 +13,7 @@ "editable_grid": 0, "fields": [ { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -40,6 +42,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -72,6 +75,37 @@ "unique": 0 }, { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "description", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Description", + "length": 0, + "no_copy": 0, + "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, @@ -101,6 +135,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -132,6 +167,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -160,6 +196,7 @@ "unique": 0 }, { + "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, @@ -190,19 +227,19 @@ "unique": 0 } ], + "has_web_view": 0, "hide_heading": 0, "hide_toolbar": 0, "icon": "fa fa-sitemap", "idx": 1, "image_view": 0, "in_create": 0, - "in_dialog": 0, "is_submittable": 0, "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-02-22 05:06:30.143089", - "modified_by": "Administrator", + "modified": "2017-10-18 14:23:06.538568", + "modified_by": "tundebabzy@gmail.com", "module": "Selling", "name": "Product Bundle", "owner": "Administrator", diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 1cdd8404288..f0cce5ffb7c 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -32,7 +32,7 @@ class Quotation(SellingController): self.validate_valid_till() if self.items: self.with_items = 1 - + def validate_valid_till(self): if self.valid_till and self.valid_till < self.transaction_date: frappe.throw(_("Valid till date cannot be before transaction date")) @@ -79,15 +79,10 @@ class Quotation(SellingController): else: frappe.throw(_("Cannot set as Lost as Sales Order is made.")) - def check_item_table(self): - if not self.get('items'): - frappe.throw(_("Please enter item details")) - def on_submit(self): - self.check_item_table() - # Check for Approving Authority - frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.base_grand_total, self) + frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, + self.company, self.base_grand_total, self) #update enquiry status self.update_opportunity() diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js index 00d2121897a..6f70ebe07e7 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.js +++ b/erpnext/selling/doctype/sales_order/sales_order.js @@ -92,7 +92,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( // delivery note if(flt(doc.per_delivered, 2) < 100 && ["Sales", "Shopping Cart"].indexOf(doc.order_type)!==-1 && allow_delivery) { this.frm.add_custom_button(__('Delivery'), - function() { me.make_delivery_note_based_on_delivery_note(); }, __("Make")); + function() { me.make_delivery_note_based_on_delivery_date(); }, __("Make")); this.frm.add_custom_button(__('Production Order'), function() { me.make_production_order() }, __("Make")); @@ -270,7 +270,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( }) }, - make_delivery_note_based_on_delivery_note: function() { + make_delivery_note_based_on_delivery_date: function() { var me = this; var delivery_dates = []; diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index b57895ad7ce..36f1284c43a 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -3272,419 +3272,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": 0, - "options": "Subscription", - "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": 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": "settings", - "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, - "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": 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 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": "\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": "Recurring Upto", - "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", @@ -3715,7 +3309,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "is_recurring", + "depends_on": "", "description": "", "fieldname": "to_date", "fieldtype": "Date", @@ -3746,10 +3340,8 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "is_recurring", - "description": "", - "fieldname": "next_date", - "fieldtype": "Date", + "fieldname": "column_break_108", + "fieldtype": "Column Break", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -3757,11 +3349,42 @@ "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, + "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": "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": 0, + "options": "Subscription", + "permlevel": 0, + "precision": "", + "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, "remember_last_selected_value": 0, @@ -3783,7 +3406,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-09-19 11:21:36.332326", + "modified": "2017-10-24 12:52:28.115742", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order", diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 8720482549d..fa21a3d7ee4 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe import json import frappe.utils -from frappe.utils import cstr, flt, getdate, comma_and, cint +from frappe.utils import cstr, flt, getdate, comma_and, cint, nowdate, add_days from frappe import _ from frappe.model.utils import get_fetch_values from frappe.model.mapper import get_mapped_doc @@ -22,8 +22,8 @@ form_grid_templates = { class WarehouseRequired(frappe.ValidationError): pass class SalesOrder(SellingController): - def __init__(self, arg1, arg2=None): - super(SalesOrder, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(SalesOrder, self).__init__(*args, **kwargs) def validate(self): super(SalesOrder, self).validate() @@ -347,15 +347,15 @@ class SalesOrder(SellingController): return items def on_recurring(self, reference_doc, subscription_doc): - self.set("delivery_date", get_next_schedule_date(reference_doc.delivery_date, subscription_doc.frequency, - cint(subscription_doc.repeat_on_day))) + self.set("delivery_date", get_next_schedule_date(reference_doc.delivery_date, + subscription_doc.frequency, cint(subscription_doc.repeat_on_day))) for d in self.get("items"): reference_delivery_date = frappe.db.get_value("Sales Order Item", {"parent": reference_doc.name, "item_code": d.item_code, "idx": d.idx}, "delivery_date") - d.set("delivery_date", - get_next_schedule_date(reference_delivery_date, subscription_doc.frequency, cint(subscription_doc.repeat_on_day))) + d.set("delivery_date", get_next_schedule_date(reference_delivery_date, + subscription_doc.frequency, cint(subscription_doc.repeat_on_day))) def get_list_context(context=None): from erpnext.controllers.website_list_for_contact import get_list_context @@ -696,7 +696,8 @@ def make_purchase_order_for_drop_shipment(source_name, for_supplier, target_doc= "contact_display", "contact_mobile", "contact_email", - "contact_person" + "contact_person", + "taxes_and_charges" ], "validation": { "docstatus": ["=", 1] diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js index a8093fd4f19..6f1cd9ff5ea 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.js +++ b/erpnext/selling/page/point_of_sale/point_of_sale.js @@ -48,12 +48,14 @@ erpnext.pos.PointOfSale = class PointOfSale { this.prepare_menu(); this.set_online_status(); }, + () => this.setup_company(), () => this.setup_pos_profile(), + () => this.make_new_invoice(), () => { + frappe.timeout(1); this.make_items(); this.bind_events(); }, - () => this.make_new_invoice(), () => this.page.set_title(__('Point of Sale')) ]); } @@ -89,6 +91,7 @@ erpnext.pos.PointOfSale = class PointOfSale { this.cart = new POSCart({ frm: this.frm, wrapper: this.wrapper.find('.cart-container'), + pos_profile: this.pos_profile, events: { on_customer_change: (customer) => this.frm.set_value('customer', customer), on_field_change: (item_code, field, value) => { @@ -98,12 +101,21 @@ erpnext.pos.PointOfSale = class PointOfSale { if (value == 'Pay') { if (!this.payment) { this.make_payment_modal(); + } else { + this.frm.doc.payments.map(p => { + this.payment.dialog.set_value(p.mode_of_payment, p.amount); + }); + + this.payment.set_title(); } this.payment.open_modal(); } }, on_select_change: () => { this.cart.numpad.set_inactive(); + }, + get_item_details: (item_code) => { + return this.items.get(item_code); } } }); @@ -196,6 +208,9 @@ erpnext.pos.PointOfSale = class PointOfSale { this.update_item_in_frm(item) .then(() => { // update cart + if (item.qty === 0) { + frappe.model.clear_doc(item.doctype, item.name); + } this.update_cart_data(item); }); }, true); @@ -208,17 +223,24 @@ erpnext.pos.PointOfSale = class PointOfSale { } update_item_in_frm(item, field, value) { - if (field) { - frappe.model.set_value(item.doctype, item.name, field, value); + if (field == 'qty' && value < 0) { + frappe.msgprint(__("Quantity must be positive")); + value = item.qty; } - return this.frm.script_manager - .trigger('qty', item.doctype, item.name) - .then(() => { - if (field === 'qty' && value === 0) { - frappe.model.clear_doc(item.doctype, item.name); - } - }); + if (field) { + return frappe.model.set_value(item.doctype, item.name, field, value) + .then(() => this.frm.script_manager.trigger('qty', item.doctype, item.name)) + .then(() => { + console.log(item.qty, item.amount); + + if (field === 'qty' && item.qty === 0) { + frappe.model.clear_doc(item.doctype, item.name); + } + }) + } + + return Promise.resolve(); } make_payment_modal() { @@ -268,11 +290,12 @@ erpnext.pos.PointOfSale = class PointOfSale { this.pos_profile = doc; if (!this.pos_profile) { - this.pos_profile = { - currency: frappe.defaults.get_default('currency'), - selling_price_list: frappe.defaults.get_default('selling_price_list') - }; - } + this.pos_profile = { + company: this.company, + currency: frappe.defaults.get_default('currency'), + selling_price_list: frappe.defaults.get_default('selling_price_list') + }; + } resolve(); }); @@ -313,6 +336,21 @@ erpnext.pos.PointOfSale = class PointOfSale { } }); }); + } + + setup_company() { + this.company = frappe.sys_defaults.company; + return new Promise(resolve => { + if(!this.company) { + frappe.prompt({fieldname:"company", options: "Company", fieldtype:"Link", + label: __("Select Company"), reqd: 1}, (data) => { + this.company = data.company; + resolve(this.company); + }, __("Select Company")); + } else { + resolve(this.company); + } + }) } make_new_invoice() { @@ -334,22 +372,25 @@ erpnext.pos.PointOfSale = class PointOfSale { const doctype = 'Sales Invoice'; return new Promise(resolve => { if (this.frm) { - this.frm = get_frm(this.frm); + this.frm = get_frm(this.pos_profile, this.frm); resolve(); } else { frappe.model.with_doctype(doctype, () => { - this.frm = get_frm(); + this.frm = get_frm(this.pos_profile); resolve(); }); } }); - function get_frm(_frm) { + function get_frm(pos_profile, _frm) { const page = $('
'); const frm = _frm || new _f.Frm(doctype, page, false); const name = frappe.model.make_new_doc_and_get_name(doctype, true); frm.refresh(name); frm.doc.items = []; + if(!frm.doc.company) { + frm.set_value('company', pos_profile.company); + } frm.set_value('is_pos', 1); frm.meta.default_print_format = 'POS Invoice'; return frm; @@ -400,10 +441,12 @@ erpnext.pos.PointOfSale = class PointOfSale { }; class POSCart { - constructor({frm, wrapper, events}) { + constructor({frm, wrapper, pos_profile, events}) { this.frm = frm; + this.item_data = {}; this.wrapper = wrapper; this.events = events; + this.pos_profile = pos_profile; this.make(); this.bind_events(); } @@ -465,6 +508,12 @@ class POSCart { this.$taxes_and_totals.html(this.get_taxes_and_totals()); this.numpad && this.numpad.reset_value(); this.customer_field.set_value(""); + + this.wrapper.find('.grand-total-value').text( + format_currency(this.frm.doc.grand_total, this.frm.currency)); + + const customer = this.frm.doc.customer || this.pos_profile.customer; + this.customer_field.set_value(customer); } get_grand_total() { @@ -528,7 +577,7 @@ class POSCart { // Update totals this.$taxes_and_totals.find('.net-total') - .html(format_currency(this.frm.doc.net_total, currency)); + .html(format_currency(this.frm.doc.total, currency)); // Update taxes const taxes_html = this.frm.doc.taxes.map(tax => { @@ -551,6 +600,7 @@ class POSCart { } make_customer_field() { + let customer = this.frm.doc.customer || this.pos_profile['customer']; this.customer_field = frappe.ui.form.make_control({ df: { fieldtype: 'Link', @@ -558,7 +608,6 @@ class POSCart { fieldname: 'customer', options: 'Customer', reqd: 1, - default: this.frm.doc.customer, onchange: () => { this.events.on_customer_change(this.customer_field.get_value()); } @@ -566,6 +615,10 @@ class POSCart { parent: this.wrapper.find('.customer-field'), render_input: true }); + + if (customer) { + this.customer_field.set_value(customer); + } } make_numpad() { @@ -650,7 +703,8 @@ class POSCart { const $item = this.$cart_items.find(`[data-item-code="${item.item_code}"]`); if(item.qty > 0) { - const indicator_class = item.actual_qty >= item.qty ? 'green' : 'red'; + const is_stock_item = this.get_item_details(item.item_code).is_stock_item; + const indicator_class = (!is_stock_item || item.actual_qty >= item.qty) ? 'green' : 'red'; const remove_class = indicator_class == 'green' ? 'red' : 'green'; $item.find('.quantity input').val(item.qty); @@ -664,8 +718,9 @@ class POSCart { } get_item_html(item) { + const is_stock_item = this.get_item_details(item.item_code).is_stock_item; const rate = format_currency(item.rate, this.frm.doc.currency); - const indicator_class = item.actual_qty >= item.qty ? 'green' : 'red'; + const indicator_class = (!is_stock_item || item.actual_qty >= item.qty) ? 'green' : 'red'; return `
@@ -700,6 +755,14 @@ class POSCart { } } + get_item_details(item_code) { + if (!this.item_data[item_code]) { + this.item_data[item_code] = this.events.get_item_details(item_code); + } + + return this.item_data[item_code]; + } + exists(item_code) { let $item = this.$cart_items.find(`[data-item-code="${item_code}"]`); return $item.length > 0; @@ -770,28 +833,41 @@ class POSCart { // }); this.wrapper.find('.additional_discount_percentage').on('change', (e) => { + const discount_percentage = flt(e.target.value, + precision("additional_discount_percentage")); + frappe.model.set_value(this.frm.doctype, this.frm.docname, - 'additional_discount_percentage', e.target.value) + 'additional_discount_percentage', discount_percentage) .then(() => { let discount_wrapper = this.wrapper.find('.discount_amount'); - discount_wrapper.val(this.frm.doc.discount_amount); + discount_wrapper.val(flt(this.frm.doc.discount_amount, + precision('discount_amount'))); discount_wrapper.trigger('change'); }); }); this.wrapper.find('.discount_amount').on('change', (e) => { + const discount_amount = flt(e.target.value, precision('discount_amount')); frappe.model.set_value(this.frm.doctype, this.frm.docname, - 'discount_amount', flt(e.target.value)); + 'discount_amount', discount_amount); this.frm.trigger('discount_amount') .then(() => { - let discount_wrapper = this.wrapper.find('.additional_discount_percentage'); - discount_wrapper.val(this.frm.doc.additional_discount_percentage); + this.update_discount_fields(); this.update_taxes_and_totals(); this.update_grand_total(); }); }); } + update_discount_fields() { + let discount_wrapper = this.wrapper.find('.additional_discount_percentage'); + let discount_amt_wrapper = this.wrapper.find('.discount_amount'); + discount_wrapper.val(flt(this.frm.doc.additional_discount_percentage, + precision('additional_discount_percentage'))); + discount_amt_wrapper.val(flt(this.frm.doc.discount_amount, + precision('discount_amount'))); + } + set_selected_item($item) { this.selected_item = $item; this.$cart_items.find('.list-item').removeClass('current-item qty disc rate'); @@ -855,7 +931,7 @@ class POSItems { this.search_field = frappe.ui.form.make_control({ df: { fieldtype: 'Data', - label: 'Search Item (Ctrl + I)', + label: 'Search Item ( Ctrl + i )', placeholder: 'Search by item code, serial number, batch no or barcode' }, parent: this.wrapper.find('.search-field'), @@ -906,7 +982,7 @@ class POSItems { const all_items = Object.values(_items).map(item => this.get_item_html(item)); let row_items = []; - const row_container = '
'; + const row_container = '
'; let curr_row = row_container; for (let i=0; i < all_items.length; i++) { @@ -935,10 +1011,13 @@ class POSItems { this.search_index = this.search_index || {}; if (this.search_index[search_term]) { const items = this.search_index[search_term]; + this.items = items; this.render_items(items); + this.set_item_in_the_cart(items); return; } } else if (item_group == "All Item Groups") { + this.items = this.all_items; return this.render_items(this.all_items); } @@ -948,20 +1027,39 @@ class POSItems { this.search_index[search_term] = items; } + this.items = items; this.render_items(items); - if(serial_no) { - this.events.update_cart(items[0].item_code, - 'serial_no', serial_no); - this.search_field.set_value(''); - } - if(batch_no) { - this.events.update_cart(items[0].item_code, - 'batch_no', serial_no); - this.search_field.set_value(''); - } + this.set_item_in_the_cart(items, serial_no, batch_no); }); } + set_item_in_the_cart(items, serial_no, batch_no) { + if (serial_no) { + this.events.update_cart(items[0].item_code, + 'serial_no', serial_no); + this.reset_search_field(); + return; + } + + if (batch_no) { + this.events.update_cart(items[0].item_code, + 'batch_no', batch_no); + this.reset_search_field(); + return; + } + + if (items.length === 1) { + this.events.update_cart(items[0].item_code, + 'qty', '+1'); + this.reset_search_field(); + } + } + + reset_search_field() { + this.search_field.set_value(''); + this.search_field.$input.trigger("input"); + } + bind_events() { var me = this; this.wrapper.on('click', '.pos-item-wrapper', function() { @@ -972,7 +1070,14 @@ class POSItems { } get(item_code) { - return this.items[item_code]; + let item = {}; + this.items.map(data => { + if (data.item_code === item_code) { + item = data; + } + }) + + return item } get_all() { @@ -1154,16 +1259,13 @@ class Payment { make() { this.set_flag(); - - let title = __('Total Amount {0}', - [format_currency(this.frm.doc.grand_total, this.frm.doc.currency)]); - this.dialog = new frappe.ui.Dialog({ - title: title, fields: this.get_fields(), width: 800 }); + this.set_title(); + this.$body = this.dialog.body; this.numpad = new NumberPad({ @@ -1182,6 +1284,13 @@ class Payment { }); } + set_title() { + let title = __('Total Amount {0}', + [format_currency(this.frm.doc.grand_total, this.frm.doc.currency)]); + + this.dialog.set_title(title); + } + bind_events() { var me = this; $(this.dialog.body).find('.input-with-feedback').focusin(function() { diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py index d74f1f06e3d..20b5bb05b6a 100644 --- a/erpnext/selling/page/point_of_sale/point_of_sale.py +++ b/erpnext/selling/page/point_of_sale/point_of_sale.py @@ -9,6 +9,8 @@ from frappe.utils.nestedset import get_root_of def get_items(start, page_length, price_list, item_group, search_value=""): serial_no = "" batch_no = "" + barcode = "" + item_code = search_value if not frappe.db.exists('Item Group', item_group): item_group = get_root_of('Item Group') @@ -24,10 +26,17 @@ def get_items(start, page_length, price_list, item_group, search_value=""): if batch_no_data: batch_no, item_code = batch_no_data + if not serial_no and not batch_no: + barcode_data = frappe.db.get_value('Item', {'barcode': search_value}, ['name', 'barcode']) + if barcode_data: + item_code, barcode = barcode_data + + item_code, condition = get_conditions(item_code, serial_no, batch_no, barcode) + lft, rgt = frappe.db.get_value('Item Group', item_group, ['lft', 'rgt']) # locate function is used to sort by closest match from the beginning of the value res = frappe.db.sql("""select i.name as item_code, i.item_name, i.image as item_image, - item_det.price_list_rate, item_det.currency + i.is_stock_item, item_det.price_list_rate, item_det.currency from `tabItem` i LEFT JOIN (select item_code, price_list_rate, currency from `tabItem Price` where price_list=%(price_list)s) item_det @@ -36,11 +45,11 @@ def get_items(start, page_length, price_list, item_group, search_value=""): where i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1 and i.item_group in (select name from `tabItem Group` where lft >= {lft} and rgt <= {rgt}) - and (i.item_code like %(item_code)s - or i.item_name like %(item_code)s or i.barcode like %(item_code)s) - limit {start}, {page_length}""".format(start=start, page_length=page_length, lft=lft, rgt=rgt), + and {condition} + limit {start}, {page_length}""".format(start=start, + page_length=page_length, lft=lft, rgt=rgt, condition=condition), { - 'item_code': '%%%s%%'%(frappe.db.escape(item_code)), + 'item_code': item_code, 'price_list': price_list } , as_dict=1) @@ -60,6 +69,15 @@ def get_items(start, page_length, price_list, item_group, search_value=""): return res +def get_conditions(item_code, serial_no, batch_no, barcode): + if serial_no or batch_no or barcode: + return frappe.db.escape(item_code), "i.name = %(item_code)s" + + condition = """(i.name like %(item_code)s + or i.item_name like %(item_code)s)""" + + return '%%%s%%'%(frappe.db.escape(item_code)), condition + @frappe.whitelist() def submit_invoice(doc): if isinstance(doc, basestring): diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index ec83705a43b..f1b10a98916 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -194,461 +194,461 @@ "search_index": 0, "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sales_settings", - "fieldtype": "Section 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": "Sales", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sales_settings", + "fieldtype": "Section 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": "Sales", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sales_monthly_history", - "fieldtype": "Small Text", - "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": "Sales Monthly History", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sales_monthly_history", + "fieldtype": "Small Text", + "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": "Sales Monthly History", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "monthly_sales_target", - "fieldtype": "Currency", - "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": "Monthly Sales Target", - "length": 0, - "no_copy": 0, - "options": "default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "monthly_sales_target", + "fieldtype": "Currency", + "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": "Monthly Sales Target", + "length": 0, + "no_copy": 0, + "options": "default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 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_goals", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_goals", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "total_monthly_sales", - "fieldtype": "Currency", - "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": "Total Monthly Sales", - "length": 0, - "no_copy": 1, - "options": "default_currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_monthly_sales", + "fieldtype": "Currency", + "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": "Total Monthly Sales", + "length": 0, + "no_copy": 1, + "options": "default_currency", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "charts_section", - "fieldtype": "Section 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": "Default Values", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "charts_section", + "fieldtype": "Section 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": "Default Values", + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "default_letter_head", - "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": "Default Letter Head", - "length": 0, - "no_copy": 0, - "options": "Letter Head", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_letter_head", + "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": "Default Letter Head", + "length": 0, + "no_copy": 0, + "options": "Letter Head", + "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": "default_holiday_list", - "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": "Default Holiday List", - "length": 0, - "no_copy": 0, - "options": "Holiday List", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_holiday_list", + "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": "Default Holiday List", + "length": 0, + "no_copy": 0, + "options": "Holiday List", + "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": "default_terms", - "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": "Default Terms", - "length": 0, - "no_copy": 0, - "options": "Terms and Conditions", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_terms", + "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": "Default Terms", + "length": 0, + "no_copy": 0, + "options": "Terms and Conditions", + "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": "default_currency", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Currency", - "length": 0, - "no_copy": 0, - "options": "Currency", - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "default_currency", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Currency", + "length": 0, + "no_copy": 0, + "options": "Currency", + "permlevel": 0, + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_10", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_10", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "country", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Country", - "length": 0, - "no_copy": 0, - "options": "Country", - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "country", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Country", + "length": 0, + "no_copy": 0, + "options": "Country", + "permlevel": 0, + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "create_chart_of_accounts_based_on", - "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": "Create Chart Of Accounts Based On", - "length": 0, - "no_copy": 0, - "options": "\nStandard Template\nExisting Company", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "create_chart_of_accounts_based_on", + "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": "Create Chart Of Accounts Based On", + "length": 0, + "no_copy": 0, + "options": "\nStandard Template\nExisting Company", + "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, - "depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Standard Template\"", - "fieldname": "chart_of_accounts", - "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": "Chart Of Accounts Template", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Standard Template\"", + "fieldname": "chart_of_accounts", + "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": "Chart Of Accounts Template", + "length": 0, + "no_copy": 1, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"", - "fieldname": "existing_company", - "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": "Existing Company ", - "length": 0, - "no_copy": 1, - "options": "Company", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.create_chart_of_accounts_based_on===\"Existing Company\"", + "fieldname": "existing_company", + "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": "Existing Company ", + "length": 0, + "no_copy": 1, + "options": "Company", + "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 }, { @@ -1978,24 +1978,24 @@ "set_only_once": 0, "unique": 0 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-building", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "menu_index": 0, - "modified": "2017-08-31 11:48:56.278568", - "modified_by": "Administrator", - "module": "Setup", - "name": "Company", - "owner": "Administrator", + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "icon": "fa fa-building", + "idx": 1, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "menu_index": 0, + "modified": "2017-09-06 15:08:44.360880", + "modified_by": "mohan@annapurna.com", + "module": "Setup", + "name": "Company", + "owner": "Administrator", "permissions": [ { "amend": 0, diff --git a/erpnext/setup/doctype/customer_group/customer_group.py b/erpnext/setup/doctype/customer_group/customer_group.py index 0f1ee818637..7472c51affd 100644 --- a/erpnext/setup/doctype/customer_group/customer_group.py +++ b/erpnext/setup/doctype/customer_group/customer_group.py @@ -17,11 +17,11 @@ class CustomerGroup(NestedSet): def validate_name_with_customer(self): if frappe.db.exists("Customer", self.name): - frappe.msgprint(_("An Customer exists with same name"), raise_exception=1) + frappe.msgprint(_("A customer with the same name already exists"), raise_exception=1) def get_parent_customer_groups(customer_group): lft, rgt = frappe.db.get_value("Customer Group", customer_group, ['lft', 'rgt']) return frappe.db.sql("""select name from `tabCustomer Group` where lft <= %s and rgt >= %s - order by lft asc""", (lft, rgt), as_dict=True) \ No newline at end of file + order by lft asc""", (lft, rgt), as_dict=True) diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index c85a541d849..8d1fb3d4a63 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -16,14 +16,13 @@ user_specific_content = ["calendar_events", "todo_list"] from frappe.model.document import Document class EmailDigest(Document): - def __init__(self, arg1, arg2=None): - super(EmailDigest, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(EmailDigest, self).__init__(*args, **kwargs) self.from_date, self.to_date = self.get_from_to_date() self.set_dates() self._accounts = {} - self.currency = frappe.db.get_value("Company", self.company, - "default_currency") + self.currency = frappe.db.get_value("Company", self.company, "default_currency") def get_users(self): """get list of users""" diff --git a/erpnext/setup/setup_wizard/domainify.py b/erpnext/setup/setup_wizard/domainify.py deleted file mode 100644 index ddb2a80afb1..00000000000 --- a/erpnext/setup/setup_wizard/domainify.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -from __future__ import unicode_literals -import frappe -from frappe import _ - -def get_domain(domain): - '''Written as a function to prevent data mutation effects''' - data = { - 'Manufacturing': { - 'desktop_icons': ['Item', 'BOM', 'Customer', 'Supplier', 'Sales Order', - 'Production Order', 'Stock Entry', 'Purchase Order', 'Task', 'Buying', 'Selling', - 'Accounts', 'HR', 'ToDo'], - 'remove_roles': ['Academics User', 'Instructor', 'Physician', 'Nursing User', - 'Laboratory user', 'LabTest Approver', 'Healthcare Administrator'], - 'properties': [ - {'doctype': 'Item', 'fieldname': 'manufacturing', 'property': 'collapsible_depends_on', 'value': 'is_stock_item'}, - ], - 'set_value': [ - ['Stock Settings', None, 'show_barcode_field', 1] - ], - 'default_portal_role': 'Customer' - }, - - 'Retail': { - 'desktop_icons': ['POS', 'Item', 'Customer', 'Sales Invoice', 'Purchase Order', - 'Warranty Claim', 'Accounts', 'Task', 'Buying', 'ToDo'], - 'remove_roles': ['Manufacturing User', 'Manufacturing Manager', 'Academics User', 'Instructor', - 'Physician', 'Nursing User', 'Laboratory user', - 'LabTest Approver', 'Healthcare Administrator'], - 'properties': [ - {'doctype': 'Item', 'fieldname': 'manufacturing', 'property': 'hidden', 'value': 1}, - {'doctype': 'Customer', 'fieldname': 'credit_limit_section', 'property': 'hidden', 'value': 1}, - ], - 'set_value': [ - ['Stock Settings', None, 'show_barcode_field', 1] - ], - 'default_portal_role': 'Customer' - }, - - 'Distribution': { - 'desktop_icons': ['Item', 'Customer', 'Supplier', 'Lead', 'Sales Order', 'Task', - 'Sales Invoice', 'CRM', 'Selling', 'Buying', 'Stock', 'Accounts', 'HR', 'ToDo'], - 'remove_roles': ['Manufacturing User', 'Manufacturing Manager', 'Academics User', 'Instructor', - 'Physician', 'Nursing User', 'Laboratory user', - 'LabTest Approver', 'Healthcare Administrator'], - 'set_value': [ - ['Stock Settings', None, 'show_barcode_field', 1] - ], - 'default_portal_role': 'Customer' - }, - - 'Services': { - 'desktop_icons': ['Project', 'Timesheet', 'Customer', 'Sales Order', 'Sales Invoice', - 'Lead', 'Opportunity', 'Task', 'Expense Claim', 'Employee', 'HR', 'ToDo'], - 'remove_roles': ['Manufacturing User', 'Manufacturing Manager', 'Academics User', 'Instructor', - 'Physician', 'Nursing User', 'Laboratory user', - 'LabTest Approver', 'Healthcare Administrator'], - 'properties': [ - {'doctype': 'Item', 'fieldname': 'is_stock_item', 'property': 'default', 'value': 0}, - ], - 'set_value': [ - ['Stock Settings', None, 'show_barcode_field', 0] - ], - 'default_portal_role': 'Customer' - }, - 'Education': { - 'desktop_icons': ['Student', 'Program', 'Course', 'Student Group', 'Instructor', - 'Fees', 'Task', 'ToDo', 'Schools'], - 'allow_roles': ['Academics User', 'Accounts User', 'Accounts Manager', 'Item Manager', - 'Website Manager', 'HR User', 'HR Manager', 'Purchase User', 'Purchase Manager', - 'Student', 'Projects User', 'Instructor'], - 'default_portal_role': 'Student' - }, - 'Healthcare': { - 'desktop_icons': ['Patient', 'Patient Appointment', 'Consultation', 'Lab Test', 'Healthcare', - 'Accounts', 'Buying', 'Stock', 'HR', 'ToDo'], - 'remove_roles': ['Manufacturing User', 'Manufacturing Manager', 'Projects User', 'Projects Manager', - 'Academics User', 'Instructor'], - 'default_portal_role': 'Patient' - }, - } - if not domain in data: - raise 'Invalid Domain {0}'.format(domain) - return frappe._dict(data[domain]) - -def setup_domain(domain): - '''Setup roles, desktop icons, properties, values, portal sidebar menu based on domain''' - data = get_domain(domain) - setup_roles(data) - setup_desktop_icons(data) - setup_properties(data) - set_values(data) - setup_sidebar_items(data) - update_module_def_restrict_to_domain() - - if data.get('default_portal_role'): - frappe.db.set_value('Portal Settings', None, 'default_role', data.get('default_portal_role')) - - frappe.clear_cache() - -def setup_desktop_icons(data): - '''set desktop icons form `data.desktop_icons`''' - from frappe.desk.doctype.desktop_icon.desktop_icon import set_desktop_icons - if data.desktop_icons: - set_desktop_icons(data.desktop_icons) - -def setup_properties(data): - if data.properties: - for args in data.properties: - frappe.make_property_setter(args) - -def setup_roles(data): - '''Add, remove roles from `data.allow_roles` or `data.remove_roles`''' - def remove_role(role): - frappe.db.sql('delete from `tabHas Role` where role=%s', role) - frappe.set_value('Role', role, 'disabled', 1) - - if data.remove_roles: - for role in data.remove_roles: - remove_role(role) - - if data.allow_roles: - # remove all roles other than allowed roles - active_domains = frappe.get_active_domains() - data.allow_roles += ['Administrator', 'Guest', 'System Manager', 'All'] - for role in frappe.get_all('Role', filters = {"restrict_to_domain": ("not in", active_domains)}): - if not (role.name in data.allow_roles): - remove_role(role.name) - -def set_values(data): - '''set values based on `data.set_value`''' - if data.set_value: - for args in data.set_value: - doc = frappe.get_doc(args[0], args[1] or args[0]) - doc.set(args[2], args[3]) - doc.save() - -def setup_sidebar_items(data): - '''Enable / disable sidebar items''' - if data.allow_sidebar_items: - # disable all - frappe.db.sql('update `tabPortal Menu Item` set enabled=0') - - # enable - frappe.db.sql('''update `tabPortal Menu Item` set enabled=1 - where route in ({0})'''.format(', '.join(['"{0}"'.format(d) for d in data.allow_sidebar_items]))) - - if data.remove_sidebar_items: - # disable all - frappe.db.sql('update `tabPortal Menu Item` set enabled=1') - - # enable - frappe.db.sql('''update `tabPortal Menu Item` set enabled=0 - where route in ({0})'''.format(', '.join(['"{0}"'.format(d) for d in data.remove_sidebar_items]))) - -def reset(): - from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to - add_all_roles_to('Administrator') - - frappe.db.sql('delete from `tabProperty Setter`') - -def update_module_def_restrict_to_domain(): - """ set the restrict to domain for the module def """ - - module_def_restrict_to_domain_mapper = { - "Schools": 'Education' - } - - lang = frappe.db.get_single_value("System Settings", "language") or "en" - for module, domain in module_def_restrict_to_domain_mapper.iteritems(): - if frappe.db.exists("Domain", _(domain, lang)): - frappe.db.set_value("Module Def", module, "restrict_to_domain", _(domain, lang)) - elif frappe.db.exists("Domain", domain): - frappe.db.set_value("Module Def", module, "restrict_to_domain", domain) - else: - pass diff --git a/erpnext/setup/setup_wizard/sample_data.py b/erpnext/setup/setup_wizard/sample_data.py index bc26e09677c..43911f06c1d 100644 --- a/erpnext/setup/setup_wizard/sample_data.py +++ b/erpnext/setup/setup_wizard/sample_data.py @@ -73,6 +73,7 @@ def make_material_request(items): mr = frappe.get_doc({ "doctype": "Material Request", "material_request_type": "Purchase", + "schedule_date": frappe.utils.add_days(frappe.utils.nowdate(), 7), "items": [{ "schedule_date": frappe.utils.add_days(frappe.utils.nowdate(), 7), "item_code": i.name, diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index a80399d905c..766f9b5223b 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -10,12 +10,10 @@ from frappe.utils import cstr, flt, getdate from frappe import _ from frappe.utils.file_manager import save_file from .default_website import website_maker -from .healthcare import setup_healthcare import install_fixtures from .sample_data import make_sample_data from erpnext.accounts.doctype.account.account import RootNotEditable from frappe.core.doctype.communication.comment import add_info_comment -from erpnext.setup.setup_wizard.domainify import setup_domain from erpnext.setup.doctype.company.company import install_country_fixtures def setup_complete(args=None): @@ -35,20 +33,14 @@ def setup_complete(args=None): create_letter_head(args) set_no_copy_fields_in_variant_settings() - if args.get('domain').lower() == 'education': - create_academic_year() - create_academic_term() - - if args.domain.lower() == 'healthcare': - setup_healthcare() - if args.get('setup_website'): website_maker(args) create_logo(args) frappe.local.message_log = [] - setup_domain(args.get('domain')) + domain_settings = frappe.get_single('Domain Settings') + domain_settings.set_active_domains([_(args.get('domain'))]) frappe.db.commit() login_as_first_user(args) @@ -400,27 +392,3 @@ def create_employee_for_self(args): emp.flags.ignore_mandatory = True emp.insert(ignore_permissions = True) -# Schools -def create_academic_term(): - at = ["Semester 1", "Semester 2", "Semester 3"] - ay = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"] - for y in ay: - for t in at: - academic_term = frappe.new_doc("Academic Term") - academic_term.academic_year = y - academic_term.term_name = t - try: - academic_term.save() - except frappe.DuplicateEntryError: - pass - -def create_academic_year(): - ac = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"] - for d in ac: - academic_year = frappe.new_doc("Academic Year") - academic_year.academic_year_name = d - try: - academic_year.save() - except frappe.DuplicateEntryError: - pass - diff --git a/erpnext/setup/setup_wizard/test_setup_wizard.py b/erpnext/setup/setup_wizard/test_setup_wizard.py index 57eeeff5b2c..97650f2d24f 100644 --- a/erpnext/setup/setup_wizard/test_setup_wizard.py +++ b/erpnext/setup/setup_wizard/test_setup_wizard.py @@ -16,44 +16,50 @@ def run_setup_wizard_test(): # Language slide driver.wait_for_ajax(True) - time.sleep(2) + time.sleep(1) + driver.set_select("language", "English (United States)") driver.wait_for_ajax(True) - driver.wait_till_clickable(".next-btn").click() + time.sleep(1) + driver.click(".next-btn") # Region slide driver.wait_for_ajax(True) driver.set_select("country", "India") driver.wait_for_ajax(True) - driver.wait_till_clickable(".next-btn").click() + time.sleep(1) + driver.click(".next-btn") # Profile slide driver.set_field("full_name", "Great Tester") driver.set_field("email", "great@example.com") driver.set_field("password", "test") - driver.wait_till_clickable(".next-btn").click() + driver.wait_for_ajax(True) + time.sleep(1) + driver.click(".next-btn") + time.sleep(1) - # Brand slide + # domain slide driver.set_select("domain", "Manufacturing") - time.sleep(5) - driver.wait_till_clickable(".next-btn").click() + time.sleep(1) + driver.click(".next-btn") # Org slide driver.set_field("company_name", "For Testing") - driver.wait_till_clickable(".next-btn").click() + time.sleep(1) + driver.print_console() + driver.click(".next-btn") + driver.set_field("company_tagline", "Just for GST") driver.set_field("bank_account", "HDFC") - driver.wait_till_clickable(".complete-btn").click() + time.sleep(3) + driver.click(".complete-btn") # Wait for desktop driver.wait_for('#page-desktop', timeout=600) - console = driver.get_console() - if frappe.flags.tests_verbose: - for line in console: - print(line) - print('-' * 40) - time.sleep(1) + driver.print_console() + time.sleep(3) frappe.db.set_default('in_selenium', None) frappe.db.set_value("Company", "For Testing", "write_off_account", "Write Off - FT") diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py index 49c439ba5ca..003a57c852b 100644 --- a/erpnext/setup/utils.py +++ b/erpnext/setup/utils.py @@ -111,27 +111,12 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None): def enable_all_roles_and_domains(): """ enable all roles and domain for testing """ - roles = frappe.get_list("Role", filters={"disabled": 1}) - for role in roles: - _role = frappe.get_doc("Role", role.get("name")) - _role.disabled = 0 - _role.flags.ignore_mandatory = True - _role.flags.ignore_permissions = True - _role.save() - # add all roles to users - if roles: - user = frappe.get_doc("User", "Administrator") - user.add_roles(*[role.get("name") for role in roles]) - - domains = frappe.get_list("Domain") + domains = frappe.get_all("Domain") if not domains: return - domain_settings = frappe.get_doc("Domain Settings", "Domain Settings") - domain_settings.set("active_domains", []) - for domain in domains: - row = domain_settings.append("active_domains", {}) - row.domain=domain.get("name") - - domain_settings.save() + from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to + frappe.get_single('Domain Settings').set_active_domains(\ + [d.name for d in domains]) + add_all_roles_to('Administrator') diff --git a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py index 390bc27568f..75899e121a5 100644 --- a/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py +++ b/erpnext/shopping_cart/doctype/shopping_cart_settings/test_shopping_cart_settings.py @@ -39,3 +39,4 @@ class TestShoppingCartSettings(unittest.TestCase): frappe.db.sql("update `tabTax Rule` set use_for_shopping_cart = 1") +test_dependencies = ["Tax Rule"] \ No newline at end of file diff --git a/erpnext/shopping_cart/product_info.py b/erpnext/shopping_cart/product_info.py new file mode 100644 index 00000000000..8015c4818f5 --- /dev/null +++ b/erpnext/shopping_cart/product_info.py @@ -0,0 +1,45 @@ +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe +from erpnext.shopping_cart.cart import _get_cart_quotation +from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings \ + import is_cart_enabled, get_shopping_cart_settings, show_quantity_in_website +from erpnext.utilities.product import get_price, get_qty_in_stock + +@frappe.whitelist(allow_guest=True) +def get_product_info_for_website(item_code): + """get product price / stock info for website""" + if not is_cart_enabled(): + return {} + + cart_quotation = _get_cart_quotation() + cart_settings = get_shopping_cart_settings() + + price = get_price( + item_code, + cart_quotation.selling_price_list, + cart_settings.default_customer_group, + cart_settings.company + ) + + stock_status = get_qty_in_stock(item_code, "website_warehouse") + + product_info = { + "price": price, + "stock_qty": stock_status.stock_qty, + "in_stock": stock_status.in_stock, + "qty": 0, + "uom": frappe.db.get_value("Item", item_code, "stock_uom"), + "show_stock_qty": show_quantity_in_website() + } + + if product_info["price"]: + if frappe.session.user != "Guest": + item = cart_quotation.get({"item_code": item_code}) + if item: + product_info["qty"] = item[0].qty + + return product_info \ No newline at end of file diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py index 31643061091..2080224a705 100644 --- a/erpnext/startup/boot.py +++ b/erpnext/startup/boot.py @@ -19,6 +19,8 @@ def boot_session(bootinfo): 'territory') bootinfo.sysdefaults.customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group') + bootinfo.sysdefaults.allow_stale = frappe.db.get_single_value('Accounts Settings', + 'allow_stale') or 1 bootinfo.notification_settings = frappe.get_doc("Notification Control", "Notification Control") diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js index e9499895fe8..113a2efb50d 100644 --- a/erpnext/stock/dashboard/item_dashboard.js +++ b/erpnext/stock/dashboard/item_dashboard.js @@ -75,8 +75,13 @@ erpnext.stock.ItemDashboard = Class.extend({ this.content.find('.more').addClass('hidden'); } - $(frappe.render_template('item_dashboard_list', context)).appendTo(this.result); - + // If not any stock in any warehouses provide a message to end user + if (context.data.length > 0) { + $(frappe.render_template('item_dashboard_list', context)).appendTo(this.result); + } else { + var message = __(" Currently no stock available in any warehouse") + $(" "+message+"").appendTo(this.result); + } }, get_item_dashboard_data: function(data, max_count, show_item) { if(!max_count) max_count = 0; @@ -182,4 +187,4 @@ erpnext.stock.move_item = function(item, source, target, actual_qty, rate, callb frappe.set_route('Form', doc.doctype, doc.name); }) }); -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py index 043dc73d378..c58a98d7c8a 100644 --- a/erpnext/stock/doctype/batch/batch.py +++ b/erpnext/stock/doctype/batch/batch.py @@ -103,7 +103,7 @@ def split_batch(batch_no, item_code, warehouse, qty, new_batch_id = None): def set_batch_nos(doc, warehouse_field, throw = False): '''Automatically select `batch_no` for outgoing items in item table''' for d in doc.items: - qty = d.get('stock_qty') or d.get('qty') or 0 + qty = d.get('stock_qty') or d.get('transfer_qty') or d.get('qty') or 0 has_batch_no = frappe.db.get_value('Item', d.item_code, 'has_batch_no') warehouse = d.get(warehouse_field, None) if has_batch_no and warehouse and qty > 0: diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index f5a99afbd21..dd00398695b 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -21,8 +21,8 @@ form_grid_templates = { } class DeliveryNote(SellingController): - def __init__(self, arg1, arg2=None): - super(DeliveryNote, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(DeliveryNote, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Delivery Note Item', 'target_dt': 'Sales Order Item', diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 03b93c0cb20..6f3fce5ba2f 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -63,7 +63,7 @@ frappe.ui.form.on("Item", { frm.page.set_inner_btn_group_as_primary(__("Make")); } if (frm.doc.variant_of) { - frm.set_intro(__('This Item is a Variant of {0} (Template).', + frm.set_intro(__('This Item is a Variant of {0} (Template).', [`${frm.doc.variant_of}`]), true); } @@ -103,6 +103,11 @@ frappe.ui.form.on("Item", { frappe.set_route("Form", "Item Variant Settings"); }, __("View")); } + + if(frm.doc.__onload && frm.doc.__onload.stock_exists) { + // Hide variants section if stock exists + frm.toggle_display("variants_section", 0); + } }, validate: function(frm){ @@ -127,7 +132,7 @@ frappe.ui.form.on("Item", { if(!frm.doc.description) frm.set_value("description", frm.doc.item_code); }, - + is_stock_item: function(frm) { if(!frm.doc.is_stock_item) { frm.set_value("has_batch_no", 0); @@ -135,7 +140,7 @@ frappe.ui.form.on("Item", { frm.set_value("has_serial_no", 0); } }, - + copy_from_item_group: function(frm) { return frm.call({ doc: frm.doc, @@ -249,15 +254,18 @@ $.extend(erpnext.item, { if(frm.doc.__islocal) return; - frappe.require('assets/js/item-dashboard.min.js', function() { - var section = frm.dashboard.add_section('
\ - ' + __("Stock Levels") + '
'); - erpnext.item.item_dashboard = new erpnext.stock.ItemDashboard({ - parent: section, - item_code: frm.doc.name + // Show Stock Levels only if is_stock_item + if (frm.doc.is_stock_item) { + frappe.require('assets/js/item-dashboard.min.js', function() { + var section = frm.dashboard.add_section('
\ + ' + __("Stock Levels") + '
'); + erpnext.item.item_dashboard = new erpnext.stock.ItemDashboard({ + parent: section, + item_code: frm.doc.name + }); + erpnext.item.item_dashboard.refresh(); }); - erpnext.item.item_dashboard.refresh(); - }); + } }, edit_prices_button: function(frm) { diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index b1686319703..fd85a50d40e 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -1,3323 +1,3509 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:item_code", - "beta": 0, - "creation": "2013-05-03 10:45:46", - "custom": 0, - "default_print_format": "", - "description": "A Product or a Service that is bought, sold or kept in stock.", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:item_code", + "beta": 0, + "creation": "2013-05-03 10:45:46", + "custom": 0, + "default_print_format": "", + "description": "A Product or a Service that is bought, sold or kept in stock.", + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "name_and_description_section", - "fieldtype": "Section 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": "", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-flag", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "name_and_description_section", + "fieldtype": "Section 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": "", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-flag", + "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": "naming_series", - "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": "Series", - "length": 0, - "no_copy": 0, - "options": "ITEM-", - "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": 1, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "naming_series", + "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": "Series", + "length": 0, + "no_copy": 0, + "options": "ITEM-", + "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": 1, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "item_code", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_code", - "oldfieldtype": "Data", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "description": "", + "fieldname": "item_code", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Item Code", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_code", + "oldfieldtype": "Data", + "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, - "depends_on": "variant_of", - "description": "If item is a variant of another item then description, image, pricing, taxes etc will be set from the template unless explicitly specified", - "fieldname": "variant_of", - "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": 1, - "label": "Variant Of", - "length": 0, - "no_copy": 0, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "variant_of", + "description": "If item is a variant of another item then description, image, pricing, taxes etc will be set from the template unless explicitly specified", + "fieldname": "variant_of", + "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": 1, + "label": "Variant Of", + "length": 0, + "no_copy": 0, + "options": "Item", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "item_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Name", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_name", - "oldfieldtype": "Data", - "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": 1, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "item_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Item Name", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_name", + "oldfieldtype": "Data", + "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": 1, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "barcode", - "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": "Barcode", - "length": 0, - "no_copy": 1, - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "barcode", + "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": "Barcode", + "length": 0, + "no_copy": 1, + "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, - "description": "", - "fieldname": "item_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Item Group", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_group", - "oldfieldtype": "Link", - "options": "Item Group", - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "", + "fieldname": "item_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Item Group", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_group", + "oldfieldtype": "Link", + "options": "Item Group", + "permlevel": 0, + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", - "fieldname": "stock_uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Unit of Measure", - "length": 0, - "no_copy": 0, - "oldfieldname": "stock_uom", - "oldfieldtype": "Link", - "options": "UOM", - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_item_from_hub", + "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 Item from Hub", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break0", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "", + "fieldname": "stock_uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Unit of Measure", + "length": 0, + "no_copy": 0, + "oldfieldname": "stock_uom", + "oldfieldtype": "Link", + "options": "UOM", + "permlevel": 0, + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "disabled", - "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": "Disabled", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break0", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "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, - "default": "1", - "description": "", - "fieldname": "is_stock_item", - "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": "Maintain Stock", - "length": 0, - "no_copy": 0, - "oldfieldname": "is_stock_item", - "oldfieldtype": "Select", - "options": "", - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "disabled", + "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": "Disabled", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:(doc.__islocal&&doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)", - "fieldname": "opening_stock", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Opening Stock", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "1", + "description": "", + "fieldname": "is_stock_item", + "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": "Maintain Stock", + "length": 0, + "no_copy": 0, + "oldfieldname": "is_stock_item", + "oldfieldtype": "Select", + "options": "", + "permlevel": 0, + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:(doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)", - "fieldname": "valuation_rate", - "fieldtype": "Currency", - "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": "Valuation Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:(doc.__islocal&&doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)", + "fieldname": "opening_stock", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Opening Stock", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "standard_rate", - "fieldtype": "Currency", - "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": "Standard Selling Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:(doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)", + "fieldname": "valuation_rate", + "fieldtype": "Currency", + "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": "Valuation Rate", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "is_fixed_asset", - "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 Fixed Asset", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "standard_rate", + "fieldtype": "Currency", + "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": "Standard Selling Rate", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_fixed_asset", - "fieldname": "asset_category", - "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": "Asset Category", - "length": 0, - "no_copy": 0, - "options": "Asset Category", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_fixed_asset", + "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 Fixed Asset", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:!doc.__islocal", - "description": "", - "fieldname": "tolerance", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow over delivery or receipt upto this percent", - "length": 0, - "no_copy": 0, - "oldfieldname": "tolerance", - "oldfieldtype": "Currency", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_fixed_asset", + "fieldname": "asset_category", + "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": "Asset Category", + "length": 0, + "no_copy": 0, + "options": "Asset Category", + "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": "image", - "fieldtype": "Attach Image", - "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": "Image", - "length": 0, - "no_copy": 0, - "options": "image", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:!doc.__islocal", + "description": "", + "fieldname": "tolerance", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Allow over delivery or receipt upto this percent", + "length": 0, + "no_copy": 0, + "oldfieldname": "tolerance", + "oldfieldtype": "Currency", + "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": 1, - "columns": 0, - "fieldname": "section_break_11", - "fieldtype": "Section 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": "Description", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "image", + "fieldtype": "Attach Image", + "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": "Image", + "length": 0, + "no_copy": 0, + "options": "image", + "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": "brand", - "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": "Brand", - "length": 0, - "no_copy": 0, - "oldfieldname": "brand", - "oldfieldtype": "Link", - "options": "Brand", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "section_break_11", + "fieldtype": "Section 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": "Description", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Text Editor", - "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": "Description", - "length": 0, - "no_copy": 0, - "oldfieldname": "description", - "oldfieldtype": "Text", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "brand", + "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": "Brand", + "length": 0, + "no_copy": 0, + "oldfieldname": "brand", + "oldfieldtype": "Link", + "options": "Brand", + "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": 1, - "collapsible_depends_on": "is_stock_item", - "columns": 0, - "depends_on": "is_stock_item", - "fieldname": "inventory", - "fieldtype": "Section 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": "Inventory", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-truck", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "description", + "fieldtype": "Text Editor", + "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": "Description", + "length": 0, + "no_copy": 0, + "oldfieldname": "description", + "oldfieldtype": "Text", + "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, - "depends_on": "is_stock_item", - "description": "", - "fieldname": "default_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Warehouse", - "length": 0, - "no_copy": 0, - "oldfieldname": "default_warehouse", - "oldfieldtype": "Link", - "options": "Warehouse", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "is_stock_item", + "columns": 0, + "depends_on": "is_stock_item", + "fieldname": "inventory", + "fieldtype": "Section 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": "Inventory", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-truck", + "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, - "default": "2099-12-31", - "depends_on": "is_stock_item", - "fieldname": "end_of_life", - "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 of Life", - "length": 0, - "no_copy": 0, - "oldfieldname": "end_of_life", - "oldfieldtype": "Date", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_stock_item", + "description": "", + "fieldname": "default_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Warehouse", + "length": 0, + "no_copy": 0, + "oldfieldname": "default_warehouse", + "oldfieldtype": "Link", + "options": "Warehouse", + "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, - "default": "Purchase", - "fieldname": "default_material_request_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": "Default Material Request Type", - "length": 0, - "no_copy": 0, - "options": "Purchase\nMaterial Transfer\nMaterial Issue\nManufacture", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "2099-12-31", + "depends_on": "is_stock_item", + "fieldname": "end_of_life", + "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 of Life", + "length": 0, + "no_copy": 0, + "oldfieldname": "end_of_life", + "oldfieldtype": "Date", + "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, - "depends_on": "is_stock_item", - "fieldname": "column_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "oldfieldtype": "Column Break", - "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, + "default": "Purchase", + "fieldname": "default_material_request_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": "Default Material Request Type", + "length": 0, + "no_copy": 0, + "options": "Purchase\nMaterial Transfer\nMaterial Issue\nManufacture", + "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, + "depends_on": "is_stock_item", + "fieldname": "column_break1", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "oldfieldtype": "Column Break", + "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, "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_stock_item", - "fieldname": "valuation_method", - "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": "Valuation Method", - "length": 0, - "no_copy": 0, - "options": "\nFIFO\nMoving Average", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_stock_item", + "fieldname": "valuation_method", + "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": "Valuation Method", + "length": 0, + "no_copy": 0, + "options": "\nFIFO\nMoving Average", + "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, - "depends_on": "eval:doc.is_stock_item", - "fieldname": "warranty_period", - "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": "Warranty Period (in days)", - "length": 0, - "no_copy": 0, - "oldfieldname": "warranty_period", - "oldfieldtype": "Data", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.is_stock_item", + "fieldname": "warranty_period", + "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": "Warranty Period (in days)", + "length": 0, + "no_copy": 0, + "oldfieldname": "warranty_period", + "oldfieldtype": "Data", + "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, - "depends_on": "is_stock_item", - "description": "", - "fieldname": "net_weight", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Net Weight", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "is_stock_item", + "description": "", + "fieldname": "net_weight", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Net Weight", + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.is_stock_item", - "fieldname": "weight_uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Weight UOM", - "length": 0, - "no_copy": 0, - "options": "UOM", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.is_stock_item", + "fieldname": "weight_uom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Weight UOM", + "length": 0, + "no_copy": 0, + "options": "UOM", + "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": 1, - "columns": 0, - "depends_on": "is_stock_item", - "description": "", - "fieldname": "reorder_section", - "fieldtype": "Section 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": "Auto re-order", - "length": 0, - "no_copy": 0, - "options": "fa fa-rss", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "depends_on": "is_stock_item", + "description": "", + "fieldname": "reorder_section", + "fieldtype": "Section 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": "Auto re-order", + "length": 0, + "no_copy": 0, + "options": "fa fa-rss", + "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, - "depends_on": "", - "description": "Will also apply for variants unless overrridden", - "fieldname": "reorder_levels", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reorder level based on Warehouse", - "length": 0, - "no_copy": 0, - "options": "Item Reorder", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "description": "Will also apply for variants unless overrridden", + "fieldname": "reorder_levels", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Reorder level based on Warehouse", + "length": 0, + "no_copy": 0, + "options": "Item Reorder", + "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": 1, - "columns": 0, - "depends_on": "", - "fieldname": "unit_of_measure_conversion", - "fieldtype": "Section 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": "Units of Measure", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "depends_on": "", + "fieldname": "unit_of_measure_conversion", + "fieldtype": "Section 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": "Units of Measure", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "description": "Will also apply for variants", - "fieldname": "uoms", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOMs", - "length": 0, - "no_copy": 1, - "oldfieldname": "uom_conversion_details", - "oldfieldtype": "Table", - "options": "UOM Conversion Detail", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "description": "Will also apply for variants", + "fieldname": "uoms", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "UOMs", + "length": 0, + "no_copy": 0, + "oldfieldname": "uom_conversion_details", + "oldfieldtype": "Table", + "options": "UOM Conversion Detail", + "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": 1, - "collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no", - "columns": 0, - "depends_on": "is_stock_item", - "fieldname": "serial_nos_and_batches", - "fieldtype": "Section 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": "Serial Nos and Batches", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "eval:doc.has_batch_no || doc.has_serial_no", + "columns": 0, + "depends_on": "is_stock_item", + "fieldname": "serial_nos_and_batches", + "fieldtype": "Section 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": "Serial Nos and Batches", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "depends_on": "eval:doc.is_stock_item", - "fieldname": "has_batch_no", - "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": "Has Batch No", - "length": 0, - "no_copy": 1, - "oldfieldname": "has_batch_no", - "oldfieldtype": "Select", - "options": "", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "depends_on": "eval:doc.is_stock_item", + "fieldname": "has_batch_no", + "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": "Has Batch No", + "length": 0, + "no_copy": 1, + "oldfieldname": "has_batch_no", + "oldfieldtype": "Select", + "options": "", + "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, - "depends_on": "has_batch_no", - "description": "", - "fieldname": "create_new_batch", - "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": "Automatically Create New Batch", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "has_batch_no", + "description": "", + "fieldname": "create_new_batch", + "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": "Automatically Create New Batch", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_37", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_37", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "depends_on": "eval:doc.is_stock_item", - "description": "", - "fieldname": "has_serial_no", - "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": "Has Serial No", - "length": 0, - "no_copy": 1, - "oldfieldname": "has_serial_no", - "oldfieldtype": "Select", - "options": "", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "depends_on": "eval:doc.is_stock_item", + "description": "", + "fieldname": "has_serial_no", + "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": "Has Serial No", + "length": 0, + "no_copy": 1, + "oldfieldname": "has_serial_no", + "oldfieldtype": "Select", + "options": "", + "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, - "depends_on": "has_serial_no", - "description": "Example: ABCD.#####\nIf series is set and Serial No is not mentioned in transactions, then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.", - "fieldname": "serial_no_series", - "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": "Serial Number Series", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "has_serial_no", + "description": "Example: ABCD.#####\nIf series is set and Serial No is not mentioned in transactions, then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.", + "fieldname": "serial_no_series", + "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": "Serial Number Series", + "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": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "attributes", - "columns": 0, - "depends_on": "", - "fieldname": "variants_section", - "fieldtype": "Section 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": "Variants", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "attributes", + "columns": 0, + "depends_on": "", + "fieldname": "variants_section", + "fieldtype": "Section 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": "Variants", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "depends_on": "eval:!doc.variant_of", - "description": "If this item has variants, then it cannot be selected in sales orders etc.", - "fieldname": "has_variants", - "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": "Has Variants", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "depends_on": "eval:!doc.variant_of", + "description": "If this item has variants, then it cannot be selected in sales orders etc.", + "fieldname": "has_variants", + "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": "Has Variants", + "length": 0, + "no_copy": 1, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Item Attribute", - "depends_on": "has_variants", - "fieldname": "variant_based_on", - "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": "Variant Based On", - "length": 0, - "no_copy": 0, - "options": "Item Attribute\nManufacturer", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Item Attribute", + "depends_on": "has_variants", + "fieldname": "variant_based_on", + "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": "Variant Based On", + "length": 0, + "no_copy": 0, + "options": "Item Attribute\nManufacturer", + "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, - "depends_on": "eval:doc.has_variants && doc.variant_based_on==='Item Attribute'", - "fieldname": "attributes", - "fieldtype": "Table", - "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": "Attributes", - "length": 0, - "no_copy": 1, - "options": "Item Variant Attribute", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.has_variants && doc.variant_based_on==='Item Attribute'", + "fieldname": "attributes", + "fieldtype": "Table", + "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": "Attributes", + "length": 0, + "no_copy": 1, + "options": "Item Variant Attribute", + "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": 1, - "columns": 0, - "fieldname": "purchase_details", - "fieldtype": "Section 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": "Purchase Details", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "purchase_details", + "fieldtype": "Section 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": "Purchase Details", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-shopping-cart", + "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, - "default": "1", - "fieldname": "is_purchase_item", - "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 Purchase Item", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "1", + "fieldname": "is_purchase_item", + "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 Purchase Item", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0.00", - "depends_on": "is_stock_item", - "description": "", - "fieldname": "min_order_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Minimum Order Qty", - "length": 0, - "no_copy": 0, - "oldfieldname": "min_order_qty", - "oldfieldtype": "Currency", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "purchase_uom", + "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": "Default Purchase Unit of Measure", + "length": 0, + "no_copy": 0, + "options": "UOM", + "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": "safety_stock", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Safety Stock", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0.00", + "depends_on": "is_stock_item", + "description": "", + "fieldname": "min_order_qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Minimum Order Qty", + "length": 0, + "no_copy": 0, + "oldfieldname": "min_order_qty", + "oldfieldtype": "Currency", + "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, - "depends_on": "", - "description": "Average time taken by the supplier to deliver", - "fieldname": "lead_time_days", - "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": "Lead Time in days", - "length": 0, - "no_copy": 0, - "oldfieldname": "lead_time_days", - "oldfieldtype": "Int", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "safety_stock", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Safety Stock", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "description": "", - "fieldname": "buying_cost_center", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Buying Cost Center", - "length": 0, - "no_copy": 0, - "oldfieldname": "cost_center", - "oldfieldtype": "Link", - "options": "Cost Center", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "description": "Average time taken by the supplier to deliver", + "fieldname": "lead_time_days", + "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": "Lead Time in days", + "length": 0, + "no_copy": 0, + "oldfieldname": "lead_time_days", + "oldfieldtype": "Int", + "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, - "depends_on": "", - "description": "", - "fieldname": "expense_account", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Expense Account", - "length": 0, - "no_copy": 0, - "oldfieldname": "purchase_account", - "oldfieldtype": "Link", - "options": "Account", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "description": "", + "fieldname": "buying_cost_center", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Buying Cost Center", + "length": 0, + "no_copy": 0, + "oldfieldname": "cost_center", + "oldfieldtype": "Link", + "options": "Cost Center", + "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, - "depends_on": "", - "fieldname": "last_purchase_rate", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Last Purchase Rate", - "length": 0, - "no_copy": 1, - "oldfieldname": "last_purchase_rate", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "description": "", + "fieldname": "expense_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Expense Account", + "length": 0, + "no_copy": 0, + "oldfieldname": "purchase_account", + "oldfieldtype": "Link", + "options": "Account", + "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": 1, - "columns": 0, - "depends_on": "", - "fieldname": "supplier_details", - "fieldtype": "Section 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": "Supplier Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "last_purchase_rate", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Last Purchase Rate", + "length": 0, + "no_copy": 1, + "oldfieldname": "last_purchase_rate", + "oldfieldtype": "Currency", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "default_supplier", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Supplier", - "length": 0, - "no_copy": 0, - "options": "Supplier", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "depends_on": "", + "fieldname": "supplier_details", + "fieldtype": "Section 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": "Supplier Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "delivered_by_supplier", - "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": "Delivered by Supplier (Drop Ship)", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "default_supplier", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Supplier", + "length": 0, + "no_copy": 0, + "options": "Supplier", + "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, - "depends_on": "", - "fieldname": "manufacturer", - "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": "Manufacturer", - "length": 0, - "no_copy": 0, - "options": "Manufacturer", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "delivered_by_supplier", + "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": "Delivered by Supplier (Drop Ship)", + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "manufacturer_part_no", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Manufacturer Part Number", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "manufacturer", + "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": "Manufacturer", + "length": 0, + "no_copy": 0, + "options": "Manufacturer", + "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, - "depends_on": "", - "fieldname": "column_break2", - "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": "Item Code for Suppliers", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Column Break", - "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, + "depends_on": "", + "fieldname": "manufacturer_part_no", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Manufacturer Part Number", + "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": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "column_break2", + "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": "Item Code for Suppliers", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Column Break", + "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, "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "supplier_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Supplier Items", - "length": 0, - "no_copy": 0, - "options": "Item Supplier", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "supplier_items", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Supplier Items", + "length": 0, + "no_copy": 0, + "options": "Item Supplier", + "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": 1, - "columns": 0, - "fieldname": "foreign_trade_details", - "fieldtype": "Section 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": "Foreign Trade Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "foreign_trade_details", + "fieldtype": "Section 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": "Foreign Trade Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "country_of_origin", - "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": "Country of Origin", - "length": 0, - "no_copy": 0, - "options": "Country", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "country_of_origin", + "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": "Country of Origin", + "length": 0, + "no_copy": 0, + "options": "Country", + "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_break_59", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_59", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customs_tariff_number", - "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": "Customs Tariff Number", - "length": 0, - "no_copy": 0, - "options": "Customs Tariff Number", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "customs_tariff_number", + "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": "Customs Tariff Number", + "length": 0, + "no_copy": 0, + "options": "Customs Tariff Number", + "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": 1, - "columns": 0, - "fieldname": "sales_details", - "fieldtype": "Section 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": "Sales Details", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-tag", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "sales_details", + "fieldtype": "Section 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": "Sales Details", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-tag", + "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, - "default": "1", - "fieldname": "is_sales_item", - "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 Sales Item", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "1", + "fieldname": "is_sales_item", + "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 Sales Item", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "description": "Publish Item to hub.erpnext.com", - "fieldname": "publish_in_hub", - "fieldtype": "Check", - "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": "Publish in Hub", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "sales_uom", + "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": "Default Sales Unit of Measure", + "length": 0, + "no_copy": 0, + "options": "UOM", + "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, - "default": "0", - "fieldname": "synced_with_hub", - "fieldtype": "Check", - "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": "Synced With Hub", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "income_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Income Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "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, - "depends_on": "", - "fieldname": "income_account", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Income Account", - "length": 0, - "no_copy": 0, - "options": "Account", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "selling_cost_center", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Selling Cost Center", + "length": 0, + "no_copy": 0, + "options": "Cost Center", + "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, - "depends_on": "", - "fieldname": "selling_cost_center", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Selling Cost Center", - "length": 0, - "no_copy": 0, - "options": "Cost Center", - "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, - "depends_on": "", - "fieldname": "column_break3", - "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": "Customer Item Codes", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Column Break", - "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, + "depends_on": "", + "fieldname": "column_break3", + "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": "Customer Item Codes", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Column Break", + "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, "width": "50%" - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "description": "", - "fieldname": "customer_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Customer Items", - "length": 0, - "no_copy": 0, - "options": "Item Customer Detail", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "description": "", + "fieldname": "customer_items", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Customer Items", + "length": 0, + "no_copy": 0, + "options": "Item Customer Detail", + "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, - "depends_on": "", - "fieldname": "max_discount", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Max Discount (%)", - "length": 0, - "no_copy": 0, - "oldfieldname": "max_discount", - "oldfieldtype": "Currency", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "max_discount", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Max Discount (%)", + "length": 0, + "no_copy": 0, + "oldfieldname": "max_discount", + "oldfieldtype": "Currency", + "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": 1, - "columns": 0, - "fieldname": "item_tax_section_break", - "fieldtype": "Section 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": "Item Tax", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-money", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "item_tax_section_break", + "fieldtype": "Section 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": "Item Tax", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-money", + "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, - "description": "Will also apply for variants", - "fieldname": "taxes", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Taxes", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_tax", - "oldfieldtype": "Table", - "options": "Item Tax", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "Will also apply for variants", + "fieldname": "taxes", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Taxes", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_tax", + "oldfieldtype": "Table", + "options": "Item Tax", + "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": 1, - "columns": 0, - "fieldname": "inspection_criteria", - "fieldtype": "Section 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": "Inspection Criteria", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-search", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "inspection_criteria", + "fieldtype": "Section 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": "Inspection Criteria", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-search", + "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, - "default": "", - "fieldname": "inspection_required_before_purchase", - "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": "Inspection Required before Purchase", - "length": 0, - "no_copy": 0, - "oldfieldname": "inspection_required", - "oldfieldtype": "Select", - "options": "", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fieldname": "inspection_required_before_purchase", + "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": "Inspection Required before Purchase", + "length": 0, + "no_copy": 0, + "oldfieldname": "inspection_required", + "oldfieldtype": "Select", + "options": "", + "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": "inspection_required_before_delivery", - "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": "Inspection Required before Delivery", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "inspection_required_before_delivery", + "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": "Inspection Required before Delivery", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)", - "description": "Will also apply to variants", - "fieldname": "quality_parameters", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Quality Parameters", - "length": 0, - "no_copy": 0, - "oldfieldname": "item_specification_details", - "oldfieldtype": "Table", - "options": "Item Quality Inspection Parameter", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:(doc.inspection_required_before_purchase || doc.inspection_required_before_delivery)", + "description": "Will also apply to variants", + "fieldname": "quality_parameters", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Quality Parameters", + "length": 0, + "no_copy": 0, + "oldfieldname": "item_specification_details", + "oldfieldtype": "Table", + "options": "Item Quality Inspection Parameter", + "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": 1, - "columns": 0, - "depends_on": "is_stock_item", - "fieldname": "manufacturing", - "fieldtype": "Section 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": "Manufacturing", - "length": 0, - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "fa fa-cogs", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "depends_on": "is_stock_item", + "fieldname": "manufacturing", + "fieldtype": "Section 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": "Manufacturing", + "length": 0, + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "fa fa-cogs", + "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, - "depends_on": "", - "fieldname": "default_bom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default BOM", - "length": 0, - "no_copy": 1, - "oldfieldname": "default_bom", - "oldfieldtype": "Link", - "options": "BOM", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "default_bom", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default BOM", + "length": 0, + "no_copy": 1, + "oldfieldname": "default_bom", + "oldfieldtype": "Link", + "options": "BOM", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "description": "If subcontracted to a vendor", - "fieldname": "is_sub_contracted_item", - "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": "Supply Raw Materials for Purchase", - "length": 0, - "no_copy": 0, - "oldfieldname": "is_sub_contracted_item", - "oldfieldtype": "Select", - "options": "", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "description": "If subcontracted to a vendor", + "fieldname": "is_sub_contracted_item", + "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": "Supply Raw Materials for Purchase", + "length": 0, + "no_copy": 0, + "oldfieldname": "is_sub_contracted_item", + "oldfieldtype": "Select", + "options": "", + "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_74", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_74", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer_code", - "fieldtype": "Data", - "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": "Customer Code", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "customer_code", + "fieldtype": "Data", + "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": "Customer Code", + "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": 1, - "columns": 0, - "fieldname": "website_section", - "fieldtype": "Section 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": "Website", - "length": 0, - "no_copy": 0, - "options": "fa fa-globe", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "website_section", + "fieldtype": "Section 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": "Website", + "length": 0, + "no_copy": 0, + "options": "fa fa-globe", + "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, - "depends_on": "eval:!doc.variant_of", - "fieldname": "show_in_website", - "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": "Show in Website", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:!doc.variant_of", + "fieldname": "show_in_website", + "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": "Show in Website", + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "variant_of", - "fieldname": "show_variant_in_website", - "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": "Show in Website (Variant)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "variant_of", + "fieldname": "show_variant_in_website", + "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": "Show in Website (Variant)", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "fieldname": "route", - "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": "Route", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "fieldname": "route", + "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": "Route", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 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.show_in_website || doc.show_variant_in_website", - "description": "Items with higher weightage will be shown higher", - "fieldname": "weightage", - "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": "Weightage", - "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": 1, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "description": "Items with higher weightage will be shown higher", + "fieldname": "weightage", + "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": "Weightage", + "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": 1, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "description": "Show a slideshow at the top of the page", - "fieldname": "slideshow", - "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": "Slideshow", - "length": 0, - "no_copy": 0, - "options": "Website Slideshow", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "description": "Show a slideshow at the top of the page", + "fieldname": "slideshow", + "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": "Slideshow", + "length": 0, + "no_copy": 0, + "options": "Website Slideshow", + "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, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "description": "Item Image (if not slideshow)", - "fieldname": "website_image", - "fieldtype": "Attach", - "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": "Image", - "length": 0, - "no_copy": 0, - "options": "", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "description": "Item Image (if not slideshow)", + "fieldname": "website_image", + "fieldtype": "Attach", + "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": "Image", + "length": 0, + "no_copy": 0, + "options": "", + "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": "thumbnail", - "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": "Thumbnail", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "thumbnail", + "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": "Thumbnail", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "cb72", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "cb72", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "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, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "description": "Show \"In Stock\" or \"Not in Stock\" based on stock available in this warehouse.", - "fieldname": "website_warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Website Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "description": "Show \"In Stock\" or \"Not in Stock\" based on stock available in this warehouse.", + "fieldname": "website_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Website Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "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, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "description": "List this Item in multiple groups on the website.", - "fieldname": "website_item_groups", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Website Item Groups", - "length": 0, - "no_copy": 0, - "options": "Website Item Group", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "description": "List this Item in multiple groups on the website.", + "fieldname": "website_item_groups", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Website Item Groups", + "length": 0, + "no_copy": 0, + "options": "Website Item Group", + "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": 1, - "collapsible_depends_on": "website_specifications", - "columns": 0, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "fieldname": "sb72", - "fieldtype": "Section 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": "Website Specifications", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "website_specifications", + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "fieldname": "sb72", + "fieldtype": "Section 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": "Website Specifications", + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "fieldname": "copy_from_item_group", - "fieldtype": "Button", - "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": "Copy From Item Group", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "fieldname": "copy_from_item_group", + "fieldtype": "Button", + "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": "Copy From Item Group", + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "fieldname": "website_specifications", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Website Specifications", - "length": 0, - "no_copy": 0, - "options": "Item Website Specification", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "fieldname": "website_specifications", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Website Specifications", + "length": 0, + "no_copy": 0, + "options": "Item Website Specification", + "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, - "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", - "fieldname": "web_long_description", - "fieldtype": "Text Editor", - "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": "Website Description", - "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, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval: doc.show_in_website || doc.show_variant_in_website", + "fieldname": "web_long_description", + "fieldtype": "Text Editor", + "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": "Website Description", + "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": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "total_projected_qty", - "fieldtype": "Float", - "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": "Total Projected Qty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "total_projected_qty", + "fieldtype": "Float", + "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": "Total Projected Qty", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:(!doc.is_item_from_hub)", + "fieldname": "hub_publishing_sb", + "fieldtype": "Section 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": "Hub Publishing Details", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "0", + "description": "Publish Item to hub.erpnext.com", + "fieldname": "publish_in_hub", + "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": "Publish in Hub", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "hub_category_to_publish", + "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": "Hub Category to Publish", + "length": 0, + "no_copy": 0, + "options": "Hub Category", + "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, + "description": "Publish \"In Stock\" or \"Not in Stock\" on Hub based on stock available in this warehouse.", + "fieldname": "hub_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Hub Warehouse", + "length": 0, + "no_copy": 0, + "options": "Warehouse", + "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, + "default": "0", + "fieldname": "synced_with_hub", + "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": "Synced With Hub", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-tag", - "idx": 2, - "image_field": "image", - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 1, - "modified": "2017-07-06 18:28:36.645217", - "modified_by": "Administrator", - "module": "Stock", - "name": "Item", - "owner": "Administrator", + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "icon": "fa fa-tag", + "idx": 2, + "image_field": "image", + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 1, + "modified": "2017-10-25 14:08:02.948326", + "modified_by": "Administrator", + "module": "Stock", + "name": "Item", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 1, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Item Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 1, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Item Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 - }, + }, { - "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": "Stock Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 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": "Stock Manager", + "set_user_permissions": 0, + "share": 0, + "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": "Stock User", - "set_user_permissions": 0, - "share": 0, - "submit": 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": "Stock 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": "Sales User", - "set_user_permissions": 0, - "share": 0, - "submit": 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": "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, + "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 - }, + }, { - "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": "Maintenance User", - "set_user_permissions": 0, - "share": 0, - "submit": 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": "Maintenance 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": "Accounts User", - "set_user_permissions": 0, - "share": 0, - "submit": 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": "Accounts 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": "Manufacturing User", - "set_user_permissions": 0, - "share": 0, - "submit": 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": "Manufacturing User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "search_fields": "item_name,description,item_group,customer_code", - "show_name_in_global_search": 1, - "sort_field": "idx desc, modified desc", - "sort_order": "DESC", - "title_field": "item_name", - "track_changes": 1, + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "search_fields": "item_name,description,item_group,customer_code", + "show_name_in_global_search": 1, + "sort_field": "idx desc, modified desc", + "sort_order": "DESC", + "title_field": "item_name", + "track_changes": 1, "track_seen": 0 } \ No newline at end of file diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index a810665997b..4b4f15bf417 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -17,6 +17,7 @@ from erpnext.controllers.item_variant import (get_variant, copy_attributes_to_va make_variant_item_code, validate_item_variant_attributes, ItemVariantExistsError) class DuplicateReorderRows(frappe.ValidationError): pass +class StockExistsForTemplate(frappe.ValidationError): pass class Item(WebsiteGenerator): website = frappe._dict( @@ -28,11 +29,15 @@ class Item(WebsiteGenerator): def onload(self): super(Item, self).onload() + self.set_onload('sle_exists', self.check_if_sle_exists()) if self.is_fixed_asset: asset = frappe.db.get_all("Asset", filters={"item_code": self.name, "docstatus": 1}, limit=1) self.set_onload("asset_exists", True if asset else False) + if frappe.db.get_value('Stock Ledger Entry', {'item_code': self.name}): + self.set_onload('stock_exists', True) + def autoname(self): if frappe.db.get_default("item_naming_by")=="Naming Series": if self.variant_of: @@ -52,7 +57,8 @@ class Item(WebsiteGenerator): if not self.description: self.description = self.item_name - self.publish_in_hub = 1 + if self.is_sales_item and not self.is_item_from_hub: + self.publish_in_hub = 1 def after_insert(self): '''set opening stock and item price''' @@ -63,6 +69,10 @@ class Item(WebsiteGenerator): self.set_opening_stock() def validate(self): + self.before_update = None + if frappe.db.exists('Item', self.name): + self.before_update = frappe.get_doc('Item', self.name) + super(Item, self).validate() if not self.item_name: @@ -85,6 +95,7 @@ class Item(WebsiteGenerator): self.synced_with_hub = 0 self.validate_has_variants() + self.validate_stock_exists_for_template_item() self.validate_attributes() self.validate_variant_attributes() self.validate_website_image() @@ -631,6 +642,12 @@ class Item(WebsiteGenerator): if frappe.db.exists("Item", {"variant_of": self.name}): frappe.throw(_("Item has variants.")) + def validate_stock_exists_for_template_item(self): + if self.has_variants and \ + frappe.db.get_value('Stock Ledger Entry', {'item_code': self.name}): + frappe.throw(_("As stock exists against an item {0}, you can not enable has variants property") + .format(self.name), StockExistsForTemplate) + def validate_uom(self): if not self.get("__islocal"): check_stock_uom_with_bin(self.name, self.stock_uom) @@ -815,4 +832,3 @@ def check_stock_uom_with_bin(item, stock_uom): if not matched: frappe.throw(_("Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. You will need to create a new Item to use a different Default UOM.").format(item)) - diff --git a/erpnext/stock/doctype/item/item_list.js b/erpnext/stock/doctype/item/item_list.js index cc46177f531..db53ae96516 100644 --- a/erpnext/stock/doctype/item/item_list.js +++ b/erpnext/stock/doctype/item/item_list.js @@ -4,12 +4,12 @@ frappe.listview_settings['Item'] = { filters: [["disabled", "=", "0"]], get_indicator: function(doc) { - if(doc.total_projected_qty < 0) { - return [__("Shortage"), "red", "total_projected_qty,<,0"]; - } else if (doc.disabled) { + if (doc.disabled) { return [__("Disabled"), "grey", "disabled,=,Yes"]; } else if (doc.end_of_life && doc.end_of_life < frappe.datetime.get_today()) { return [__("Expired"), "grey", "end_of_life,<,Today"]; + } else if(doc.total_projected_qty < 0) { + return [__("Shortage"), "red", "total_projected_qty,<,0"]; } else if (doc.has_variants) { return [__("Template"), "orange", "has_variants,=,Yes"]; } else if (doc.variant_of) { diff --git a/erpnext/stock/doctype/item/test_item.js b/erpnext/stock/doctype/item/test_item.js new file mode 100644 index 00000000000..af44278a59a --- /dev/null +++ b/erpnext/stock/doctype/item/test_item.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Item", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Item + () => frappe.tests.make('Item', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index 34e3af6102f..86934143607 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -8,6 +8,7 @@ import frappe from frappe.test_runner import make_test_records from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError, InvalidItemAttributeValueError, get_variant) +from erpnext.stock.doctype.item.item import StockExistsForTemplate from frappe.model.rename_doc import rename_doc from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry @@ -120,6 +121,8 @@ class TestItem(unittest.TestCase): self.assertRaises(ItemVariantExistsError, variant.save) def test_copy_fields_from_template_to_variants(self): + frappe.delete_doc_if_exists("Item", "_Test Variant Item-XL", force=1) + fields = [{'field_name': 'item_group'}, {'field_name': 'is_stock_item'}] allow_fields = [d.get('field_name') for d in fields] set_item_variant_settings(fields) @@ -188,7 +191,8 @@ class TestItem(unittest.TestCase): "increment": 0.5 } ], - "default_warehouse": "_Test Warehouse - _TC" + "default_warehouse": "_Test Warehouse - _TC", + "has_variants": 1 }) variant = create_variant("_Test Numeric Template Item", @@ -261,6 +265,15 @@ class TestItem(unittest.TestCase): self.assertEquals(variant.manufacturer, 'MSG1') self.assertEquals(variant.manufacturer_part_no, '007') + def test_stock_exists_against_template_item(self): + stock_item = frappe.get_all('Stock Ledger Entry', fields = ["item_code"], limit=1) + if stock_item: + item_code = stock_item[0].item_code + + item_doc = frappe.get_doc('Item', item_code) + item_doc.has_variants = 1 + self.assertRaises(StockExistsForTemplate, item_doc.save) + def set_item_variant_settings(fields): doc = frappe.get_doc('Item Variant Settings') doc.set('fields', fields) diff --git a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js index df78572dcb4..24f7e31a0cc 100644 --- a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js +++ b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.js @@ -5,7 +5,7 @@ frappe.ui.form.on('Item Variant Settings', { setup: function(frm) { const allow_fields = []; const exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website", - "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate", "variant_based_on"]; + "show_variant_in_website", "opening_stock", "variant_of", "valuation_rate"]; frappe.model.with_doctype('Item', () => { frappe.get_meta('Item').fields.forEach(d => { diff --git a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py index 0c6acd4290b..678de1a9ba7 100644 --- a/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py +++ b/erpnext/stock/doctype/item_variant_settings/item_variant_settings.py @@ -12,7 +12,7 @@ class ItemVariantSettings(Document): fields = frappe.get_meta('Item').fields exclude_fields = ["naming_series", "item_code", "item_name", "show_in_website", "show_variant_in_website", "standard_rate", "opening_stock", "image", "description", - "variant_of", "valuation_rate", "description", "variant_based_on", + "variant_of", "valuation_rate", "description", "website_image", "thumbnail", "website_specifiations", "web_long_description"] for d in fields: diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js index 7043fb7ba8e..9eb2313bb27 100644 --- a/erpnext/stock/doctype/material_request/material_request.js +++ b/erpnext/stock/doctype/material_request/material_request.js @@ -17,6 +17,9 @@ frappe.ui.form.on('Material Request', { // add item, if previous view was item erpnext.utils.add_item(frm); + //set schedule_date + set_schedule_date(frm); + // formatter for material request item frm.set_indicator_formatter('item_code', function(doc) { return (doc.qty<=doc.ordered_qty) ? "green" : "orange" }), @@ -38,12 +41,18 @@ frappe.ui.form.on("Material Request Item", { }, item_code: function(frm, doctype, name) { - frm.script_manager.copy_from_first_row('items', frm.selected_doc, - 'schedule_date'); + set_schedule_date(frm); }, schedule_date: function(frm, cdt, cdn) { - erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "schedule_date"); + var row = locals[cdt][cdn]; + if (row.schedule_date) { + if(!frm.doc.schedule_date) { + erpnext.utils.copy_value_in_all_row(frm.doc, cdt, cdn, "items", "schedule_date"); + } else { + set_schedule_date(frm); + } + } } }); @@ -227,6 +236,28 @@ erpnext.buying.MaterialRequestController = erpnext.buying.BuyingController.exten } } }); + }, + + validate: function() { + set_schedule_date(this.frm); + }, + + items_add: function(doc, cdt, cdn) { + var row = frappe.get_doc(cdt, cdn); + if(doc.schedule_date) { + row.schedule_date = doc.schedule_date; + refresh_field("schedule_date", cdn, "items"); + } else { + this.frm.script_manager.copy_from_first_row("items", row, ["schedule_date"]); + } + }, + + items_on_form_rendered: function() { + set_schedule_date(this.frm); + }, + + schedule_date: function() { + set_schedule_date(this.frm); } }); @@ -246,3 +277,9 @@ cur_frm.cscript['Unstop Material Request'] = function(){ cur_frm.refresh(); }); }; + +function set_schedule_date(frm) { + if(frm.doc.schedule_date){ + erpnext.utils.copy_value_in_all_row(frm.doc, frm.doc.doctype, frm.doc.name, "items", "schedule_date"); + } +} \ No newline at end of file diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json index 87cde0d3e2f..ba373453beb 100644 --- a/erpnext/stock/doctype/material_request/material_request.json +++ b/erpnext/stock/doctype/material_request/material_request.json @@ -42,6 +42,38 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "naming_series", + "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": "Series", + "length": 0, + "no_copy": 1, + "oldfieldname": "naming_series", + "oldfieldtype": "Select", + "options": "MREQ-", + "permlevel": 0, + "print_hide": 1, + "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": 1, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 1, @@ -133,69 +165,33 @@ }, { "allow_bulk_edit": 0, - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "naming_series", - "fieldtype": "Select", + "fieldname": "schedule_date", + "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 1, - "oldfieldname": "naming_series", - "oldfieldtype": "Select", - "options": "MREQ-", - "permlevel": 0, - "print_hide": 1, - "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": 1, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Amended From", + "label": "Required Date", "length": 0, - "no_copy": 1, - "oldfieldname": "amended_from", - "oldfieldtype": "Data", - "options": "Material Request", + "no_copy": 0, "permlevel": 0, - "print_hide": 1, + "precision": "", + "print_hide": 0, "print_hide_if_no_value": 0, - "print_width": "150px", - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, "search_index": 0, "set_only_once": 0, - "unique": 0, - "width": "150px" + "unique": 0 }, { "allow_bulk_edit": 0, @@ -232,6 +228,40 @@ "unique": 0, "width": "150px" }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "oldfieldname": "amended_from", + "oldfieldtype": "Data", + "options": "Material Request", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "print_width": "150px", + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, + "width": "150px" + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -686,7 +716,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2017-07-26 19:43:31.823549", + "modified": "2017-10-05 18:24:17.148782", "modified_by": "Administrator", "module": "Stock", "name": "Material Request", diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 65263a0694c..59075c588b7 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import cstr, flt, getdate, new_line_sep +from frappe.utils import cstr, flt, getdate, new_line_sep, nowdate, add_days from frappe import msgprint, _ from frappe.model.mapper import get_mapped_doc from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty @@ -53,11 +53,6 @@ class MaterialRequest(BuyingController): if actual_so_qty and (flt(so_items[so_no][item]) + already_indented > actual_so_qty): frappe.throw(_("Material Request of maximum {0} can be made for Item {1} against Sales Order {2}").format(actual_so_qty - already_indented, item, so_no)) - def validate_schedule_date(self): - for d in self.get('items'): - if d.schedule_date and getdate(d.schedule_date) < getdate(self.transaction_date): - frappe.throw(_("Expected Date cannot be before Material Request Date")) - # Validate # --------------------- def validate(self): @@ -70,9 +65,9 @@ class MaterialRequest(BuyingController): self.status = "Draft" from erpnext.controllers.status_updater import validate_status - validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled", "Pending", - "Partially Ordered", "Ordered", "Issued", "Transferred"] - ) + validate_status(self.status, + ["Draft", "Submitted", "Stopped", "Cancelled", "Pending", + "Partially Ordered", "Ordered", "Issued", "Transferred"]) validate_for_items(self) @@ -287,7 +282,7 @@ def make_purchase_order_based_on_supplier(source_name, target_doc=None): def postprocess(source, target_doc): target_doc.supplier = source_name - + target_doc.schedule_date = add_days(nowdate(), 1) target_doc.set("items", [d for d in target_doc.get("items") if d.get("item_code") in supplier_items and d.get("qty") > 0]) @@ -320,12 +315,12 @@ def get_material_requests_based_on_supplier(supplier): material_requests = frappe.db.sql_list("""select distinct mr.name from `tabMaterial Request` mr, `tabMaterial Request Item` mr_item where mr.name = mr_item.parent - and mr_item.item_code in (%s) - and mr.material_request_type = 'Purchase' - and mr.per_ordered < 99.99 - and mr.docstatus = 1 - and mr.status != 'Stopped' - order by mr_item.item_code ASC""" % ', '.join(['%s']*len(supplier_items)), + and mr_item.item_code in (%s) + and mr.material_request_type = 'Purchase' + and mr.per_ordered < 99.99 + and mr.docstatus = 1 + and mr.status != 'Stopped' + order by mr_item.item_code ASC""" % ', '.join(['%s']*len(supplier_items)), tuple(supplier_items)) else: material_requests = [] diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 1531f4096ea..a24957e2b07 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -206,6 +206,7 @@ class TestMaterialRequest(unittest.TestCase): po_doc = make_purchase_order(mr.name) po_doc.supplier = "_Test Supplier" po_doc.transaction_date = "2013-07-07" + po_doc.schedule_date = "2013-07-09" po_doc.get("items")[0].qty = 27.0 po_doc.get("items")[1].qty = 1.5 po_doc.get("items")[0].schedule_date = "2013-07-09" @@ -557,5 +558,5 @@ class TestMaterialRequest(unittest.TestCase): item_code= %s and warehouse= %s """, (mr.items[0].item_code, mr.items[0].warehouse))[0][0] self.assertEquals(requested_qty, new_requested_qty) -test_dependencies = ["Currency Exchange"] +test_dependencies = ["Currency Exchange", "BOM"] test_records = frappe.get_test_records('Material Request') diff --git a/erpnext/stock/doctype/material_request/test_records.json b/erpnext/stock/doctype/material_request/test_records.json index 09d1912ed74..1c714969eb3 100644 --- a/erpnext/stock/doctype/material_request/test_records.json +++ b/erpnext/stock/doctype/material_request/test_records.json @@ -29,7 +29,8 @@ ], "material_request_type": "Purchase", "naming_series": "_T-Material Request-", - "transaction_date": "2013-02-18" + "transaction_date": "2013-02-18", + "schedule_date": "2013-02-19" }, { "company": "_Test Company", @@ -43,13 +44,14 @@ "item_name": "_Test FG Item", "parentfield": "items", "qty": 5, - "schedule_date": "2013-02-18", + "schedule_date": "2013-02-19", "uom": "_Test UOM 1", "warehouse": "_Test Warehouse - _TC" } ], "material_request_type": "Manufacture", "naming_series": "_T-Material Request-", - "transaction_date": "2013-02-18" + "transaction_date": "2013-02-18", + "schedule_date": "2013-02-19" } ] \ No newline at end of file diff --git a/erpnext/stock/doctype/material_request/tests/test_material_request.js b/erpnext/stock/doctype/material_request/tests/test_material_request.js index 22d1088cfe7..bf26cd117f8 100644 --- a/erpnext/stock/doctype/material_request/tests/test_material_request.js +++ b/erpnext/stock/doctype/material_request/tests/test_material_request.js @@ -1,7 +1,7 @@ QUnit.module('Stock'); QUnit.test("test material request", function(assert) { - assert.expect(1); + assert.expect(5); let done = assert.async(); frappe.run_serially([ () => { @@ -11,14 +11,25 @@ QUnit.test("test material request", function(assert) { {'schedule_date': frappe.datetime.add_days(frappe.datetime.nowdate(), 5)}, {'qty': 5}, {'item_code': 'Test Product 1'}, + ], + [ + {'schedule_date': frappe.datetime.add_days(frappe.datetime.nowdate(), 6)}, + {'qty': 2}, + {'item_code': 'Test Product 2'}, ] ]}, ]); }, () => cur_frm.save(), () => { + assert.ok(cur_frm.doc.schedule_date == frappe.datetime.add_days(frappe.datetime.now_date(), 5), "Schedule Date correct"); + // get_item_details assert.ok(cur_frm.doc.items[0].item_name=='Test Product 1', "Item name correct"); + assert.ok(cur_frm.doc.items[0].schedule_date == frappe.datetime.add_days(frappe.datetime.now_date(), 5), "Schedule Date correct"); + + assert.ok(cur_frm.doc.items[1].item_name=='Test Product 2', "Item name correct"); + assert.ok(cur_frm.doc.items[1].schedule_date == frappe.datetime.add_days(frappe.datetime.now_date(), 6), "Schedule Date correct"); }, () => frappe.tests.click_button('Submit'), () => frappe.tests.click_button('Yes'), diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 2d089c4419e..e49f9937a56 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -19,8 +19,8 @@ form_grid_templates = { } class PurchaseReceipt(BuyingController): - def __init__(self, arg1, arg2=None): - super(PurchaseReceipt, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(PurchaseReceipt, self).__init__(*args, **kwargs) self.status_updater = [{ 'source_dt': 'Purchase Receipt Item', 'target_dt': 'Purchase Order Item', diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index c39efa06f71..80c93ef434d 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -20,8 +20,8 @@ class SerialNoNotExistsError(ValidationError): pass class SerialNoDuplicateError(ValidationError): pass class SerialNo(StockController): - def __init__(self, arg1, arg2=None): - super(SerialNo, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(SerialNo, self).__init__(*args, **kwargs) self.via_stock_ledger = False def validate(self): diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py index 4bcbcc4b6f4..0aecb78ddd6 100644 --- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py @@ -11,7 +11,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \ from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError from erpnext.stock.stock_ledger import get_previous_sle from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation -from erpnext.stock.doctype.item.test_item import set_item_variant_settings +from erpnext.stock.doctype.item.test_item import set_item_variant_settings, make_item_variant from frappe.tests.test_permissions import set_user_permission_doctypes from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry from erpnext.accounts.doctype.account.test_account import get_inventory_account @@ -46,6 +46,7 @@ class TestStockEntry(unittest.TestCase): make_stock_entry(item_code=item_code, target=warehouse, qty=1, basic_rate=10) sle = get_sle(item_code = item_code, warehouse = warehouse)[0] + self.assertEqual([[1, 10]], frappe.safe_eval(sle.stock_queue)) # negative qty @@ -74,7 +75,6 @@ class TestStockEntry(unittest.TestCase): frappe.db.set_default("allow_negative_stock", 0) def test_auto_material_request(self): - from erpnext.stock.doctype.item.test_item import make_item_variant make_item_variant() self._test_auto_material_request("_Test Item") self._test_auto_material_request("_Test Item", material_request_type="Transfer") @@ -82,6 +82,7 @@ class TestStockEntry(unittest.TestCase): def test_auto_material_request_for_variant(self): fields = [{'field_name': 'reorder_levels'}] set_item_variant_settings(fields) + make_item_variant() template = frappe.get_doc("Item", "_Test Variant Item") if not template.reorder_levels: diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 360ebca11ea..0f91e43223a 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -14,8 +14,8 @@ class OpeningEntryAccountError(frappe.ValidationError): pass class EmptyStockReconciliationItemsError(frappe.ValidationError): pass class StockReconciliation(StockController): - def __init__(self, arg1, arg2=None): - super(StockReconciliation, self).__init__(arg1, arg2) + def __init__(self, *args, **kwargs): + super(StockReconciliation, self).__init__(*args, **kwargs) self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] def validate(self): diff --git a/erpnext/stock/doctype/warehouse/test_records.json b/erpnext/stock/doctype/warehouse/test_records.json index af3bd231fc0..014cf3e5015 100644 --- a/erpnext/stock/doctype/warehouse/test_records.json +++ b/erpnext/stock/doctype/warehouse/test_records.json @@ -13,13 +13,6 @@ "warehouse_name": "_Test Scrap Warehouse", "is_group": 0 }, - { - "company": "_Test Company", - "create_account_under": "Stock Assets - _TC", - "doctype": "Warehouse", - "warehouse_name": "_Test Warehouse", - "is_group": 0 - }, { "company": "_Test Company", "create_account_under": "Fixed Assets - _TC", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 72a83c6c1b2..539e8a56676 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -164,6 +164,15 @@ def get_basic_details(args, item): warehouse = user_default_warehouse or item.default_warehouse or args.warehouse + #Set the UOM to the Default Sales UOM or Default Purchase UOM if configured in the Item Master + if not args.uom: + if args.get('doctype') in ['Quotation', 'Sales Order', 'Delivery Note', 'Sales Invoice']: + args.uom = item.sales_uom if item.sales_uom else item.stock_uom + elif args.get('doctype') in ['Purchase Order', 'Purchase Receipt', 'Purchase Invoice']: + args.uom = item.purchase_uom if item.purchase_uom else item.stock_uom + else: + args.uom = item.stock_uom + out = frappe._dict({ "item_code": item.name, "item_name": item.item_name, @@ -178,7 +187,7 @@ def get_basic_details(args, item): "batch_no": None, "item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in item.get("taxes")))), - "uom": item.stock_uom, + "uom": args.uom, "min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "", "qty": args.qty or 1.0, "stock_qty": args.qty or 1.0, diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 7c6b34bd909..180ccbb3e2b 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -461,6 +461,6 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no, if not allow_zero_rate and not valuation_rate \ and cint(erpnext.is_perpetual_inventory_enabled(company)): frappe.local.message_log = [] - frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a sample item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting/cancelling this entry").format(item_code, voucher_type, voucher_no)) + frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a zero valuation rate item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting/cancelling this entry").format(item_code, voucher_type, voucher_no)) return valuation_rate diff --git a/erpnext/support/doctype/issue/issue.js b/erpnext/support/doctype/issue/issue.js index 306736f3dc8..77c59f4edcc 100644 --- a/erpnext/support/doctype/issue/issue.js +++ b/erpnext/support/doctype/issue/issue.js @@ -4,7 +4,7 @@ frappe.ui.form.on("Issue", { }, "refresh": function(frm) { - if(frm.doc.status==="Open") { + if(frm.doc.status!=="Closed") { frm.add_custom_button(__("Close"), function() { frm.set_value("status", "Closed"); frm.save(); diff --git a/erpnext/support/report/minutes_to_first_response_for_issues/minutes_to_first_response_for_issues.js b/erpnext/support/report/minutes_to_first_response_for_issues/minutes_to_first_response_for_issues.js index e84b13ced5a..4cf07fa2987 100644 --- a/erpnext/support/report/minutes_to_first_response_for_issues/minutes_to_first_response_for_issues.js +++ b/erpnext/support/report/minutes_to_first_response_for_issues/minutes_to_first_response_for_issues.js @@ -18,23 +18,13 @@ frappe.query_reports["Minutes to First Response for Issues"] = { get_chart_data: function(columns, result) { return { data: { - x: 'Date', - columns: [ - ['Date'].concat($.map(result, function(d) { return d[0]; })), - ['Mins to first response'].concat($.map(result, function(d) { return d[1]; })) - ] - // rows: [['Date', 'Mins to first response']].concat(result) + labels: result.map(d => d[0]), + datasets: [{ + title: 'Mins to first response', + values: result.map(d => d[1]) + }] }, - axis: { - x: { - type: 'timeseries', - tick: { - format: frappe.ui.py_date_format - } - } - }, - chart_type: 'line', - + type: 'line', } } } diff --git a/erpnext/support/report/support_hour_distribution/support_hour_distribution.py b/erpnext/support/report/support_hour_distribution/support_hour_distribution.py index e96b7b21044..905ea6a5d92 100644 --- a/erpnext/support/report/support_hour_distribution/support_hour_distribution.py +++ b/erpnext/support/report/support_hour_distribution/support_hour_distribution.py @@ -24,7 +24,7 @@ def execute(filters=None): columns = get_columns() data, timeslot_wise_count = get_data(filters) - chart = get_chartdata(timeslot_wise_count) + chart = get_chart_data(timeslot_wise_count) return columns, data, None, chart def get_data(filters): @@ -75,23 +75,21 @@ def get_columns(): return columns -def get_chartdata(timeslot_wise_count): - x_interval = ['x'] - total_count = ['Total'] +def get_chart_data(timeslot_wise_count): + total_count = [] timeslots = ['12AM - 3AM', '3AM - 6AM', '6AM - 9AM', '9AM - 12PM', '12PM - 3PM', '3PM - 6PM', '6PM - 9PM', '9PM - 12AM'] - x_interval.extend(timeslots) - columns = [x_interval] + datasets = [] for data in timeslots: total_count.append(timeslot_wise_count.get(data, 0)) - columns.append(total_count) + datasets.append({'values': total_count}) chart = { "data": { - 'x': 'x', - 'columns': columns + 'labels': timeslots, + 'datasets': datasets } } - chart["chart_type"] = "line" + chart["type"] = "line" return chart diff --git a/erpnext/templates/emails/recurring_document_failed.html b/erpnext/templates/emails/recurring_document_failed.html index ea48034f418..f9e8c2dafcf 100644 --- a/erpnext/templates/emails/recurring_document_failed.html +++ b/erpnext/templates/emails/recurring_document_failed.html @@ -1,11 +1,11 @@

{{_("Recurring")}} {{ type }} {{ _("Failed")}}

-

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.

+

{{_("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.")}}


-

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 -of this {{ type }} for generating the recurring {{ type }} in the subscription {{ subscription }}.

-

[This email is autogenerated]

+

{{_("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 +of this')}} {{ type }} {{_("for generating the recurring")}} {{ type }} {{_("in the subscription")}} {{ subscription }}.

+

[{{_("This email is autogenerated")}}]

diff --git a/erpnext/templates/includes/product_page.js b/erpnext/templates/includes/product_page.js index b2d5ad952b4..93dadaa589e 100644 --- a/erpnext/templates/includes/product_page.js +++ b/erpnext/templates/includes/product_page.js @@ -7,7 +7,7 @@ frappe.ready(function() { frappe.call({ type: "POST", - method: "erpnext.shopping_cart.product.get_product_info", + method: "erpnext.shopping_cart.product_info.get_product_info_for_website", args: { item_code: get_item_code() }, diff --git a/erpnext/templates/utils.py b/erpnext/templates/utils.py index 6ebe41185fd..7ee39602f55 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 0bd74915c29..949e92b1ca4 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 909216b92eb..e7de60439ae 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 @@ -86,6 +85,7 @@ erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice.js erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment.js erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_payment_request.js erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.js +erpnext/accounts/doctype/payment_entry/tests/test_payment_against_purchase_invoice.js erpnext/buying/doctype/supplier_quotation/tests/test_supplier_quotation_for_item_wise_discount.js erpnext/buying/doctype/purchase_order/tests/test_purchase_order.js erpnext/buying/doctype/purchase_order/tests/test_purchase_order_with_multi_uom.js @@ -128,3 +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 +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 diff --git a/erpnext/shopping_cart/product.py b/erpnext/utilities/product.py similarity index 50% rename from erpnext/shopping_cart/product.py rename to erpnext/utilities/product.py index 0d6eccd62b4..1ad8b6e5ee5 100644 --- a/erpnext/shopping_cart/product.py +++ b/erpnext/utilities/product.py @@ -5,51 +5,15 @@ from __future__ import unicode_literals import frappe from frappe.utils import cint, fmt_money, flt -from erpnext.shopping_cart.cart import _get_cart_quotation -from erpnext.shopping_cart.doctype.shopping_cart_settings.shopping_cart_settings \ - import is_cart_enabled, get_shopping_cart_settings, show_quantity_in_website from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item -@frappe.whitelist(allow_guest=True) -def get_product_info(item_code): - """get product price / stock info""" - if not is_cart_enabled(): - return {} - - qty = 0 - cart_quotation = _get_cart_quotation() - template_item_code = frappe.db.get_value("Item", item_code, "variant_of") - stock_status = get_qty_in_stock(item_code, template_item_code) - in_stock = stock_status.in_stock - stock_qty = stock_status.stock_qty - price = get_price(item_code, template_item_code, cart_quotation.selling_price_list) - - if price: - price["formatted_price"] = fmt_money(price["price_list_rate"], currency=price["currency"]) - - price["currency"] = not cint(frappe.db.get_default("hide_currency_symbol")) \ - and (frappe.db.get_value("Currency", price.currency, "symbol") or price.currency) \ - or "" - - if frappe.session.user != "Guest": - item = cart_quotation.get({"item_code": item_code}) - if item: - qty = item[0].qty - - return { - "price": price, - "stock_qty": stock_qty, - "in_stock": in_stock, - "uom": frappe.db.get_value("Item", item_code, "stock_uom"), - "qty": qty, - "show_stock_qty": show_quantity_in_website() - } - -def get_qty_in_stock(item_code, template_item_code): +def get_qty_in_stock(item_code, item_warehouse_field): in_stock, stock_qty = 0, '' - warehouse = frappe.db.get_value("Item", item_code, "website_warehouse") + template_item_code = frappe.db.get_value("Item", item_code, "variant_of") + + warehouse = frappe.db.get_value("Item", item_code, item_warehouse_field) if not warehouse and template_item_code and template_item_code != item_code: - warehouse = frappe.db.get_value("Item", template_item_code, "website_warehouse") + warehouse = frappe.db.get_value("Item", template_item_code, item_warehouse_field) if warehouse: stock_qty = frappe.db.sql("""select actual_qty from tabBin where @@ -59,10 +23,10 @@ def get_qty_in_stock(item_code, template_item_code): return frappe._dict({"in_stock": in_stock, "stock_qty": stock_qty}) -def get_price(item_code, template_item_code, price_list, qty=1): - if price_list: - cart_settings = get_shopping_cart_settings() +def get_price(item_code, price_list, customer_group, company, qty=1): + template_item_code = frappe.db.get_value("Item", item_code, "variant_of") + if price_list: price = frappe.get_all("Item Price", fields=["price_list_rate", "currency"], filters={"price_list": price_list, "item_code": item_code}) @@ -76,8 +40,8 @@ def get_price(item_code, template_item_code, price_list, qty=1): "qty": qty, "transaction_type": "selling", "price_list": price_list, - "customer_group": cart_settings.default_customer_group, - "company": cart_settings.company, + "customer_group": customer_group, + "company": company, "conversion_rate": 1, "for_shopping_cart": True })) @@ -89,4 +53,21 @@ def get_price(item_code, template_item_code, price_list, qty=1): if pricing_rule.pricing_rule_for == "Price": price[0].price_list_rate = pricing_rule.price_list_rate - return price[0] + price_obj = price[0] + if price_obj: + price_obj["formatted_price"] = fmt_money(price_obj["price_list_rate"], currency=price_obj["currency"]) + + price_obj["currency_symbol"] = not cint(frappe.db.get_default("hide_currency_symbol")) \ + and (frappe.db.get_value("Currency", price_obj.currency, "symbol") or price_obj.currency) \ + or "" + + if not price_obj["price_list_rate"]: + price_obj["price_list_rate"] = 0 + + if not price_obj["currency"]: + price_obj["currency"] = "" + + if not price_obj["formatted_price"]: + price_obj["formatted_price"] = "" + + return price_obj diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py index 0e3a4f95251..65310aa9e30 100644 --- a/erpnext/utilities/transaction_base.py +++ b/erpnext/utilities/transaction_base.py @@ -25,7 +25,7 @@ class TransactionBase(StatusUpdater): if not getattr(self, 'set_posting_time', None): now = now_datetime() self.posting_date = now.strftime('%Y-%m-%d') - self.posting_time = now.strftime('%H:%M:%S') + self.posting_time = now.strftime('%H:%M:%S.%f') def add_calendar_event(self, opts, force=False): if cstr(self.contact_by) != cstr(self._prev.contact_by) or \