From 35a6b58c127695e016495765d94d45b41eb8550d Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Tue, 18 Jan 2022 13:10:23 +0530 Subject: [PATCH 01/53] feat: purchase grouped asset --- erpnext/assets/doctype/asset/asset.json | 11 ++++++++++- erpnext/controllers/buying_controller.py | 20 ++++++++++++++------ erpnext/stock/doctype/item/item.json | 11 ++++++++++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index de060757e2..3c3be98b07 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -35,6 +35,7 @@ "available_for_use_date", "column_break_23", "gross_purchase_amount", + "asset_quantity", "purchase_date", "section_break_23", "calculate_depreciation", @@ -480,6 +481,12 @@ "fieldname": "section_break_36", "fieldtype": "Section Break", "label": "Finance Books" + }, + { + "fieldname": "asset_quantity", + "fieldtype": "Int", + "label": "Asset Quantity", + "read_only": 1 } ], "idx": 72, @@ -502,10 +509,11 @@ "link_fieldname": "asset" } ], - "modified": "2021-06-24 14:58:51.097908", + "modified": "2022-01-18 12:57:36.741192", "modified_by": "Administrator", "module": "Assets", "name": "Asset", + "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", "permissions": [ { @@ -542,6 +550,7 @@ "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "title_field": "asset_name", "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index a3d2502268..f088b9ffc2 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -554,10 +554,13 @@ class BuyingController(StockController, Subcontracting): # Check for asset naming series if item_data.get('asset_naming_series'): created_assets = [] - - for qty in range(cint(d.qty)): - asset = self.make_asset(d) + if item_data.get('is_grouped_asset'): + asset = self.make_asset(d, is_grouped_asset=True) created_assets.append(asset) + else: + for qty in range(cint(d.qty)): + asset = self.make_asset(d) + created_assets.append(asset) if len(created_assets) > 5: # dont show asset form links if more than 5 assets are created @@ -580,14 +583,18 @@ class BuyingController(StockController, Subcontracting): for message in messages: frappe.msgprint(message, title="Success", indicator="green") - def make_asset(self, row): + def make_asset(self, row, is_grouped_asset=False): if not row.asset_location: frappe.throw(_("Row {0}: Enter location for the asset item {1}").format(row.idx, row.item_code)) item_data = frappe.db.get_value('Item', row.item_code, ['asset_naming_series', 'asset_category'], as_dict=1) - purchase_amount = flt(row.base_rate + row.item_tax_amount) + if is_grouped_asset: + purchase_amount = flt(row.base_amount + row.item_tax_amount) + else: + purchase_amount = flt(row.base_rate + row.item_tax_amount) + asset = frappe.get_doc({ 'doctype': 'Asset', 'item_code': row.item_code, @@ -601,6 +608,7 @@ class BuyingController(StockController, Subcontracting): 'calculate_depreciation': 1, 'purchase_receipt_amount': purchase_amount, 'gross_purchase_amount': purchase_amount, + 'asset_quantity': row.qty if is_grouped_asset else 0, 'purchase_receipt': self.name if self.doctype == 'Purchase Receipt' else None, 'purchase_invoice': self.name if self.doctype == 'Purchase Invoice' else None }) @@ -687,7 +695,7 @@ class BuyingController(StockController, Subcontracting): def get_asset_item_details(asset_items): asset_items_data = {} - for d in frappe.get_all('Item', fields = ["name", "auto_create_assets", "asset_naming_series"], + for d in frappe.get_all('Item', fields = ["name", "auto_create_assets", "asset_naming_series", "is_grouped_asset"], filters = {'name': ('in', asset_items)}): asset_items_data.setdefault(d.name, d) diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 29abd45fcc..2d28cc09f9 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -28,6 +28,7 @@ "standard_rate", "is_fixed_asset", "auto_create_assets", + "is_grouped_asset", "asset_category", "asset_naming_series", "over_delivery_receipt_allowance", @@ -1026,6 +1027,13 @@ "fieldname": "grant_commission", "fieldtype": "Check", "label": "Grant Commission" + }, + { + "default": "0", + "depends_on": "auto_create_assets", + "fieldname": "is_grouped_asset", + "fieldtype": "Check", + "label": "Create Grouped Asset" } ], "has_web_view": 1, @@ -1034,7 +1042,7 @@ "image_field": "image", "index_web_pages_for_search": 1, "links": [], - "modified": "2021-12-14 04:13:16.857534", + "modified": "2022-01-18 12:57:54.273202", "modified_by": "Administrator", "module": "Stock", "name": "Item", @@ -1104,6 +1112,7 @@ "show_preview_popup": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "title_field": "item_name", "track_changes": 1 } \ No newline at end of file From e44c4e007a28072c2671aeb644acd25cbcbe4c5b Mon Sep 17 00:00:00 2001 From: Anupam Date: Wed, 19 Jan 2022 12:54:00 +0530 Subject: [PATCH 02/53] fix: contact duplication on converting lead to customer --- erpnext/selling/doctype/customer/customer.py | 68 +++++--------------- 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index b7f74df105..64196b5797 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -178,60 +178,22 @@ class Customer(TransactionBase): def create_lead_address_contact(self): if self.lead_name: - # assign lead address to customer (if already not set) - address_names = frappe.get_all('Dynamic Link', filters={ - "parenttype":"Address", - "link_doctype":"Lead", - "link_name":self.lead_name - }, fields=["parent as name"]) + # assign lead address and contact to customer (if already not set) + linked_contacts_and_addresses = frappe.get_all( + "Dynamic Link", + filters=[ + ["parenttype", "in", ["Contact", "Address"]], + ["link_doctype", "=", "Lead"], + ["link_name", "=", self.lead_name], + ], + fields=["parent as name", "parenttype as doctype"], + ) - for address_name in address_names: - address = frappe.get_doc('Address', address_name.get('name')) - if not address.has_link('Customer', self.name): - address.append('links', dict(link_doctype='Customer', link_name=self.name)) - address.save(ignore_permissions=self.flags.ignore_permissions) - - lead = frappe.db.get_value("Lead", self.lead_name, ["company_name", "lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True) - - if not lead.lead_name: - frappe.throw(_("Please mention the Lead Name in Lead {0}").format(self.lead_name)) - - contact_names = frappe.get_all('Dynamic Link', filters={ - "parenttype":"Contact", - "link_doctype":"Lead", - "link_name":self.lead_name - }, fields=["parent as name"]) - - for contact_name in contact_names: - contact = frappe.get_doc('Contact', contact_name.get('name')) - if not contact.has_link('Customer', self.name): - contact.append('links', dict(link_doctype='Customer', link_name=self.name)) - contact.save(ignore_permissions=self.flags.ignore_permissions) - - if not contact_names: - lead.lead_name = lead.lead_name.lstrip().split(" ") - lead.first_name = lead.lead_name[0] - lead.last_name = " ".join(lead.lead_name[1:]) - - # create contact from lead - contact = frappe.new_doc('Contact') - contact.first_name = lead.first_name - contact.last_name = lead.last_name - contact.gender = lead.gender - contact.salutation = lead.salutation - contact.email_id = lead.email_id - contact.phone = lead.phone - contact.mobile_no = lead.mobile_no - contact.is_primary_contact = 1 - contact.append('links', dict(link_doctype='Customer', link_name=self.name)) - if lead.email_id: - contact.append('email_ids', dict(email_id=lead.email_id, is_primary=1)) - if lead.mobile_no: - contact.append('phone_nos', dict(phone=lead.mobile_no, is_primary_mobile_no=1)) - contact.flags.ignore_permissions = self.flags.ignore_permissions - contact.autoname() - if not frappe.db.exists("Contact", contact.name): - contact.insert() + for row in linked_contacts_and_addresses: + linked_doc = frappe.get_doc(row.doctype, row.name) + if not linked_doc.has_link('Customer', self.name): + linked_doc.append('links', dict(link_doctype='Customer', link_name=self.name)) + linked_doc.save(ignore_permissions=self.flags.ignore_permissions) def validate_name_with_customer_group(self): if frappe.db.exists("Customer Group", self.name): From 6ebee9b4c4dfb21ce8ec956718751c83ae19deed Mon Sep 17 00:00:00 2001 From: Anupam Date: Wed, 19 Jan 2022 13:05:48 +0530 Subject: [PATCH 03/53] fix: changed function name --- erpnext/selling/doctype/customer/customer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 64196b5797..d74d5a6df9 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -142,7 +142,7 @@ class Customer(TransactionBase): self.update_lead_status() if self.flags.is_new_doc: - self.create_lead_address_contact() + self.link_lead_address_and_contact() self.update_customer_groups() @@ -176,7 +176,7 @@ class Customer(TransactionBase): if self.lead_name: frappe.db.set_value("Lead", self.lead_name, "status", "Converted") - def create_lead_address_contact(self): + def link_lead_address_and_contact(self): if self.lead_name: # assign lead address and contact to customer (if already not set) linked_contacts_and_addresses = frappe.get_all( From 7d8eef5c4edc263e9308a461f2589d248f5478b0 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Wed, 19 Jan 2022 15:31:20 +0530 Subject: [PATCH 04/53] fix: cannot set asset quantity for existing assets --- erpnext/assets/doctype/asset/asset.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset/asset.json b/erpnext/assets/doctype/asset/asset.json index 3c3be98b07..0a7c041396 100644 --- a/erpnext/assets/doctype/asset/asset.json +++ b/erpnext/assets/doctype/asset/asset.json @@ -486,7 +486,7 @@ "fieldname": "asset_quantity", "fieldtype": "Int", "label": "Asset Quantity", - "read_only": 1 + "read_only_depends_on": "eval:!doc.is_existing_asset" } ], "idx": 72, From a5643d500e9989420e41a945598f9f38e10da731 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Wed, 19 Jan 2022 15:31:31 +0530 Subject: [PATCH 05/53] test: purchase of grouped assets --- erpnext/assets/doctype/asset/test_asset.py | 36 +++++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 44c4ce542d..b2638bbf23 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -134,6 +134,29 @@ class TestAsset(AssetSetup): pr.cancel() self.assertEqual(asset.docstatus, 2) + def test_purchase_of_grouped_asset(self): + create_fixed_asset_item("Rack", is_grouped_asset=1) + pr = make_purchase_receipt(item_code="Rack", qty=3, rate=100000.0, location="Test Location") + + asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name') + asset = frappe.get_doc('Asset', asset_name) + self.assertEqual(asset.asset_quantity, 3) + asset.calculate_depreciation = 1 + + month_end_date = get_last_day(nowdate()) + purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15) + + asset.available_for_use_date = purchase_date + asset.purchase_date = purchase_date + asset.append("finance_books", { + "expected_value_after_useful_life": 10000, + "depreciation_method": "Straight Line", + "total_number_of_depreciations": 3, + "frequency_of_depreciation": 10, + "depreciation_start_date": month_end_date + }) + asset.submit() + def test_is_fixed_asset_set(self): asset = create_asset(is_existing_asset = 1) doc = frappe.new_doc('Purchase Invoice') @@ -1202,13 +1225,13 @@ def create_asset_category(): }) asset_category.insert() -def create_fixed_asset_item(): +def create_fixed_asset_item(item_code=None, auto_create_assets=1, is_grouped_asset=0): meta = frappe.get_meta('Asset') naming_series = meta.get_field("naming_series").options.splitlines()[0] or 'ACC-ASS-.YYYY.-' try: - frappe.get_doc({ + item = frappe.get_doc({ "doctype": "Item", - "item_code": "Macbook Pro", + "item_code": item_code or "Macbook Pro", "item_name": "Macbook Pro", "description": "Macbook Pro Retina Display", "asset_category": "Computers", @@ -1216,11 +1239,14 @@ def create_fixed_asset_item(): "stock_uom": "Nos", "is_stock_item": 0, "is_fixed_asset": 1, - "auto_create_assets": 1, + "auto_create_assets": auto_create_assets, + "is_grouped_asset": is_grouped_asset, "asset_naming_series": naming_series - }).insert() + }) + item.insert() except frappe.DuplicateEntryError: pass + return item def set_depreciation_settings_in_company(): company = frappe.get_doc("Company", "_Test Company") From ed0f9cc0639773e1a6880b836832f390556d43a7 Mon Sep 17 00:00:00 2001 From: ruthra Date: Wed, 19 Jan 2022 15:50:04 +0530 Subject: [PATCH 06/53] refactor: a more generalized way to clear old entries for test cases --- .../test_deferred_revenue_and_expense.py | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py index 1de6fb6824..5604b740d9 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py @@ -17,10 +17,42 @@ from erpnext.stock.doctype.item.test_item import create_item class TestDeferredRevenueAndExpense(unittest.TestCase): @classmethod def setUpClass(self): - clear_old_entries() + clear_accounts_and_items() create_company() + self.maxDiff = None + + def clear_old_entries(self): + sinv = qb.DocType("Sales Invoice") + sinv_item = qb.DocType("Sales Invoice Item") + pinv = qb.DocType("Purchase Invoice") + pinv_item = qb.DocType("Purchase Invoice Item") + + # delete existing invoices with deferred items + deferred_invoices = ( + qb.from_(sinv) + .join(sinv_item) + .on(sinv.name == sinv_item.parent) + .select(sinv.name) + .where(sinv_item.enable_deferred_revenue == 1) + .run() + ) + if deferred_invoices: + qb.from_(sinv).delete().where(sinv.name.isin(deferred_invoices)).run() + + deferred_invoices = ( + qb.from_(pinv) + .join(pinv_item) + .on(pinv.name == pinv_item.parent) + .select(pinv.name) + .where(pinv_item.enable_deferred_expense == 1) + .run() + ) + if deferred_invoices: + qb.from_(pinv).delete().where(pinv.name.isin(deferred_invoices)).run() def test_deferred_revenue(self): + self.clear_old_entries() + # created deferred expense accounts, if not found deferred_revenue_account = create_account( account_name="Deferred Revenue", @@ -108,6 +140,8 @@ class TestDeferredRevenueAndExpense(unittest.TestCase): self.assertEqual(report.period_total, expected) def test_deferred_expense(self): + self.clear_old_entries() + # created deferred expense accounts, if not found deferred_expense_account = create_account( account_name="Deferred Expense", @@ -209,15 +243,11 @@ def create_company(): company.insert() -def clear_old_entries(): +def clear_accounts_and_items(): item = qb.DocType("Item") account = qb.DocType("Account") customer = qb.DocType("Customer") supplier = qb.DocType("Supplier") - sinv = qb.DocType("Sales Invoice") - sinv_item = qb.DocType("Sales Invoice Item") - pinv = qb.DocType("Purchase Invoice") - pinv_item = qb.DocType("Purchase Invoice Item") qb.from_(account).delete().where( (account.account_name == "Deferred Revenue") @@ -228,26 +258,3 @@ def clear_old_entries(): ).run() qb.from_(customer).delete().where(customer.customer_name == "_Test Customer DR").run() qb.from_(supplier).delete().where(supplier.supplier_name == "_Test Furniture Supplier").run() - - # delete existing invoices with deferred items - deferred_invoices = ( - qb.from_(sinv) - .join(sinv_item) - .on(sinv.name == sinv_item.parent) - .select(sinv.name) - .where(sinv_item.enable_deferred_revenue == 1) - .run() - ) - if deferred_invoices: - qb.from_(sinv).delete().where(sinv.name.isin(deferred_invoices)).run() - - deferred_invoices = ( - qb.from_(pinv) - .join(pinv_item) - .on(pinv.name == pinv_item.parent) - .select(pinv.name) - .where(pinv_item.enable_deferred_expense == 1) - .run() - ) - if deferred_invoices: - qb.from_(pinv).delete().where(pinv.name.isin(deferred_invoices)).run() From 1e0450ed17fc9e02567ad3a910dc521ad8ce8900 Mon Sep 17 00:00:00 2001 From: ruthra Date: Wed, 19 Jan 2022 15:51:40 +0530 Subject: [PATCH 07/53] test: unit test for deferred items with zero months --- .../test_deferred_revenue_and_expense.py | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py index 5604b740d9..86eb2134fe 100644 --- a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py +++ b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py @@ -232,6 +232,91 @@ class TestDeferredRevenueAndExpense(unittest.TestCase): ] self.assertEqual(report.period_total, expected) + def test_zero_months(self): + self.clear_old_entries() + # created deferred expense accounts, if not found + deferred_revenue_account = create_account( + account_name="Deferred Revenue", + parent_account="Current Liabilities - _CD", + company="_Test Company DR", + ) + + acc_settings = frappe.get_doc("Accounts Settings", "Accounts Settings") + acc_settings.book_deferred_entries_based_on = "Months" + acc_settings.save() + + customer = frappe.new_doc("Customer") + customer.customer_name = "_Test Customer DR" + customer.type = "Individual" + customer.insert() + + item = create_item( + "_Test Internet Subscription", + is_stock_item=0, + warehouse="All Warehouses - _CD", + company="_Test Company DR", + ) + item.enable_deferred_revenue = 1 + item.deferred_revenue_account = deferred_revenue_account + item.no_of_months = 0 + item.save() + + si = create_sales_invoice( + item=item.name, + company="_Test Company DR", + customer="_Test Customer DR", + debit_to="Debtors - _CD", + posting_date="2021-05-01", + parent_cost_center="Main - _CD", + cost_center="Main - _CD", + do_not_submit=True, + rate=300, + price_list_rate=300, + ) + si.items[0].enable_deferred_revenue = 1 + si.items[0].deferred_revenue_account = deferred_revenue_account + si.items[0].income_account = "Sales - _CD" + si.save() + si.submit() + + pda = frappe.get_doc( + dict( + doctype="Process Deferred Accounting", + posting_date=nowdate(), + start_date="2021-05-01", + end_date="2021-08-01", + type="Income", + company="_Test Company DR", + ) + ) + pda.insert() + pda.submit() + + # execute report + fiscal_year = frappe.get_doc("Fiscal Year", frappe.defaults.get_user_default("fiscal_year")) + self.filters = frappe._dict( + { + "company": frappe.defaults.get_user_default("Company"), + "filter_based_on": "Date Range", + "period_start_date": "2021-05-01", + "period_end_date": "2021-08-01", + "from_fiscal_year": fiscal_year.year, + "to_fiscal_year": fiscal_year.year, + "periodicity": "Monthly", + "type": "Revenue", + "with_upcoming_postings": False, + } + ) + + report = Deferred_Revenue_and_Expense_Report(filters=self.filters) + report.run() + expected = [ + {"key": "may_2021", "total": 300.0, "actual": 300.0}, + {"key": "jun_2021", "total": 0, "actual": 0}, + {"key": "jul_2021", "total": 0, "actual": 0}, + {"key": "aug_2021", "total": 0, "actual": 0}, + ] + self.assertEqual(report.period_total, expected) def create_company(): company = frappe.db.exists("Company", "_Test Company DR") From d36092d448f3d87fabe67b1d5ed729c1786c9d2a Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Wed, 19 Jan 2022 18:27:19 +0530 Subject: [PATCH 08/53] patch: set default asset quantity as 1 --- erpnext/patches.txt | 3 ++- erpnext/patches/v13_0/update_asset_quantity_field.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 erpnext/patches/v13_0/update_asset_quantity_field.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index fa62b7fc27..2fa668e84f 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -326,4 +326,5 @@ erpnext.patches.v13_0.agriculture_deprecation_warning erpnext.patches.v14_0.delete_agriculture_doctypes erpnext.patches.v13_0.update_exchange_rate_settings erpnext.patches.v14_0.rearrange_company_fields -erpnext.patches.v14_0.update_leave_notification_template \ No newline at end of file +erpnext.patches.v14_0.update_leave_notification_template +erpnext.patches.v13_0.update_asset_quantity_field \ No newline at end of file diff --git a/erpnext/patches/v13_0/update_asset_quantity_field.py b/erpnext/patches/v13_0/update_asset_quantity_field.py new file mode 100644 index 0000000000..47884d1968 --- /dev/null +++ b/erpnext/patches/v13_0/update_asset_quantity_field.py @@ -0,0 +1,8 @@ +import frappe + + +def execute(): + if frappe.db.count('Asset'): + frappe.reload_doc("assets", "doctype", "Asset") + asset = frappe.qb.DocType('Asset') + frappe.qb.update(asset).set(asset.asset_quantity, 1).run() \ No newline at end of file From 04d64567ef36073f8b62c6b6d1ff66b90f2fb30c Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Wed, 19 Jan 2022 19:37:55 +0530 Subject: [PATCH 09/53] fix: cannot cancel jv after migrating from v12 --- erpnext/patches.txt | 3 ++- .../v13_0/delete_bank_reconciliation_detail.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 erpnext/patches/v13_0/delete_bank_reconciliation_detail.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 1f83c4fed7..34899e4ca2 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -327,4 +327,5 @@ erpnext.patches.v13_0.agriculture_deprecation_warning erpnext.patches.v14_0.delete_agriculture_doctypes erpnext.patches.v13_0.update_exchange_rate_settings erpnext.patches.v14_0.rearrange_company_fields -erpnext.patches.v14_0.update_leave_notification_template \ No newline at end of file +erpnext.patches.v14_0.update_leave_notification_template +erpnext.patches.v13_0.delete_bank_reconciliation_detail \ No newline at end of file diff --git a/erpnext/patches/v13_0/delete_bank_reconciliation_detail.py b/erpnext/patches/v13_0/delete_bank_reconciliation_detail.py new file mode 100644 index 0000000000..75953b0e30 --- /dev/null +++ b/erpnext/patches/v13_0/delete_bank_reconciliation_detail.py @@ -0,0 +1,13 @@ +# Copyright (c) 2019, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + + +import frappe + + +def execute(): + + if frappe.db.exists('DocType', 'Bank Reconciliation Detail') and \ + frappe.db.exists('DocType', 'Bank Clearance Detail'): + + frappe.delete_doc("DocType", 'Bank Reconciliation Detail', force=1) From 50c276f64fdad179f8fafe43bb543af1f2bcfc62 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 20 Jan 2022 10:56:49 +0530 Subject: [PATCH 10/53] fix: bypass_credit_limit_check in credit balance report --- .../report/customer_credit_balance/customer_credit_balance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py index 777b02ca66..0997b51cd2 100644 --- a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py +++ b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py @@ -23,7 +23,7 @@ def execute(filters=None): row = [] outstanding_amt = get_customer_outstanding(d.name, filters.get("company"), - ignore_outstanding_sales_order=d.bypass_credit_limit_check_at_sales_order) + ignore_outstanding_sales_order=d.bypass_credit_limit_check) credit_limit = get_credit_limit(d.name, filters.get("company")) @@ -35,7 +35,7 @@ def execute(filters=None): d.disabled] else: row = [d.name, credit_limit, outstanding_amt, bal, - d.bypass_credit_limit_check_at_sales_order, d.is_frozen, d.disabled] + d.bypass_credit_limit_check, d.is_frozen, d.disabled] if credit_limit: data.append(row) From e34da90653b2b4ee187b23e2a13b7c9e8a20dc1e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 20 Jan 2022 10:51:59 +0530 Subject: [PATCH 11/53] fix: Cleanup empty rows on bank statement import (cherry picked from commit 25398d017bca53f14c7ebb6c9f937ef7c1390093) --- .../bank_statement_import.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py index e786d13c95..1403303f53 100644 --- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py +++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.py @@ -16,6 +16,7 @@ from frappe.utils.xlsxutils import ILLEGAL_CHARACTERS_RE, handle_html from openpyxl.styles import Font from openpyxl.utils import get_column_letter +INVALID_VALUES = ("", None) class BankStatementImport(DataImport): def __init__(self, *args, **kwargs): @@ -95,6 +96,18 @@ def download_errored_template(data_import_name): data_import = frappe.get_doc("Bank Statement Import", data_import_name) data_import.export_errored_rows() +def parse_data_from_template(raw_data): + data = [] + + for i, row in enumerate(raw_data): + if all(v in INVALID_VALUES for v in row): + # empty row + continue + + data.append(row) + + return data + def start_import(data_import, bank_account, import_file_path, google_sheets_url, bank, template_options): """This method runs in background job""" @@ -104,7 +117,8 @@ def start_import(data_import, bank_account, import_file_path, google_sheets_url, file = import_file_path if import_file_path else google_sheets_url import_file = ImportFile("Bank Transaction", file = file, import_type="Insert New Records") - data = import_file.raw_data + + data = parse_data_from_template(import_file.raw_data) if import_file_path: add_bank_account(data, bank_account) From 4390adcaa1191ae919164af0903ee12eba5c3cfa Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 20 Jan 2022 11:54:14 +0530 Subject: [PATCH 12/53] fix: cost center validation of asset --- erpnext/assets/doctype/asset/asset.py | 14 ++++++++++++++ erpnext/assets/doctype/asset/test_asset.py | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index ee3ec8e63a..e23b033c75 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -36,6 +36,7 @@ class Asset(AccountsController): self.validate_asset_values() self.validate_asset_and_reference() self.validate_item() + self.validate_cost_center() self.set_missing_values() self.prepare_depreciation_data() self.validate_gross_and_purchase_amount() @@ -95,6 +96,19 @@ class Asset(AccountsController): elif item.is_stock_item: frappe.throw(_("Item {0} must be a non-stock item").format(self.item_code)) + def validate_cost_center(self): + if not self.cost_center: return + + cost_center_company = frappe.db.get_value('Cost Center', self.cost_center, 'company') + if cost_center_company != self.company: + frappe.throw( + _("Selected Cost Center {} doesn't belongs to {}").format( + frappe.bold(self.cost_center), + frappe.bold(self.company) + ), + title=_("Invalid Cost Center") + ) + def validate_in_use_date(self): if not self.available_for_use_date: frappe.throw(_("Available for use date is required")) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 44c4ce542d..05ab1d885a 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -1109,6 +1109,7 @@ class TestDepreciationBasics(AssetSetup): self.assertEqual(gle, expected_gle) self.assertEqual(asset.get("value_after_depreciation"), 0) + def test_expected_value_change(self): """ tests if changing `expected_value_after_useful_life` @@ -1130,6 +1131,15 @@ class TestDepreciationBasics(AssetSetup): asset.reload() self.assertEquals(asset.finance_books[0].value_after_depreciation, 98000.0) + def test_asset_cost_center(self): + asset = create_asset(is_existing_asset = 1, do_not_save=1) + asset.cost_center = "Main - WP" + + self.assertRaises(frappe.ValidationError, asset.submit) + + asset.cost_center = "Main - _TC" + asset.submit() + def create_asset_data(): if not frappe.db.exists("Asset Category", "Computers"): create_asset_category() From 2718ddd784e8dc13b5fae1bd7c201c6b76e1391d Mon Sep 17 00:00:00 2001 From: Chillar Anand Date: Thu, 20 Jan 2022 11:57:22 +0530 Subject: [PATCH 13/53] refactor: Removed hospitality domain from ERPNext (#29167) --- erpnext/domains/hospitality.py | 35 -- erpnext/hooks.py | 8 - erpnext/hotels/__init__.py | 0 erpnext/hotels/doctype/__init__.py | 0 erpnext/hotels/doctype/hotel_room/__init__.py | 0 .../hotels/doctype/hotel_room/hotel_room.js | 8 - .../hotels/doctype/hotel_room/hotel_room.json | 175 ------- .../hotels/doctype/hotel_room/hotel_room.py | 13 - .../doctype/hotel_room/test_hotel_room.py | 23 - .../doctype/hotel_room_amenity/__init__.py | 0 .../hotel_room_amenity.json | 103 ----- .../hotel_room_amenity/hotel_room_amenity.py | 9 - .../doctype/hotel_room_package/__init__.py | 0 .../hotel_room_package/hotel_room_package.js | 23 - .../hotel_room_package.json | 215 --------- .../hotel_room_package/hotel_room_package.py | 20 - .../test_hotel_room_package.py | 47 -- .../doctype/hotel_room_pricing/__init__.py | 0 .../hotel_room_pricing/hotel_room_pricing.js | 8 - .../hotel_room_pricing.json | 266 ----------- .../hotel_room_pricing/hotel_room_pricing.py | 9 - .../test_hotel_room_pricing.py | 19 - .../hotel_room_pricing_item/__init__.py | 0 .../hotel_room_pricing_item.json | 103 ----- .../hotel_room_pricing_item.py | 9 - .../hotel_room_pricing_package/__init__.py | 0 .../hotel_room_pricing_package.js | 8 - .../hotel_room_pricing_package.json | 173 ------- .../hotel_room_pricing_package.py | 9 - .../test_hotel_room_pricing_package.py | 8 - .../hotel_room_reservation/__init__.py | 0 .../hotel_room_reservation.js | 68 --- .../hotel_room_reservation.json | 436 ------------------ .../hotel_room_reservation.py | 111 ----- .../hotel_room_reservation_calendar.js | 9 - .../test_hotel_room_reservation.py | 65 --- .../hotel_room_reservation_item/__init__.py | 0 .../hotel_room_reservation_item.json | 195 -------- .../hotel_room_reservation_item.py | 9 - .../doctype/hotel_room_type/__init__.py | 0 .../hotel_room_type/hotel_room_type.js | 8 - .../hotel_room_type/hotel_room_type.json | 204 -------- .../hotel_room_type/hotel_room_type.py | 9 - .../hotel_room_type/test_hotel_room_type.py | 8 - .../hotels/doctype/hotel_settings/__init__.py | 0 .../doctype/hotel_settings/hotel_settings.js | 8 - .../hotel_settings/hotel_settings.json | 175 ------- .../doctype/hotel_settings/hotel_settings.py | 9 - .../hotel_settings/test_hotel_settings.py | 8 - erpnext/hotels/report/__init__.py | 0 .../report/hotel_room_occupancy/__init__.py | 0 .../hotel_room_occupancy.js | 22 - .../hotel_room_occupancy.json | 26 -- .../hotel_room_occupancy.py | 34 -- erpnext/modules.txt | 2 - erpnext/patches.txt | 4 +- .../v13_0/hospitality_deprecation_warning.py | 10 + .../v14_0/delete_hospitality_doctypes.py | 22 + erpnext/restaurant/__init__.py | 0 erpnext/restaurant/doctype/__init__.py | 0 .../restaurant/doctype/restaurant/__init__.py | 0 .../doctype/restaurant/restaurant.js | 10 - .../doctype/restaurant/restaurant.json | 309 ------------- .../doctype/restaurant/restaurant.py | 9 - .../restaurant/restaurant_dashboard.py | 17 - .../doctype/restaurant/test_restaurant.py | 14 - .../doctype/restaurant_menu/__init__.py | 0 .../restaurant_menu/restaurant_menu.js | 8 - .../restaurant_menu/restaurant_menu.json | 247 ---------- .../restaurant_menu/restaurant_menu.py | 59 --- .../restaurant_menu/test_restaurant_menu.py | 52 --- .../doctype/restaurant_menu_item/__init__.py | 0 .../restaurant_menu_item.json | 105 ----- .../restaurant_menu_item.py | 9 - .../restaurant_order_entry/__init__.py | 0 .../restaurant_order_entry.js | 162 ------- .../restaurant_order_entry.json | 280 ----------- .../restaurant_order_entry.py | 91 ---- .../restaurant_order_entry_item/__init__.py | 0 .../restaurant_order_entry_item.json | 163 ------- .../restaurant_order_entry_item.py | 9 - .../restaurant_reservation/__init__.py | 0 .../restaurant_reservation.js | 11 - .../restaurant_reservation.json | 355 -------------- .../restaurant_reservation.py | 14 - .../restaurant_reservation_calendar.js | 18 - .../test_restaurant_reservation.py | 8 - .../doctype/restaurant_table/__init__.py | 0 .../restaurant_table/restaurant_table.js | 8 - .../restaurant_table/restaurant_table.json | 156 ------- .../restaurant_table/restaurant_table.py | 14 - .../restaurant_table/test_restaurant_table.py | 14 - 92 files changed, 35 insertions(+), 4840 deletions(-) delete mode 100644 erpnext/domains/hospitality.py delete mode 100644 erpnext/hotels/__init__.py delete mode 100644 erpnext/hotels/doctype/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room/hotel_room.js delete mode 100644 erpnext/hotels/doctype/hotel_room/hotel_room.json delete mode 100644 erpnext/hotels/doctype/hotel_room/hotel_room.py delete mode 100644 erpnext/hotels/doctype/hotel_room/test_hotel_room.py delete mode 100644 erpnext/hotels/doctype/hotel_room_amenity/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.json delete mode 100644 erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py delete mode 100644 erpnext/hotels/doctype/hotel_room_package/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room_package/hotel_room_package.js delete mode 100644 erpnext/hotels/doctype/hotel_room_package/hotel_room_package.json delete mode 100644 erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py delete mode 100644 erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.js delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.json delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing_item/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.json delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.js delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py delete mode 100644 erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.js delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.json delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation_item/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.json delete mode 100644 erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py delete mode 100644 erpnext/hotels/doctype/hotel_room_type/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_room_type/hotel_room_type.js delete mode 100644 erpnext/hotels/doctype/hotel_room_type/hotel_room_type.json delete mode 100644 erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py delete mode 100644 erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py delete mode 100644 erpnext/hotels/doctype/hotel_settings/__init__.py delete mode 100644 erpnext/hotels/doctype/hotel_settings/hotel_settings.js delete mode 100644 erpnext/hotels/doctype/hotel_settings/hotel_settings.json delete mode 100644 erpnext/hotels/doctype/hotel_settings/hotel_settings.py delete mode 100644 erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py delete mode 100644 erpnext/hotels/report/__init__.py delete mode 100644 erpnext/hotels/report/hotel_room_occupancy/__init__.py delete mode 100644 erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.js delete mode 100644 erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.json delete mode 100644 erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py create mode 100644 erpnext/patches/v13_0/hospitality_deprecation_warning.py create mode 100644 erpnext/patches/v14_0/delete_hospitality_doctypes.py delete mode 100644 erpnext/restaurant/__init__.py delete mode 100644 erpnext/restaurant/doctype/__init__.py delete mode 100644 erpnext/restaurant/doctype/restaurant/__init__.py delete mode 100644 erpnext/restaurant/doctype/restaurant/restaurant.js delete mode 100644 erpnext/restaurant/doctype/restaurant/restaurant.json delete mode 100644 erpnext/restaurant/doctype/restaurant/restaurant.py delete mode 100644 erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py delete mode 100644 erpnext/restaurant/doctype/restaurant/test_restaurant.py delete mode 100644 erpnext/restaurant/doctype/restaurant_menu/__init__.py delete mode 100644 erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js delete mode 100644 erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json delete mode 100644 erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py delete mode 100644 erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py delete mode 100644 erpnext/restaurant/doctype/restaurant_menu_item/__init__.py delete mode 100644 erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json delete mode 100644 erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py delete mode 100644 erpnext/restaurant/doctype/restaurant_order_entry/__init__.py delete mode 100644 erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js delete mode 100644 erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.json delete mode 100644 erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py delete mode 100644 erpnext/restaurant/doctype/restaurant_order_entry_item/__init__.py delete mode 100644 erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.json delete mode 100644 erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py delete mode 100644 erpnext/restaurant/doctype/restaurant_reservation/__init__.py delete mode 100644 erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js delete mode 100644 erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json delete mode 100644 erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py delete mode 100644 erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js delete mode 100644 erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py delete mode 100644 erpnext/restaurant/doctype/restaurant_table/__init__.py delete mode 100644 erpnext/restaurant/doctype/restaurant_table/restaurant_table.js delete mode 100644 erpnext/restaurant/doctype/restaurant_table/restaurant_table.json delete mode 100644 erpnext/restaurant/doctype/restaurant_table/restaurant_table.py delete mode 100644 erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py diff --git a/erpnext/domains/hospitality.py b/erpnext/domains/hospitality.py deleted file mode 100644 index 09b98c288b..0000000000 --- a/erpnext/domains/hospitality.py +++ /dev/null @@ -1,35 +0,0 @@ -data = { - 'desktop_icons': [ - 'Restaurant', - 'Hotels', - 'Accounts', - 'Buying', - 'Stock', - 'HR', - 'Project', - 'ToDo' - ], - 'restricted_roles': [ - 'Restaurant Manager', - 'Hotel Manager', - 'Hotel Reservation User' - ], - '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/hooks.py b/erpnext/hooks.py index f014b0e1e9..d172da3f1f 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -67,7 +67,6 @@ calendars = ["Task", "Work Order", "Leave Application", "Sales Order", "Holiday domains = { 'Distribution': 'erpnext.domains.distribution', 'Education': 'erpnext.domains.education', - 'Hospitality': 'erpnext.domains.hospitality', 'Manufacturing': 'erpnext.domains.manufacturing', 'Non Profit': 'erpnext.domains.non_profit', 'Retail': 'erpnext.domains.retail', @@ -579,13 +578,6 @@ global_search_doctypes = { {'doctype': 'Donor Type', 'index': 10}, {'doctype': 'Membership Type', 'index': 11} ], - "Hospitality": [ - {'doctype': 'Hotel Room', 'index': 0}, - {'doctype': 'Hotel Room Reservation', 'index': 1}, - {'doctype': 'Hotel Room Pricing', 'index': 2}, - {'doctype': 'Hotel Room Package', 'index': 3}, - {'doctype': 'Hotel Room Type', 'index': 4} - ] } additional_timeline_content = { diff --git a/erpnext/hotels/__init__.py b/erpnext/hotels/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/__init__.py b/erpnext/hotels/doctype/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room/__init__.py b/erpnext/hotels/doctype/hotel_room/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room/hotel_room.js b/erpnext/hotels/doctype/hotel_room/hotel_room.js deleted file mode 100644 index 76f22d5d4e..0000000000 --- a/erpnext/hotels/doctype/hotel_room/hotel_room.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Hotel Room', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/hotels/doctype/hotel_room/hotel_room.json b/erpnext/hotels/doctype/hotel_room/hotel_room.json deleted file mode 100644 index 2567c077b6..0000000000 --- a/erpnext/hotels/doctype/hotel_room/hotel_room.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "prompt", - "beta": 1, - "creation": "2017-12-08 12:33:56.320420", - "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": "hotel_room_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": "Hotel Room Type", - "length": 0, - "no_copy": 0, - "options": "Hotel Room Type", - "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": "capacity", - "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": "Capacity", - "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": "extra_bed_capacity", - "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": "Extra Bed Capacity", - "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-12-09 12:10:50.670113", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room", - "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 - }, - { - "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": "Hotel 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/hotels/doctype/hotel_room/hotel_room.py b/erpnext/hotels/doctype/hotel_room/hotel_room.py deleted file mode 100644 index e4bd1c8846..0000000000 --- a/erpnext/hotels/doctype/hotel_room/hotel_room.py +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe.model.document import Document - - -class HotelRoom(Document): - def validate(self): - if not self.capacity: - self.capacity, self.extra_bed_capacity = frappe.db.get_value('Hotel Room Type', - self.hotel_room_type, ['capacity', 'extra_bed_capacity']) diff --git a/erpnext/hotels/doctype/hotel_room/test_hotel_room.py b/erpnext/hotels/doctype/hotel_room/test_hotel_room.py deleted file mode 100644 index 95efe2c606..0000000000 --- a/erpnext/hotels/doctype/hotel_room/test_hotel_room.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - -test_dependencies = ["Hotel Room Package"] -test_records = [ - dict(doctype="Hotel Room", name="1001", - hotel_room_type="Basic Room"), - dict(doctype="Hotel Room", name="1002", - hotel_room_type="Basic Room"), - dict(doctype="Hotel Room", name="1003", - hotel_room_type="Basic Room"), - dict(doctype="Hotel Room", name="1004", - hotel_room_type="Basic Room"), - dict(doctype="Hotel Room", name="1005", - hotel_room_type="Basic Room"), - dict(doctype="Hotel Room", name="1006", - hotel_room_type="Basic Room") -] - -class TestHotelRoom(unittest.TestCase): - pass diff --git a/erpnext/hotels/doctype/hotel_room_amenity/__init__.py b/erpnext/hotels/doctype/hotel_room_amenity/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.json b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.json deleted file mode 100644 index 29a0407a8a..0000000000 --- a/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2017-12-08 12:35:36.572185", - "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": "billable", - "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": "Billable", - "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-12-09 12:05:07.125687", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Amenity", - "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/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py b/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py deleted file mode 100644 index 166493124a..0000000000 --- a/erpnext/hotels/doctype/hotel_room_amenity/hotel_room_amenity.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class HotelRoomAmenity(Document): - pass diff --git a/erpnext/hotels/doctype/hotel_room_package/__init__.py b/erpnext/hotels/doctype/hotel_room_package/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.js b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.js deleted file mode 100644 index 5b09ae568e..0000000000 --- a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.js +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Hotel Room Package', { - hotel_room_type: function(frm) { - if (frm.doc.hotel_room_type) { - frappe.model.with_doc('Hotel Room Type', frm.doc.hotel_room_type, () => { - let hotel_room_type = frappe.get_doc('Hotel Room Type', frm.doc.hotel_room_type); - - // reset the amenities - frm.doc.amenities = []; - - for (let amenity of hotel_room_type.amenities) { - let d = frm.add_child('amenities'); - d.item = amenity.item; - d.billable = amenity.billable; - } - - frm.refresh(); - }); - } - } -}); diff --git a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.json b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.json deleted file mode 100644 index 57dad44b7d..0000000000 --- a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.json +++ /dev/null @@ -1,215 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "prompt", - "beta": 1, - "creation": "2017-12-08 12:43:17.211064", - "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": "hotel_room_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": "Hotel Room Type", - "length": 0, - "no_copy": 0, - "options": "Hotel Room Type", - "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_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, - "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": "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": "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": "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, - "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": "amenities", - "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": "Amenities", - "length": 0, - "no_copy": 0, - "options": "Hotel Room Amenity", - "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-12-09 12:10:31.111952", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Package", - "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/hotels/doctype/hotel_room_package/hotel_room_package.py b/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py deleted file mode 100644 index aedc83a846..0000000000 --- a/erpnext/hotels/doctype/hotel_room_package/hotel_room_package.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe.model.document import Document - - -class HotelRoomPackage(Document): - def validate(self): - if not self.item: - item = frappe.get_doc(dict( - doctype = 'Item', - item_code = self.name, - item_group = 'Products', - is_stock_item = 0, - stock_uom = 'Unit' - )) - item.insert() - self.item = item.name diff --git a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py b/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py deleted file mode 100644 index 749731f491..0000000000 --- a/erpnext/hotels/doctype/hotel_room_package/test_hotel_room_package.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - -test_records = [ - dict(doctype='Item', item_code='Breakfast', - item_group='Products', is_stock_item=0), - dict(doctype='Item', item_code='Lunch', - item_group='Products', is_stock_item=0), - dict(doctype='Item', item_code='Dinner', - item_group='Products', is_stock_item=0), - dict(doctype='Item', item_code='WiFi', - item_group='Products', is_stock_item=0), - dict(doctype='Hotel Room Type', name="Delux Room", - capacity=4, - extra_bed_capacity=2, - amenities = [ - dict(item='WiFi', billable=0) - ]), - dict(doctype='Hotel Room Type', name="Basic Room", - capacity=4, - extra_bed_capacity=2, - amenities = [ - dict(item='Breakfast', billable=0) - ]), - dict(doctype="Hotel Room Package", name="Basic Room with Breakfast", - hotel_room_type="Basic Room", - amenities = [ - dict(item="Breakfast", billable=0) - ]), - dict(doctype="Hotel Room Package", name="Basic Room with Lunch", - hotel_room_type="Basic Room", - amenities = [ - dict(item="Breakfast", billable=0), - dict(item="Lunch", billable=0) - ]), - dict(doctype="Hotel Room Package", name="Basic Room with Dinner", - hotel_room_type="Basic Room", - amenities = [ - dict(item="Breakfast", billable=0), - dict(item="Dinner", billable=0) - ]) -] - -class TestHotelRoomPackage(unittest.TestCase): - pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing/__init__.py b/erpnext/hotels/doctype/hotel_room_pricing/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.js b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.js deleted file mode 100644 index 87bb192570..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Hotel Room Pricing', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.json b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.json deleted file mode 100644 index 0f5a776211..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.json +++ /dev/null @@ -1,266 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "autoname": "prompt", - "beta": 1, - "creation": "2017-12-08 12:51:47.088174", - "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, - "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": 0, - "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": "currency", - "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": "Currency", - "length": 0, - "no_copy": 0, - "options": "Currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "from_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": "From 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": 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": "to_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "To Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 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": "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": "Hotel Room Pricing 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-12-09 12:10:41.559559", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Pricing", - "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 - }, - { - "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": "Hotel 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/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py b/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py deleted file mode 100644 index d28e573426..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing/hotel_room_pricing.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class HotelRoomPricing(Document): - pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py b/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py deleted file mode 100644 index 34550096dd..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing/test_hotel_room_pricing.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - -test_dependencies = ["Hotel Room Package"] -test_records = [ - dict(doctype="Hotel Room Pricing", enabled=1, - name="Winter 2017", - from_date="2017-01-01", to_date="2017-01-10", - items = [ - dict(item="Basic Room with Breakfast", rate=10000), - dict(item="Basic Room with Lunch", rate=11000), - dict(item="Basic Room with Dinner", rate=12000) - ]) -] - -class TestHotelRoomPricing(unittest.TestCase): - pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing_item/__init__.py b/erpnext/hotels/doctype/hotel_room_pricing_item/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.json b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.json deleted file mode 100644 index d6cd826bcc..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2017-12-08 12:50:13.486090", - "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": "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": 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": 1, - "max_attachments": 0, - "modified": "2017-12-09 12:04:58.641703", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Pricing 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/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py b/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py deleted file mode 100644 index 2e6bb5fac2..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing_item/hotel_room_pricing_item.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class HotelRoomPricingItem(Document): - pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/__init__.py b/erpnext/hotels/doctype/hotel_room_pricing_package/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.js b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.js deleted file mode 100644 index f6decd9e95..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Hotel Room Pricing Package', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json deleted file mode 100644 index 1e529325cd..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2017-12-08 12:50:13.486090", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "from_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": "From 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": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "to_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "To Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "hotel_room_package", - "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": "Hotel Room Package", - "length": 0, - "no_copy": 0, - "options": "Hotel Room Package", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 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": "2018-11-04 03:34:02.551811", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Pricing Package", - "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, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py b/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py deleted file mode 100644 index ebbdb6ec6c..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing_package/hotel_room_pricing_package.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class HotelRoomPricingPackage(Document): - pass diff --git a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py b/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py deleted file mode 100644 index 196e6504b5..0000000000 --- a/erpnext/hotels/doctype/hotel_room_pricing_package/test_hotel_room_pricing_package.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestHotelRoomPricingPackage(unittest.TestCase): - pass diff --git a/erpnext/hotels/doctype/hotel_room_reservation/__init__.py b/erpnext/hotels/doctype/hotel_room_reservation/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.js b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.js deleted file mode 100644 index e58d763e47..0000000000 --- a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.js +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Hotel Room Reservation', { - refresh: function(frm) { - if(frm.doc.docstatus == 1){ - frm.add_custom_button(__('Create Invoice'), ()=> { - frm.trigger("make_invoice"); - }); - } - }, - from_date: function(frm) { - frm.trigger("recalculate_rates"); - }, - to_date: function(frm) { - frm.trigger("recalculate_rates"); - }, - recalculate_rates: function(frm) { - if (!frm.doc.from_date || !frm.doc.to_date - || !frm.doc.items.length){ - return; - } - frappe.call({ - "method": "erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation.get_room_rate", - "args": {"hotel_room_reservation": frm.doc} - }).done((r)=> { - for (var i = 0; i < r.message.items.length; i++) { - frm.doc.items[i].rate = r.message.items[i].rate; - frm.doc.items[i].amount = r.message.items[i].amount; - } - frappe.run_serially([ - ()=> frm.set_value("net_total", r.message.net_total), - ()=> frm.refresh_field("items") - ]); - }); - }, - make_invoice: function(frm) { - frappe.model.with_doc("Hotel Settings", "Hotel Settings", ()=>{ - frappe.model.with_doctype("Sales Invoice", ()=>{ - let hotel_settings = frappe.get_doc("Hotel Settings", "Hotel Settings"); - let invoice = frappe.model.get_new_doc("Sales Invoice"); - invoice.customer = frm.doc.customer || hotel_settings.default_customer; - if (hotel_settings.default_invoice_naming_series){ - invoice.naming_series = hotel_settings.default_invoice_naming_series; - } - for (let d of frm.doc.items){ - let invoice_item = frappe.model.add_child(invoice, "items") - invoice_item.item_code = d.item; - invoice_item.qty = d.qty; - invoice_item.rate = d.rate; - } - if (hotel_settings.default_taxes_and_charges){ - invoice.taxes_and_charges = hotel_settings.default_taxes_and_charges; - } - frappe.set_route("Form", invoice.doctype, invoice.name); - }); - }); - } -}); - -frappe.ui.form.on('Hotel Room Reservation Item', { - item: function(frm, doctype, name) { - frm.trigger("recalculate_rates"); - }, - qty: function(frm) { - frm.trigger("recalculate_rates"); - } -}); diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.json b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.json deleted file mode 100644 index fd20efdf8d..0000000000 --- a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.json +++ /dev/null @@ -1,436 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "autoname": "HTL-RES-.YYYY.-.#####", - "beta": 1, - "creation": "2017-12-08 13:01:34.829175", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", - "fields": [ - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "guest_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": "Guest 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "from_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": "From 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": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "to_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "To Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "late_checkin", - "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": "Late Checkin", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_6", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 0, - "options": "Booked\nAdvance Paid\nInvoiced\nPaid\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": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_8", - "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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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": "Hotel Room Reservation 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "net_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": "Net 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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": "Hotel Room Reservation", - "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, - "translatable": 0, - "unique": 0 - } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-21 16:15:47.326951", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Reservation", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Hotel Reservation User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, - "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, - "track_views": 0 -} \ No newline at end of file diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py deleted file mode 100644 index 7725955396..0000000000 --- a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import json - -import frappe -from frappe import _ -from frappe.model.document import Document -from frappe.utils import add_days, date_diff, flt - - -class HotelRoomUnavailableError(frappe.ValidationError): pass -class HotelRoomPricingNotSetError(frappe.ValidationError): pass - -class HotelRoomReservation(Document): - def validate(self): - self.total_rooms = {} - self.set_rates() - self.validate_availability() - - def validate_availability(self): - for i in range(date_diff(self.to_date, self.from_date)): - day = add_days(self.from_date, i) - self.rooms_booked = {} - - for d in self.items: - if not d.item in self.rooms_booked: - self.rooms_booked[d.item] = 0 - - room_type = frappe.db.get_value("Hotel Room Package", - d.item, 'hotel_room_type') - rooms_booked = get_rooms_booked(room_type, day, exclude_reservation=self.name) \ - + d.qty + self.rooms_booked.get(d.item) - total_rooms = self.get_total_rooms(d.item) - if total_rooms < rooms_booked: - frappe.throw(_("Hotel Rooms of type {0} are unavailable on {1}").format(d.item, - frappe.format(day, dict(fieldtype="Date"))), exc=HotelRoomUnavailableError) - - self.rooms_booked[d.item] += rooms_booked - - def get_total_rooms(self, item): - if not item in self.total_rooms: - self.total_rooms[item] = frappe.db.sql(""" - select count(*) - from - `tabHotel Room Package` package - inner join - `tabHotel Room` room on package.hotel_room_type = room.hotel_room_type - where - package.item = %s""", item)[0][0] or 0 - - return self.total_rooms[item] - - def set_rates(self): - self.net_total = 0 - for d in self.items: - net_rate = 0.0 - for i in range(date_diff(self.to_date, self.from_date)): - day = add_days(self.from_date, i) - if not d.item: - continue - day_rate = frappe.db.sql(""" - select - item.rate - from - `tabHotel Room Pricing Item` item, - `tabHotel Room Pricing` pricing - where - item.parent = pricing.name - and item.item = %s - and %s between pricing.from_date - and pricing.to_date""", (d.item, day)) - - if day_rate: - net_rate += day_rate[0][0] - else: - frappe.throw( - _("Please set Hotel Room Rate on {}").format( - frappe.format(day, dict(fieldtype="Date"))), exc=HotelRoomPricingNotSetError) - d.rate = net_rate - d.amount = net_rate * flt(d.qty) - self.net_total += d.amount - -@frappe.whitelist() -def get_room_rate(hotel_room_reservation): - """Calculate rate for each day as it may belong to different Hotel Room Pricing Item""" - doc = frappe.get_doc(json.loads(hotel_room_reservation)) - doc.set_rates() - return doc.as_dict() - -def get_rooms_booked(room_type, day, exclude_reservation=None): - exclude_condition = '' - if exclude_reservation: - exclude_condition = 'and reservation.name != {0}'.format(frappe.db.escape(exclude_reservation)) - - return frappe.db.sql(""" - select sum(item.qty) - from - `tabHotel Room Package` room_package, - `tabHotel Room Reservation Item` item, - `tabHotel Room Reservation` reservation - where - item.parent = reservation.name - and room_package.item = item.item - and room_package.hotel_room_type = %s - and reservation.docstatus = 1 - {exclude_condition} - and %s between reservation.from_date - and reservation.to_date""".format(exclude_condition=exclude_condition), - (room_type, day))[0][0] or 0 diff --git a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js b/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js deleted file mode 100644 index 7bde292a2b..0000000000 --- a/erpnext/hotels/doctype/hotel_room_reservation/hotel_room_reservation_calendar.js +++ /dev/null @@ -1,9 +0,0 @@ -frappe.views.calendar["Hotel Room Reservation"] = { - field_map: { - "start": "from_date", - "end": "to_date", - "id": "name", - "title": "guest_name", - "status": "status" - } -} diff --git a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py b/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py deleted file mode 100644 index bb32a27fa7..0000000000 --- a/erpnext/hotels/doctype/hotel_room_reservation/test_hotel_room_reservation.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - -import frappe - -from erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation import ( - HotelRoomPricingNotSetError, - HotelRoomUnavailableError, -) - -test_dependencies = ["Hotel Room Package", "Hotel Room Pricing", "Hotel Room"] - -class TestHotelRoomReservation(unittest.TestCase): - def setUp(self): - frappe.db.sql("delete from `tabHotel Room Reservation`") - frappe.db.sql("delete from `tabHotel Room Reservation Item`") - - def test_reservation(self): - reservation = make_reservation( - from_date="2017-01-01", - to_date="2017-01-03", - items=[ - dict(item="Basic Room with Dinner", qty=2) - ] - ) - reservation.insert() - self.assertEqual(reservation.net_total, 48000) - - def test_price_not_set(self): - reservation = make_reservation( - from_date="2016-01-01", - to_date="2016-01-03", - items=[ - dict(item="Basic Room with Dinner", qty=2) - ] - ) - self.assertRaises(HotelRoomPricingNotSetError, reservation.insert) - - def test_room_unavailable(self): - reservation = make_reservation( - from_date="2017-01-01", - to_date="2017-01-03", - items=[ - dict(item="Basic Room with Dinner", qty=2), - ] - ) - reservation.insert() - - reservation = make_reservation( - from_date="2017-01-01", - to_date="2017-01-03", - items=[ - dict(item="Basic Room with Dinner", qty=20), - ] - ) - self.assertRaises(HotelRoomUnavailableError, reservation.insert) - -def make_reservation(**kwargs): - kwargs["doctype"] = "Hotel Room Reservation" - if not "guest_name" in kwargs: - kwargs["guest_name"] = "Test Guest" - doc = frappe.get_doc(kwargs) - return doc diff --git a/erpnext/hotels/doctype/hotel_room_reservation_item/__init__.py b/erpnext/hotels/doctype/hotel_room_reservation_item/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.json b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.json deleted file mode 100644 index 2b7931ebc0..0000000000 --- a/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.json +++ /dev/null @@ -1,195 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "", - "beta": 0, - "creation": "2017-12-08 12:58:21.733330", - "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": 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", - "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", - "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": "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "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": "Amount", - "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-12-09 12:04:34.562956", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Reservation 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/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py b/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py deleted file mode 100644 index 41d86ddca6..0000000000 --- a/erpnext/hotels/doctype/hotel_room_reservation_item/hotel_room_reservation_item.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class HotelRoomReservationItem(Document): - pass diff --git a/erpnext/hotels/doctype/hotel_room_type/__init__.py b/erpnext/hotels/doctype/hotel_room_type/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.js b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.js deleted file mode 100644 index d73835db94..0000000000 --- a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Hotel Room Type', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.json b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.json deleted file mode 100644 index 3d26413cf8..0000000000 --- a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "prompt", - "beta": 1, - "creation": "2017-12-08 12:38:29.485175", - "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": "capacity", - "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": "Capacity", - "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": "extra_bed_capacity", - "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": "Extra Bed Capacity", - "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_3", - "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": "amenities", - "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": "Amenities", - "length": 0, - "no_copy": 0, - "options": "Hotel Room Amenity", - "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-12-09 12:10:23.355486", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Type", - "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 - }, - { - "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": "Hotel 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/hotels/doctype/hotel_room_type/hotel_room_type.py b/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py deleted file mode 100644 index 7ab529fee9..0000000000 --- a/erpnext/hotels/doctype/hotel_room_type/hotel_room_type.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class HotelRoomType(Document): - pass diff --git a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py b/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py deleted file mode 100644 index 8d1147d0f2..0000000000 --- a/erpnext/hotels/doctype/hotel_room_type/test_hotel_room_type.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestHotelRoomType(unittest.TestCase): - pass diff --git a/erpnext/hotels/doctype/hotel_settings/__init__.py b/erpnext/hotels/doctype/hotel_settings/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/doctype/hotel_settings/hotel_settings.js b/erpnext/hotels/doctype/hotel_settings/hotel_settings.js deleted file mode 100644 index 0b4a2c36ca..0000000000 --- a/erpnext/hotels/doctype/hotel_settings/hotel_settings.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Hotel Settings', { - refresh: function(frm) { - - } -}); diff --git a/erpnext/hotels/doctype/hotel_settings/hotel_settings.json b/erpnext/hotels/doctype/hotel_settings/hotel_settings.json deleted file mode 100644 index d9f5572549..0000000000 --- a/erpnext/hotels/doctype/hotel_settings/hotel_settings.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-12-08 17:50:24.523107", - "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": "default_customer", - "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": "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": "default_taxes_and_charges", - "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 Taxes and Charges", - "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": "default_invoice_naming_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": "Default Invoice Naming Series", - "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": 1, - "istable": 0, - "max_attachments": 0, - "modified": "2017-12-09 12:11:12.857308", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Settings", - "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": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 1 - }, - { - "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": "Hotel 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/hotels/doctype/hotel_settings/hotel_settings.py b/erpnext/hotels/doctype/hotel_settings/hotel_settings.py deleted file mode 100644 index 8376d50969..0000000000 --- a/erpnext/hotels/doctype/hotel_settings/hotel_settings.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from frappe.model.document import Document - - -class HotelSettings(Document): - pass diff --git a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py b/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py deleted file mode 100644 index e76c00ce10..0000000000 --- a/erpnext/hotels/doctype/hotel_settings/test_hotel_settings.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestHotelSettings(unittest.TestCase): - pass diff --git a/erpnext/hotels/report/__init__.py b/erpnext/hotels/report/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/report/hotel_room_occupancy/__init__.py b/erpnext/hotels/report/hotel_room_occupancy/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.js b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.js deleted file mode 100644 index 81efb2dd12..0000000000 --- a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.js +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt -/* eslint-disable */ - -frappe.query_reports["Hotel Room Occupancy"] = { - "filters": [ - { - "fieldname":"from_date", - "label": __("From Date"), - "fieldtype": "Date", - "default": frappe.datetime.now_date(), - "reqd":1 - }, - { - "fieldname":"to_date", - "label": __("To Date"), - "fieldtype": "Date", - "default": frappe.datetime.now_date(), - "reqd":1 - } - ] -} diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.json b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.json deleted file mode 100644 index 782a48bbb9..0000000000 --- a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "add_total_row": 1, - "apply_user_permissions": 1, - "creation": "2017-12-09 14:31:26.306705", - "disabled": 0, - "docstatus": 0, - "doctype": "Report", - "idx": 0, - "is_standard": "Yes", - "modified": "2017-12-09 14:31:26.306705", - "modified_by": "Administrator", - "module": "Hotels", - "name": "Hotel Room Occupancy", - "owner": "Administrator", - "ref_doctype": "Hotel Room Reservation", - "report_name": "Hotel Room Occupancy", - "report_type": "Script Report", - "roles": [ - { - "role": "System Manager" - }, - { - "role": "Hotel Reservation User" - } - ] -} \ No newline at end of file diff --git a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py b/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py deleted file mode 100644 index c43589d2a8..0000000000 --- a/erpnext/hotels/report/hotel_room_occupancy/hotel_room_occupancy.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import frappe -from frappe import _ -from frappe.utils import add_days, date_diff - -from erpnext.hotels.doctype.hotel_room_reservation.hotel_room_reservation import get_rooms_booked - - -def execute(filters=None): - columns = get_columns(filters) - data = get_data(filters) - return columns, data - -def get_columns(filters): - columns = [ - dict(label=_("Room Type"), fieldname="room_type"), - dict(label=_("Rooms Booked"), fieldtype="Int") - ] - return columns - -def get_data(filters): - out = [] - for room_type in frappe.get_all('Hotel Room Type'): - total_booked = 0 - for i in range(date_diff(filters.to_date, filters.from_date)): - day = add_days(filters.from_date, i) - total_booked += get_rooms_booked(room_type.name, day) - - out.append([room_type.name, total_booked]) - - return out diff --git a/erpnext/modules.txt b/erpnext/modules.txt index ae0bb2d5c9..e62e2bcfab 100644 --- a/erpnext/modules.txt +++ b/erpnext/modules.txt @@ -15,10 +15,8 @@ Portal Maintenance Education Regional -Restaurant ERPNext Integrations Non Profit -Hotels Quality Management Communication Loan Management diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 1f83c4fed7..981500e1c7 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -325,6 +325,8 @@ execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings' erpnext.patches.v14_0.set_payroll_cost_centers erpnext.patches.v13_0.agriculture_deprecation_warning erpnext.patches.v14_0.delete_agriculture_doctypes +erpnext.patches.v13_0.hospitality_deprecation_warning +erpnext.patches.v14_0.delete_hospitality_doctypes erpnext.patches.v13_0.update_exchange_rate_settings erpnext.patches.v14_0.rearrange_company_fields -erpnext.patches.v14_0.update_leave_notification_template \ No newline at end of file +erpnext.patches.v14_0.update_leave_notification_template diff --git a/erpnext/patches/v13_0/hospitality_deprecation_warning.py b/erpnext/patches/v13_0/hospitality_deprecation_warning.py new file mode 100644 index 0000000000..2708b2ccd3 --- /dev/null +++ b/erpnext/patches/v13_0/hospitality_deprecation_warning.py @@ -0,0 +1,10 @@ +import click + + +def execute(): + + click.secho( + "Hospitality domain is moved to a separate app and will be removed from ERPNext in version-14.\n" + "When upgrading to ERPNext version-14, please install the app to continue using the Hospitality domain: https://github.com/frappe/hospitality", + fg="yellow", + ) diff --git a/erpnext/patches/v14_0/delete_hospitality_doctypes.py b/erpnext/patches/v14_0/delete_hospitality_doctypes.py new file mode 100644 index 0000000000..5bb5e4bb89 --- /dev/null +++ b/erpnext/patches/v14_0/delete_hospitality_doctypes.py @@ -0,0 +1,22 @@ +import frappe + + +def execute(): + modules = ['Hotels', 'Restaurant'] + + for module in modules: + frappe.delete_doc("Module Def", module, ignore_missing=True, force=True) + + frappe.delete_doc("Workspace", module, ignore_missing=True, force=True) + + reports = frappe.get_all("Report", {"module": module, "is_standard": "Yes"}, pluck='name') + for report in reports: + frappe.delete_doc("Report", report, ignore_missing=True, force=True) + + dashboards = frappe.get_all("Dashboard", {"module": module, "is_standard": 1}, pluck='name') + for dashboard in dashboards: + frappe.delete_doc("Dashboard", dashboard, ignore_missing=True, force=True) + + doctypes = frappe.get_all("DocType", {"module": module, "custom": 0}, pluck='name') + for doctype in doctypes: + frappe.delete_doc("DocType", doctype, ignore_missing=True) diff --git a/erpnext/restaurant/__init__.py b/erpnext/restaurant/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/restaurant/doctype/__init__.py b/erpnext/restaurant/doctype/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/restaurant/doctype/restaurant/__init__.py b/erpnext/restaurant/doctype/restaurant/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/restaurant/doctype/restaurant/restaurant.js b/erpnext/restaurant/doctype/restaurant/restaurant.js deleted file mode 100644 index 13fda73922..0000000000 --- a/erpnext/restaurant/doctype/restaurant/restaurant.js +++ /dev/null @@ -1,10 +0,0 @@ -// 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 deleted file mode 100644 index 8572687411..0000000000 --- a/erpnext/restaurant/doctype/restaurant/restaurant.json +++ /dev/null @@ -1,309 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "prompt", - "beta": 1, - "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-12-09 12:13:10.185496", - "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 deleted file mode 100644 index 67838d29a3..0000000000 --- a/erpnext/restaurant/doctype/restaurant/restaurant.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -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 deleted file mode 100644 index bfdd052753..0000000000 --- a/erpnext/restaurant/doctype/restaurant/restaurant_dashboard.py +++ /dev/null @@ -1,17 +0,0 @@ -from frappe import _ - - -def get_data(): - return { - 'fieldname': 'restaurant', - 'transactions': [ - { - 'label': _('Setup'), - 'items': ['Restaurant Menu', 'Restaurant Table'] - }, - { - 'label': _('Operations'), - 'items': ['Restaurant Reservation', 'Sales Invoice'] - } - ] - } diff --git a/erpnext/restaurant/doctype/restaurant/test_restaurant.py b/erpnext/restaurant/doctype/restaurant/test_restaurant.py deleted file mode 100644 index f88f980129..0000000000 --- a/erpnext/restaurant/doctype/restaurant/test_restaurant.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -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 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js b/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js deleted file mode 100644 index da7d43f8a3..0000000000 --- a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.js +++ /dev/null @@ -1,8 +0,0 @@ -// 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 deleted file mode 100644 index 1b1610dbac..0000000000 --- a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.json +++ /dev/null @@ -1,247 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "prompt", - "beta": 1, - "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-12-09 12:13:13.684500", - "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 deleted file mode 100644 index 64eb40f364..0000000000 --- a/erpnext/restaurant/doctype/restaurant_menu/restaurant_menu.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -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.py b/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py deleted file mode 100644 index 27020eb869..0000000000 --- a/erpnext/restaurant/doctype/restaurant_menu/test_restaurant_menu.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - -import frappe - -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.assertEqual(frappe.db.get_value('Item Price', - dict(price_list = 'Test Restaurant 1 Menu 1', item_code='Food Item 1'), 'price_list_rate'), 400) - self.assertEqual(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.assertEqual(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 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json b/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json deleted file mode 100644 index 87568bf981..0000000000 --- a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "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 deleted file mode 100644 index 98b245edec..0000000000 --- a/erpnext/restaurant/doctype/restaurant_menu_item/restaurant_menu_item.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -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 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js b/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js deleted file mode 100644 index 8df851c62b..0000000000 --- a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.js +++ /dev/null @@ -1,162 +0,0 @@ -// 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(!frm.item_selector) { - frm.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 deleted file mode 100644 index 3e4d593d5b..0000000000 --- a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.json +++ /dev/null @@ -1,280 +0,0 @@ -{ - "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 deleted file mode 100644 index f9e75b47a0..0000000000 --- a/erpnext/restaurant/doctype/restaurant_order_entry/restaurant_order_entry.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import json - -import frappe -from frappe import _ -from frappe.model.document import Document - -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 - -@frappe.whitelist() -def item_query_restaurant(doctype='Item', txt='', searchfield='name', start=0, page_len=20, filters=None, as_dict=False): - '''Return items that are selected in active menu of the restaurant''' - restaurant, menu = get_restaurant_and_menu_name(filters['table']) - 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 diff --git a/erpnext/restaurant/doctype/restaurant_order_entry_item/__init__.py b/erpnext/restaurant/doctype/restaurant_order_entry_item/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 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 deleted file mode 100644 index 0240013c78..0000000000 --- a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.json +++ /dev/null @@ -1,163 +0,0 @@ -{ - "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 deleted file mode 100644 index 0d9c236c0e..0000000000 --- a/erpnext/restaurant/doctype/restaurant_order_entry_item/restaurant_order_entry_item.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -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 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js deleted file mode 100644 index cebd1052a8..0000000000 --- a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.js +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Restaurant Reservation', { - setup: function(frm) { - frm.add_fetch('customer', 'customer_name', 'customer_name'); - }, - refresh: function(frm) { - - } -}); diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json deleted file mode 100644 index 17df2b931d..0000000000 --- a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.json +++ /dev/null @@ -1,355 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "RES-RES-.YYYY.-.#####", - "beta": 1, - "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_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 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, - "translatable": 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": "2018-08-21 16:15:38.435656", - "modified_by": "Administrator", - "module": "Restaurant", - "name": "Restaurant Reservation", - "name_case": "", - "owner": "Administrator", - "permissions": [ - { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "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, - "track_views": 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 deleted file mode 100644 index 02ffaf6c20..0000000000 --- a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from datetime import timedelta - -from frappe.model.document import Document -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) diff --git a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js b/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js deleted file mode 100644 index fe3dc57a72..0000000000 --- a/erpnext/restaurant/doctype/restaurant_reservation/restaurant_reservation_calendar.js +++ /dev/null @@ -1,18 +0,0 @@ -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: "frappe.desk.calendar.get_events" -}; diff --git a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py b/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py deleted file mode 100644 index 11a3541bd5..0000000000 --- a/erpnext/restaurant/doctype/restaurant_reservation/test_restaurant_reservation.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -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 deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js b/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js deleted file mode 100644 index a55605c90b..0000000000 --- a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.js +++ /dev/null @@ -1,8 +0,0 @@ -// 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 deleted file mode 100644 index 5fc6e62ecb..0000000000 --- a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "", - "beta": 1, - "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-12-09 12:13:24.382345", - "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 deleted file mode 100644 index 29f8a1a12b..0000000000 --- a/erpnext/restaurant/doctype/restaurant_table/restaurant_table.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -import 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.py b/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py deleted file mode 100644 index 00d14d2bb2..0000000000 --- a/erpnext/restaurant/doctype/restaurant_table/test_restaurant_table.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -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 From a9ff1fc52e1be73fa0d4cbb415607d5d545c545c Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 20 Jan 2022 13:36:46 +0530 Subject: [PATCH 14/53] fix: (enhance) BOM Operations Report - Added filters in the Report for BOM ID, Item Code and Workstation - Converted Raw SQL to frappe.qb and added method to get filtered data - Changed fieldtype of 'Time in mins' from Int to Float - Get BOM wise grouped data to keep order and accurate grouping in report --- .../bom_operations_time.js | 35 ++++++++- .../bom_operations_time.py | 78 +++++++++++++------ 2 files changed, 89 insertions(+), 24 deletions(-) diff --git a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.js b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.js index 7468e34020..705da5a3a6 100644 --- a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.js +++ b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.js @@ -4,6 +4,39 @@ frappe.query_reports["BOM Operations Time"] = { "filters": [ - + { + "fieldname": "item_code", + "label": __("Item Code"), + "fieldtype": "Link", + "width": "100", + "options": "Item", + "get_query": () =>{ + return { + filters: { "disabled": 0, "is_stock_item": 1 } + } + } + }, + { + "fieldname": "bom_id", + "label": __("BOM ID"), + "fieldtype": "MultiSelectList", + "width": "80", + "options": "BOM", + "get_data": function(txt) { + return frappe.db.get_link_options("BOM", txt); + }, + "get_query": () =>{ + return { + filters: { "docstatus": 1, "is_active": 1 } + } + } + }, + { + "fieldname": "workstation", + "label": __("Workstation"), + "fieldtype": "Link", + "width": "100", + "options": "Workstation" + }, ] }; diff --git a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py index e7a818abd5..0bed46ac70 100644 --- a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py +++ b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py @@ -4,7 +4,8 @@ import frappe from frappe import _ - +from frappe.model.meta import get_field_precision +from frappe.utils import flt def execute(filters=None): data = get_data(filters) @@ -12,19 +13,15 @@ def execute(filters=None): return columns, data def get_data(filters): - data = [] + bom_wise_data = {} + bom_data, report_data = [], [] - bom_data = [] - for d in frappe.db.sql(""" - SELECT - bom.name, bom.item, bom.item_name, bom.uom, - bomps.operation, bomps.workstation, bomps.time_in_mins - FROM `tabBOM` bom, `tabBOM Operation` bomps - WHERE - bom.docstatus = 1 and bom.is_active = 1 and bom.name = bomps.parent - """, as_dict=1): + bom_operation_data = get_filtered_data(filters) + + for d in bom_operation_data: row = get_args() if d.name not in bom_data: + bom_wise_data[d.name] = [] bom_data.append(d.name) row.update(d) else: @@ -34,14 +31,49 @@ def get_data(filters): "time_in_mins": d.time_in_mins }) - data.append(row) + # maintain BOM wise data for grouping such as: + # {"BOM A": [{Row1}, {Row2}], "BOM B": ...} + bom_wise_data[d.name].append(row) used_as_subassembly_items = get_bom_count(bom_data) - for d in data: - d.used_as_subassembly_items = used_as_subassembly_items.get(d.name, 0) + for d in bom_wise_data: + for row in bom_wise_data[d]: + row.used_as_subassembly_items = used_as_subassembly_items.get(row.name, 0) + report_data.append(row) - return data + return report_data + +def get_filtered_data(filters): + bom = frappe.qb.DocType("BOM") + bom_ops = frappe.qb.DocType("BOM Operation") + + bom_ops_query = ( + frappe.qb.from_(bom) + .join(bom_ops).on(bom.name == bom_ops.parent) + .select( + bom.name, bom.item, bom.item_name, bom.uom, + bom_ops.operation, bom_ops.workstation, bom_ops.time_in_mins + ).where( + (bom.docstatus == 1) + & (bom.is_active == 1) + ) + ) + + if filters.get("item_code"): + bom_ops_query = bom_ops_query.where(bom.item == filters.get("item_code")) + + if filters.get("bom_id"): + bom_ops_query = bom_ops_query.where(bom.name.isin(filters.get("bom_id"))) + + if filters.get("workstation"): + bom_ops_query = bom_ops_query.where( + bom_ops.workstation == filters.get("workstation") + ) + + bom_operation_data = bom_ops_query.run(as_dict=True) + + return bom_operation_data def get_bom_count(bom_data): data = frappe.get_all("BOM Item", @@ -68,13 +100,13 @@ def get_columns(filters): "options": "BOM", "fieldname": "name", "fieldtype": "Link", - "width": 140 + "width": 220 }, { - "label": _("BOM Item Code"), + "label": _("Item Code"), "options": "Item", "fieldname": "item", "fieldtype": "Link", - "width": 140 + "width": 150 }, { "label": _("Item Name"), "fieldname": "item_name", @@ -85,13 +117,13 @@ def get_columns(filters): "options": "UOM", "fieldname": "uom", "fieldtype": "Link", - "width": 140 + "width": 100 }, { "label": _("Operation"), "options": "Operation", "fieldname": "operation", "fieldtype": "Link", - "width": 120 + "width": 140 }, { "label": _("Workstation"), "options": "Workstation", @@ -101,11 +133,11 @@ def get_columns(filters): }, { "label": _("Time (In Mins)"), "fieldname": "time_in_mins", - "fieldtype": "Int", - "width": 140 + "fieldtype": "Float", + "width": 120 }, { "label": _("Sub-assembly BOM Count"), "fieldname": "used_as_subassembly_items", "fieldtype": "Int", - "width": 180 + "width": 200 }] From 3c7b7721123bb2284a00f84f335a8ab1708831f5 Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 20 Jan 2022 14:19:08 +0530 Subject: [PATCH 15/53] fix: Sider (unused imports) and Linter(add extra empty line) --- .../report/bom_operations_time/bom_operations_time.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py index 0bed46ac70..eda9eb9d70 100644 --- a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py +++ b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.py @@ -4,8 +4,7 @@ import frappe from frappe import _ -from frappe.model.meta import get_field_precision -from frappe.utils import flt + def execute(filters=None): data = get_data(filters) From af734298c8ac541188de4593a064f962147ea27d Mon Sep 17 00:00:00 2001 From: marination Date: Thu, 20 Jan 2022 14:29:18 +0530 Subject: [PATCH 16/53] fix: Allow only BOM with ops in BOM ID filter & add total row to report --- .../report/bom_operations_time/bom_operations_time.js | 4 ++-- .../report/bom_operations_time/bom_operations_time.json | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.js b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.js index 705da5a3a6..0eb22a22f7 100644 --- a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.js +++ b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.js @@ -20,14 +20,14 @@ frappe.query_reports["BOM Operations Time"] = { "fieldname": "bom_id", "label": __("BOM ID"), "fieldtype": "MultiSelectList", - "width": "80", + "width": "100", "options": "BOM", "get_data": function(txt) { return frappe.db.get_link_options("BOM", txt); }, "get_query": () =>{ return { - filters: { "docstatus": 1, "is_active": 1 } + filters: { "docstatus": 1, "is_active": 1, "with_operations": 1 } } } }, diff --git a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.json b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.json index 665c5b9f79..8162017ca8 100644 --- a/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.json +++ b/erpnext/manufacturing/report/bom_operations_time/bom_operations_time.json @@ -1,14 +1,16 @@ { - "add_total_row": 0, + "add_total_row": 1, + "columns": [], "creation": "2020-03-03 01:41:20.862521", "disable_prepared_report": 0, "disabled": 0, "docstatus": 0, "doctype": "Report", + "filters": [], "idx": 0, "is_standard": "Yes", "letter_head": "", - "modified": "2020-03-03 01:41:20.862521", + "modified": "2022-01-20 14:21:47.771591", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Operations Time", From 7e407bcc42260e78ed7275946f71e3e7a89b282f Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 20 Jan 2022 14:49:39 +0530 Subject: [PATCH 17/53] fix: show stock UOM for material transfers (#29376) --- .../manufacturing/doctype/production_plan/production_plan.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 19a0694901..8b1dbd0b90 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -948,6 +948,7 @@ def get_materials_from_other_locations(item, warehouses, new_mr_items, company): warehouses, item.get("quantity"), company, ignore_validation=True) required_qty = item.get("quantity") + # get available material by transferring to production warehouse for d in locations: if required_qty <=0: return @@ -958,12 +959,14 @@ def get_materials_from_other_locations(item, warehouses, new_mr_items, company): new_dict.update({ "quantity": quantity, "material_request_type": "Material Transfer", + "uom": new_dict.get("stock_uom"), # internal transfer should be in stock UOM "from_warehouse": d.get("warehouse") }) required_qty -= quantity new_mr_items.append(new_dict) + # raise purchase request for remaining qty if required_qty: stock_uom, purchase_uom = frappe.db.get_value( 'Item', From cce35c15360ca9a67bafb1c71ad4655312585cac Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 20 Jan 2022 19:42:08 +0530 Subject: [PATCH 18/53] fix(patch): delete hospitality custom fields (#29382) --- erpnext/patches.txt | 2 +- erpnext/patches/v14_0/delete_hospitality_doctypes.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 981500e1c7..e21671c9c6 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -326,7 +326,7 @@ erpnext.patches.v14_0.set_payroll_cost_centers erpnext.patches.v13_0.agriculture_deprecation_warning erpnext.patches.v14_0.delete_agriculture_doctypes erpnext.patches.v13_0.hospitality_deprecation_warning -erpnext.patches.v14_0.delete_hospitality_doctypes +erpnext.patches.v14_0.delete_hospitality_doctypes # 20-01-2022 erpnext.patches.v13_0.update_exchange_rate_settings erpnext.patches.v14_0.rearrange_company_fields erpnext.patches.v14_0.update_leave_notification_template diff --git a/erpnext/patches/v14_0/delete_hospitality_doctypes.py b/erpnext/patches/v14_0/delete_hospitality_doctypes.py index 5bb5e4bb89..d0216f80d3 100644 --- a/erpnext/patches/v14_0/delete_hospitality_doctypes.py +++ b/erpnext/patches/v14_0/delete_hospitality_doctypes.py @@ -20,3 +20,13 @@ def execute(): doctypes = frappe.get_all("DocType", {"module": module, "custom": 0}, pluck='name') for doctype in doctypes: frappe.delete_doc("DocType", doctype, ignore_missing=True) + + custom_fields = [ + {"dt": "Sales Invoice", "fieldname": "restaurant"}, + {"dt": "Sales Invoice", "fieldname": "restaurant_table"}, + {"dt": "Price List", "fieldname": "restaurant_menu"}, + ] + + for field in custom_fields: + custom_field = frappe.db.get_value("Custom Field", field) + frappe.delete_doc("Custom Field", custom_field, ignore_missing=True) From 60bfead773943f4b877483f8cf2b8bbafe6dedba Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 21 Jan 2022 11:32:55 +0530 Subject: [PATCH 19/53] fix: first depreciation amount in asset --- erpnext/assets/doctype/asset/asset.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index ee3ec8e63a..ff52f370ef 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -242,8 +242,9 @@ class Asset(AccountsController): # For first row if has_pro_rata and not self.opening_accumulated_depreciation and n==0: + from_date = add_days(self.available_for_use_date, -1) # needed to calc depr amount for available_for_use_date too depreciation_amount, days, months = self.get_pro_rata_amt(finance_book, depreciation_amount, - self.available_for_use_date, finance_book.depreciation_start_date) + from_date, finance_book.depreciation_start_date) # For first depr schedule date will be the start date # so monthly schedule date is calculated by removing month difference between use date and start date From 0bbde4819bb2d3241b9b9d431cb7b7aa493b1cdd Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 21 Jan 2022 11:42:09 +0530 Subject: [PATCH 20/53] fix: depreciation amount on selling an asset --- erpnext/assets/doctype/asset/asset.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index ff52f370ef..e3bb923a91 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -375,7 +375,9 @@ class Asset(AccountsController): if from_date: return from_date - return self.available_for_use_date + + # since depr for available_for_use_date is not yet booked + return add_days(self.available_for_use_date, -1) # if it returns True, depreciation_amount will not be equal for the first and last rows def check_is_pro_rata(self, row): From 20216fa9f1e98e612c36a89e497de3e92238db7b Mon Sep 17 00:00:00 2001 From: Noah Jacob Date: Fri, 21 Jan 2022 11:50:13 +0530 Subject: [PATCH 21/53] fix: updated packed_items getting fetched on Sales Return / Credit Note (#28607) * fix: updated packed_items getting fetched on sales return * fix: updated test cases for product bundle returns * fix: moved calculate_mapped_packed_items_return to stock.utils * fix: updated packed_items getting fetched on Return/Credit Note * refactor: change var name to avoid `self` * fix: check item code before assigning parent item Co-authored-by: Ankush Menat --- .../accounts/doctype/sales_invoice/sales_invoice.py | 8 ++++++-- .../stock/doctype/delivery_note/delivery_note.py | 9 +++++++-- .../doctype/delivery_note/test_delivery_note.py | 12 ++++++++++-- .../stock_ledger_entry/test_stock_ledger_entry.py | 8 +++++--- erpnext/stock/utils.py | 13 +++++++++++++ 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 98bc9539c2..f04e7eacb9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -43,6 +43,7 @@ from erpnext.setup.doctype.company.company import update_company_current_month_s from erpnext.stock.doctype.batch.batch import set_batch_nos from erpnext.stock.doctype.delivery_note.delivery_note import update_billed_amount_based_on_so from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no, get_serial_nos +from erpnext.stock.utils import calculate_mapped_packed_items_return form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -728,8 +729,11 @@ class SalesInvoice(SellingController): def update_packing_list(self): if cint(self.update_stock) == 1: - from erpnext.stock.doctype.packed_item.packed_item import make_packing_list - make_packing_list(self) + if cint(self.is_return) and self.return_against: + calculate_mapped_packed_items_return(self) + else: + from erpnext.stock.doctype.packed_item.packed_item import make_packing_list + make_packing_list(self) else: self.set('packed_items', []) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 70d48a42d7..d1e22440b9 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -14,6 +14,7 @@ from erpnext.controllers.accounts_controller import get_taxes_and_charges from erpnext.controllers.selling_controller import SellingController from erpnext.stock.doctype.batch.batch import set_batch_nos from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no +from erpnext.stock.utils import calculate_mapped_packed_items_return form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -128,8 +129,12 @@ class DeliveryNote(SellingController): self.validate_uom_is_integer("uom", "qty") self.validate_with_previous_doc() - from erpnext.stock.doctype.packed_item.packed_item import make_packing_list - make_packing_list(self) + # Keeps mapped packed_items in case product bundle is updated. + if self.is_return and self.return_against: + calculate_mapped_packed_items_return(self) + else: + from erpnext.stock.doctype.packed_item.packed_item import make_packing_list + make_packing_list(self) if self._action != 'submit' and not self.is_return: set_batch_nos(self, 'warehouse', throw=True) diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index 4f89a19f3c..bd18e788ba 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -386,8 +386,7 @@ class TestDeliveryNote(ERPNextTestCase): self.assertEqual(actual_qty, 25) # return bundled item - dn1 = create_delivery_note(item_code='_Test Product Bundle Item', is_return=1, - return_against=dn.name, qty=-2, rate=500, company=company, warehouse="Stores - TCP1", expense_account="Cost of Goods Sold - TCP1", cost_center="Main - TCP1") + dn1 = create_return_delivery_note(source_name=dn.name, rate=500, qty=-2) # qty after return actual_qty = get_qty_after_transaction(warehouse="Stores - TCP1") @@ -823,6 +822,15 @@ class TestDeliveryNote(ERPNextTestCase): automatically_fetch_payment_terms(enable=0) +def create_return_delivery_note(**args): + args = frappe._dict(args) + from erpnext.controllers.sales_and_purchase_return import make_return_doc + doc = make_return_doc("Delivery Note", args.source_name, None) + doc.items[0].rate = args.rate + doc.items[0].qty = args.qty + doc.submit() + return doc + def create_delivery_note(**args): dn = frappe.new_doc("Delivery Note") args = frappe._dict(args) diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py index cafbd7581c..a1030d5496 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py @@ -5,7 +5,10 @@ import frappe from frappe.core.page.permission_manager.permission_manager import reset from frappe.utils import add_days, today -from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note +from erpnext.stock.doctype.delivery_note.test_delivery_note import ( + create_delivery_note, + create_return_delivery_note, +) from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import ( create_landed_cost_voucher, @@ -232,8 +235,7 @@ class TestStockLedgerEntry(ERPNextTestCase): self.assertEqual(outgoing_rate, 100) # Return Entry: Qty = -2, Rate = 150 - return_dn = create_delivery_note(is_return=1, return_against=dn.name, item_code=bundled_item, qty=-2, rate=150, - company=company, warehouse="Stores - _TC", expense_account="Cost of Goods Sold - _TC", cost_center="Main - _TC") + return_dn = create_return_delivery_note(source_name=dn.name, rate=150, qty=-2) # check incoming rate for Return entry incoming_rate, stock_value_difference = frappe.db.get_value("Stock Ledger Entry", diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 3c70b41eda..1a846f035a 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -419,6 +419,19 @@ def is_reposting_item_valuation_in_progress(): if reposting_in_progress: frappe.msgprint(_("Item valuation reposting in progress. Report might show incorrect item valuation."), alert=1) + +def calculate_mapped_packed_items_return(return_doc): + parent_items = set([item.parent_item for item in return_doc.packed_items]) + against_doc = frappe.get_doc(return_doc.doctype, return_doc.return_against) + + for original_bundle, returned_bundle in zip(against_doc.items, return_doc.items): + if original_bundle.item_code in parent_items: + for returned_packed_item, original_packed_item in zip(return_doc.packed_items, against_doc.packed_items): + if returned_packed_item.parent_item == original_bundle.item_code: + returned_packed_item.parent_detail_docname = returned_bundle.name + returned_packed_item.qty = (original_packed_item.qty / original_bundle.qty) * returned_bundle.qty + + def check_pending_reposting(posting_date: str, throw_error: bool = True) -> bool: """Check if there are pending reposting job till the specified posting date.""" From ae580d116cf0972bacb32d509ea37ea94911a6af Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 21 Jan 2022 12:19:53 +0530 Subject: [PATCH 22/53] fix: failing test cases --- .../sales_invoice/test_sales_invoice.py | 18 +++++----- erpnext/assets/doctype/asset/test_asset.py | 33 ++++++++++--------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index cfa42f6905..55e3853060 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2192,9 +2192,9 @@ class TestSalesInvoice(unittest.TestCase): asset.load_from_db() expected_values = [ - ["2020-06-30", 1311.48, 1311.48], - ["2021-06-30", 20000.0, 21311.48], - ["2021-09-30", 5041.1, 26352.58] + ["2020-06-30", 1366.12, 1366.12], + ["2021-06-30", 20000.0, 21366.12], + ["2021-09-30", 5041.1, 26407.22] ] for i, schedule in enumerate(asset.schedules): @@ -2242,12 +2242,12 @@ class TestSalesInvoice(unittest.TestCase): asset.load_from_db() expected_values = [ - ["2020-06-30", 1311.48, 1311.48, True], - ["2021-06-30", 20000.0, 21311.48, True], - ["2022-06-30", 20000.0, 41311.48, False], - ["2023-06-30", 20000.0, 61311.48, False], - ["2024-06-30", 20000.0, 81311.48, False], - ["2025-06-06", 18688.52, 100000.0, False] + ["2020-06-30", 1366.12, 1366.12, True], + ["2021-06-30", 20000.0, 21366.12, True], + ["2022-06-30", 20000.0, 41366.12, False], + ["2023-06-30", 20000.0, 61366.12, False], + ["2024-06-30", 20000.0, 81366.12, False], + ["2025-06-06", 18633.88, 100000.0, False] ] for i, schedule in enumerate(asset.schedules): diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 44c4ce542d..5b09b4cbd4 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -207,9 +207,9 @@ class TestAsset(AssetSetup): self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Sold") expected_gle = ( - ("_Test Accumulated Depreciations - _TC", 20392.16, 0.0), + ("_Test Accumulated Depreciations - _TC", 20490.2, 0.0), ("_Test Fixed Asset - _TC", 0.0, 100000.0), - ("_Test Gain/Loss on Asset Disposal - _TC", 54607.84, 0.0), + ("_Test Gain/Loss on Asset Disposal - _TC", 54509.8, 0.0), ("Debtors - _TC", 25000.0, 0.0) ) @@ -491,10 +491,10 @@ class TestDepreciationMethods(AssetSetup): ) expected_schedules = [ - ["2030-12-31", 27534.25, 27534.25], - ["2031-12-31", 30000.0, 57534.25], - ["2032-12-31", 30000.0, 87534.25], - ["2033-01-30", 2465.75, 90000.0] + ['2030-12-31', 27616.44, 27616.44], + ['2031-12-31', 30000.0, 57616.44], + ['2032-12-31', 30000.0, 87616.44], + ['2033-01-30', 2383.56, 90000.0] ] schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] @@ -544,10 +544,10 @@ class TestDepreciationMethods(AssetSetup): self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0) expected_schedules = [ - ["2030-12-31", 28493.15, 28493.15], - ["2031-12-31", 35753.43, 64246.58], - ["2032-12-31", 17876.71, 82123.29], - ["2033-06-06", 5376.71, 87500.0] + ['2030-12-31', 28630.14, 28630.14], + ['2031-12-31', 35684.93, 64315.07], + ['2032-12-31', 17842.47, 82157.54], + ['2033-06-06', 5342.46, 87500.0] ] schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] @@ -580,10 +580,10 @@ class TestDepreciationMethods(AssetSetup): self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0) expected_schedules = [ - ["2030-12-31", 11780.82, 11780.82], - ["2031-12-31", 44109.59, 55890.41], - ["2032-12-31", 22054.8, 77945.21], - ["2033-07-12", 9554.79, 87500.0] + ["2030-12-31", 11849.32, 11849.32], + ["2031-12-31", 44075.34, 55924.66], + ["2032-12-31", 22037.67, 77962.33], + ["2033-07-12", 9537.67, 87500.0] ] schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)] @@ -621,7 +621,7 @@ class TestDepreciationBasics(AssetSetup): asset = create_asset( item_code = "Macbook Pro", calculate_depreciation = 1, - available_for_use_date = getdate("2019-12-31"), + available_for_use_date = getdate("2020-01-01"), total_number_of_depreciations = 3, expected_value_after_useful_life = 10000, depreciation_start_date = getdate("2020-07-01"), @@ -632,7 +632,7 @@ class TestDepreciationBasics(AssetSetup): ["2020-07-01", 15000, 15000], ["2021-07-01", 30000, 45000], ["2022-07-01", 30000, 75000], - ["2022-12-31", 15000, 90000] + ["2023-01-01", 15000, 90000] ] for i, schedule in enumerate(asset.schedules): @@ -1109,6 +1109,7 @@ class TestDepreciationBasics(AssetSetup): self.assertEqual(gle, expected_gle) self.assertEqual(asset.get("value_after_depreciation"), 0) + def test_expected_value_change(self): """ tests if changing `expected_value_after_useful_life` From 53addfda1547f03ce2c53b839ff8042f736f606f Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 21 Jan 2022 12:23:52 +0530 Subject: [PATCH 23/53] fix: sider issue --- .../customer_credit_balance.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py index 0997b51cd2..dd49f1355d 100644 --- a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py +++ b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py @@ -30,12 +30,17 @@ def execute(filters=None): bal = flt(credit_limit) - flt(outstanding_amt) if customer_naming_type == "Naming Series": - row = [d.name, d.customer_name, credit_limit, outstanding_amt, bal, - d.bypass_credit_limit_check, d.is_frozen, - d.disabled] + row = [ + d.name, d.customer_name, credit_limit, + outstanding_amt, bal, d.bypass_credit_limit_check, + d.is_frozen, d.disabled + ] else: - row = [d.name, credit_limit, outstanding_amt, bal, - d.bypass_credit_limit_check, d.is_frozen, d.disabled] + row = [ + d.name, credit_limit, outstanding_amt, bal, + d.bypass_credit_limit_check, d.is_frozen, + d.disabled + ] if credit_limit: data.append(row) From f5ed0c83b7bae03e657b7a6920bd8a8b490d3917 Mon Sep 17 00:00:00 2001 From: Himanshu Date: Fri, 21 Jan 2022 13:05:47 +0530 Subject: [PATCH 24/53] fix(Timesheets): calculate to time (#28589) Co-authored-by: Ankush Menat Co-authored-by: barredterra <14891507+barredterra@users.noreply.github.com> --- .../doctype/timesheet/test_timesheet.py | 23 ++++++++++++++++++- .../projects/doctype/timesheet/timesheet.py | 11 ++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py index 148d8ba29c..989bcd1670 100644 --- a/erpnext/projects/doctype/timesheet/test_timesheet.py +++ b/erpnext/projects/doctype/timesheet/test_timesheet.py @@ -5,7 +5,7 @@ import datetime import unittest import frappe -from frappe.utils import add_months, now_datetime, nowdate +from frappe.utils import add_months, add_to_date, now_datetime, nowdate from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.hr.doctype.employee.test_employee import make_employee @@ -151,6 +151,27 @@ class TestTimesheet(unittest.TestCase): settings.ignore_employee_time_overlap = initial_setting settings.save() + def test_to_time(self): + emp = make_employee("test_employee_6@salary.com") + from_time = now_datetime() + + timesheet = frappe.new_doc("Timesheet") + timesheet.employee = emp + timesheet.append( + 'time_logs', + { + "billable": 1, + "activity_type": "_Test Activity Type", + "from_time": from_time, + "hours": 2, + "company": "_Test Company" + } + ) + timesheet.save() + + to_time = timesheet.time_logs[0].to_time + self.assertEqual(to_time, add_to_date(from_time, hours=2, as_datetime=True)) + def make_salary_structure_for_timesheet(employee, company=None): salary_structure_name = "Timesheet Salary Structure Test" diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py index e92785e06c..dd0b5f90f4 100644 --- a/erpnext/projects/doctype/timesheet/timesheet.py +++ b/erpnext/projects/doctype/timesheet/timesheet.py @@ -7,7 +7,7 @@ import json import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import flt, getdate, time_diff_in_hours +from frappe.utils import add_to_date, flt, getdate, time_diff_in_hours from erpnext.controllers.queries import get_match_cond from erpnext.hr.utils import validate_active_employee @@ -136,10 +136,19 @@ class Timesheet(Document): def validate_time_logs(self): for data in self.get('time_logs'): + self.set_to_time(data) self.validate_overlap(data) self.set_project(data) self.validate_project(data) + def set_to_time(self, data): + if not (data.from_time and data.hours): + return + + _to_time = add_to_date(data.from_time, hours=data.hours, as_datetime=True) + if data.to_time != _to_time: + data.to_time = _to_time + def validate_overlap(self, data): settings = frappe.get_single('Projects Settings') self.validate_overlap_for("user", data, self.user, settings.ignore_user_time_overlap) From 11c9a5a79f2ddb66558658069f10250ac5cbea05 Mon Sep 17 00:00:00 2001 From: Noah Jacob Date: Fri, 21 Jan 2022 14:48:33 +0530 Subject: [PATCH 25/53] fix: update status on visit cancel (#29389) * fix: update status on cancelling visit * test: updated test for cancelling visits --- .../test_maintenance_schedule.py | 8 +++++++ .../maintenance_visit/maintenance_visit.py | 24 +++++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py index 4d3c3f48f4..6e727e53ef 100644 --- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py +++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py @@ -4,6 +4,7 @@ import unittest import frappe +from frappe.utils import format_date from frappe.utils.data import add_days, formatdate, today from erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule import ( @@ -82,6 +83,13 @@ class TestMaintenanceSchedule(unittest.TestCase): #checks if visit status is back updated in schedule self.assertTrue(ms.schedules[1].completion_status, "Partially Completed") + self.assertEqual(format_date(visit.mntc_date), format_date(ms.schedules[1].actual_date)) + + #checks if visit status is updated on cancel + visit.cancel() + ms.reload() + self.assertTrue(ms.schedules[1].completion_status, "Pending") + self.assertEqual(ms.schedules[1].actual_date, None) def test_serial_no_filters(self): # Without serial no. set in schedule -> returns None diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py index d5d87536da..6fe2466be2 100644 --- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py +++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py @@ -4,7 +4,7 @@ import frappe from frappe import _ -from frappe.utils import get_datetime +from frappe.utils import format_date, get_datetime from erpnext.utilities.transaction_base import TransactionBase @@ -28,20 +28,24 @@ class MaintenanceVisit(TransactionBase): if item_ref: start_date, end_date = frappe.db.get_value('Maintenance Schedule Item', item_ref, ['start_date', 'end_date']) if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(self.mntc_date) > get_datetime(end_date): - frappe.throw(_("Date must be between {0} and {1}").format(start_date, end_date)) + frappe.throw(_("Date must be between {0} and {1}") + .format(format_date(start_date), format_date(end_date))) + def validate(self): self.validate_serial_no() self.validate_maintenance_date() self.validate_purpose_table() - def update_completion_status(self): + def update_status_and_actual_date(self, cancel=False): + status = "Pending" + actual_date = None + if not cancel: + status = self.completion_status + actual_date = self.mntc_date if self.maintenance_schedule_detail: - frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'completion_status', self.completion_status) - - def update_actual_date(self): - if self.maintenance_schedule_detail: - frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'actual_date', self.mntc_date) + frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'completion_status', status) + frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'actual_date', actual_date) def update_customer_issue(self, flag): if not self.maintenance_schedule: @@ -102,12 +106,12 @@ class MaintenanceVisit(TransactionBase): def on_submit(self): self.update_customer_issue(1) frappe.db.set(self, 'status', 'Submitted') - self.update_completion_status() - self.update_actual_date() + self.update_status_and_actual_date() def on_cancel(self): self.check_if_last_visit() frappe.db.set(self, 'status', 'Cancelled') + self.update_status_and_actual_date(cancel=True) def on_update(self): pass From ea5efd0791b1a55b18027c6a07b408ea11fd63cb Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 21 Jan 2022 13:12:31 +0530 Subject: [PATCH 26/53] perf: single query to update serial nos --- erpnext/controllers/stock_controller.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index f22669b255..b97432e748 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -256,11 +256,7 @@ class StockController(AccountsController): for d in self.items: if not d.batch_no: continue - serial_nos = [sr.name for sr in frappe.get_all("Serial No", - {'batch_no': d.batch_no, 'status': 'Inactive'})] - - if serial_nos: - frappe.db.set_value("Serial No", { 'name': ['in', serial_nos] }, "batch_no", None) + frappe.db.set_value("Serial No", {"batch_no": d.batch_no, "status": "Inactive"}, "batch_no", None) d.batch_no = None d.db_set("batch_no", None) From 33c4a0b5a96178be7d448d15cbe7643f7276cffd Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 21 Jan 2022 14:04:09 +0530 Subject: [PATCH 27/53] fix: bad default for non-existing serial nos serial_no field should have empty string if it doesn't have any serial nos --- erpnext/stock/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py index 1a846f035a..f620c183eb 100644 --- a/erpnext/stock/utils.py +++ b/erpnext/stock/utils.py @@ -103,7 +103,7 @@ def get_stock_balance(item_code, warehouse, posting_date=None, posting_time=None serial_nos = get_serial_nos_data_after_transactions(args) return ((last_entry.qty_after_transaction, last_entry.valuation_rate, serial_nos) - if last_entry else (0.0, 0.0, 0.0)) + if last_entry else (0.0, 0.0, None)) else: return (last_entry.qty_after_transaction, last_entry.valuation_rate) if last_entry else (0.0, 0.0) else: From 203f0086f8ce3990e47f58095aab40ce49532e74 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 21 Jan 2022 14:12:35 +0530 Subject: [PATCH 28/53] fix(patch): update stock reconciliation current serial nos When current serial nos are non-existing there shouldn't be any value in current_serial_no field. --- erpnext/patches.txt | 1 + .../patches/v13_0/wipe_serial_no_field_for_0_qty.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 44c74b1289..30679f14e3 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -318,6 +318,7 @@ erpnext.patches.v13_0.create_ksa_vat_custom_fields # 07-01-2022 erpnext.patches.v14_0.rename_ongoing_status_in_sla_documents erpnext.patches.v14_0.migrate_crm_settings erpnext.patches.v13_0.rename_ksa_qr_field +erpnext.patches.v13_0.wipe_serial_no_field_for_0_qty erpnext.patches.v13_0.disable_ksa_print_format_for_others # 16-12-2021 erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template erpnext.patches.v13_0.update_tax_category_for_rcm diff --git a/erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py b/erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py new file mode 100644 index 0000000000..30b7592466 --- /dev/null +++ b/erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py @@ -0,0 +1,11 @@ +import frappe + + +def execute(): + sr_item = frappe.qb.DocType("Stock Reconciliation Item") + + (frappe.qb + .update(sr_item) + .set(sr_item.current_serial_no, None) + .where(sr_item.current_qty == 0) + ).run() From 4fa93e246eeac8b44da2a850a231c20083352e79 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 21 Jan 2022 14:21:49 +0530 Subject: [PATCH 29/53] test: create and cancel sr no with stock reco --- .../test_stock_reconciliation.py | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py index c4ddc9e2d6..428370cc75 100644 --- a/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/test_stock_reconciliation.py @@ -6,7 +6,7 @@ import frappe -from frappe.utils import add_days, flt, nowdate, nowtime, random_string +from frappe.utils import add_days, cstr, flt, nowdate, nowtime, random_string from erpnext.accounts.utils import get_stock_and_account_balance from erpnext.stock.doctype.item.test_item import create_item @@ -439,8 +439,8 @@ class TestStockReconciliation(ERPNextTestCase): self.assertRaises(frappe.ValidationError, sr.submit) def test_serial_no_cancellation(self): - from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry + item = create_item("Stock-Reco-Serial-Item-9", is_stock_item=1) if not item.has_serial_no: item.has_serial_no = 1 @@ -466,6 +466,31 @@ class TestStockReconciliation(ERPNextTestCase): self.assertEqual(len(active_sr_no), 10) + def test_serial_no_creation_and_inactivation(self): + item = create_item("_TestItemCreatedWithStockReco", is_stock_item=1) + if not item.has_serial_no: + item.has_serial_no = 1 + item.save() + + item_code = item.name + warehouse = "_Test Warehouse - _TC" + + sr = create_stock_reconciliation(item_code=item.name, warehouse=warehouse, + serial_no="SR-CREATED-SR-NO", qty=1, do_not_submit=True, rate=100) + sr.save() + self.assertEqual(cstr(sr.items[0].current_serial_no), "") + sr.submit() + + active_sr_no = frappe.get_all("Serial No", + filters={"item_code": item_code, "warehouse": warehouse, "status": "Active"}) + self.assertEqual(len(active_sr_no), 1) + + sr.cancel() + active_sr_no = frappe.get_all("Serial No", + filters={"item_code": item_code, "warehouse": warehouse, "status": "Active"}) + self.assertEqual(len(active_sr_no), 0) + + def create_batch_item_with_batch(item_name, batch_id): batch_item_doc = create_item(item_name, is_stock_item=1) if not batch_item_doc.has_batch_no: From dc8dad44569ec88d28a8ba7d1fbb81ae44af321c Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 21 Jan 2022 16:08:39 +0530 Subject: [PATCH 30/53] fix(patch): skip patch if column doesn't exist --- erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py b/erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py index 30b7592466..e43a8bad8e 100644 --- a/erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py +++ b/erpnext/patches/v13_0/wipe_serial_no_field_for_0_qty.py @@ -2,7 +2,14 @@ import frappe def execute(): - sr_item = frappe.qb.DocType("Stock Reconciliation Item") + + doctype = "Stock Reconciliation Item" + + if not frappe.db.has_column(doctype, "current_serial_no"): + # nothing to fix if column doesn't exist + return + + sr_item = frappe.qb.DocType(doctype) (frappe.qb .update(sr_item) From e2267cdba85471ce602c90d22ac67e4135a04ad9 Mon Sep 17 00:00:00 2001 From: ruthra Date: Fri, 21 Jan 2022 19:21:26 +0530 Subject: [PATCH 31/53] fix: opening invoice creation tool not taking in accouting dimension --- .../opening_invoice_creation_tool.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py index ddb833ff3b..19d8d49dfe 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/opening_invoice_creation_tool.py @@ -135,7 +135,7 @@ class OpeningInvoiceCreationTool(Document): default_uom = frappe.db.get_single_value("Stock Settings", "stock_uom") or _("Nos") rate = flt(row.outstanding_amount) / flt(row.qty) - return frappe._dict({ + item_dict = frappe._dict({ "uom": default_uom, "rate": rate or 0.0, "qty": row.qty, @@ -146,6 +146,13 @@ class OpeningInvoiceCreationTool(Document): "cost_center": cost_center }) + for dimension in get_accounting_dimensions(): + item_dict.update({ + dimension: row.get(dimension) + }) + + return item_dict + item = get_item_dict() invoice = frappe._dict({ @@ -166,7 +173,7 @@ class OpeningInvoiceCreationTool(Document): accounting_dimension = get_accounting_dimensions() for dimension in accounting_dimension: invoice.update({ - dimension: item.get(dimension) + dimension: self.get(dimension) or item.get(dimension) }) return invoice From 88463dc494089abcdc7b9655747c75b180b7470d Mon Sep 17 00:00:00 2001 From: ruthra Date: Fri, 21 Jan 2022 19:33:06 +0530 Subject: [PATCH 32/53] test: validating custom accouting dimension in opening invoice tool - create new dimension 'department' - assign and validate department in opening invoices --- .../test_opening_invoice_creation_tool.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py index b5aae9845b..41c47c59cb 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py @@ -11,17 +11,19 @@ from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_crea get_temporary_opening_account, ) -test_dependencies = ["Customer", "Supplier"] +from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension + +test_dependencies = ["Customer", "Supplier", "Accounting Dimension"] class TestOpeningInvoiceCreationTool(unittest.TestCase): def setUp(self): if not frappe.db.exists("Company", "_Test Opening Invoice Company"): make_company() - def make_invoices(self, invoice_type="Sales", company=None, party_1=None, party_2=None, invoice_number=None): + def make_invoices(self, invoice_type="Sales", company=None, party_1=None, party_2=None, invoice_number=None, department=None): doc = frappe.get_single("Opening Invoice Creation Tool") args = get_opening_invoice_creation_dict(invoice_type=invoice_type, company=company, - party_1=party_1, party_2=party_2, invoice_number=invoice_number) + party_1=party_1, party_2=party_2, invoice_number=invoice_number, department=department) doc.update(args) return doc.make_invoices() @@ -106,6 +108,18 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase): doc = frappe.get_doc('Sales Invoice', inv) doc.cancel() + def test_opening_invoice_with_accounting_dimension(self): + # new dimensions department and location are created + create_dimension() + invoices = self.make_invoices(invoice_type="Sales", company="_Test Opening Invoice Company", department='Sales - _TOIC') + + expected_value = { + "keys": ["customer", "outstanding_amount", "status", "department"], + 0: ["_Test Customer", 300, "Overdue", "Sales - _TOIC"], + 1: ["_Test Customer 1", 250, "Overdue", "Sales - _TOIC"], + } + self.check_expected_values(invoices, expected_value, invoice_type="Sales") + def get_opening_invoice_creation_dict(**args): party = "Customer" if args.get("invoice_type", "Sales") == "Sales" else "Supplier" company = args.get("company", "_Test Company") From 8e3cd1ab31c56f22919d9d902a405a18f0bf4884 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sun, 23 Jan 2022 17:04:55 +0530 Subject: [PATCH 33/53] fix: Don't delete barcode while saving Item (#29411) (#29417) (cherry picked from commit 096e7b9ec5e3b67983cfa3a06335fba435f88c97) Co-authored-by: Britlog --- erpnext/stock/doctype/item/item.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 281e881875..d99fadca46 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -602,14 +602,6 @@ class Item(WebsiteGenerator): frappe.throw(_("Barcode {0} is not a valid {1} code").format( item_barcode.barcode, item_barcode.barcode_type), InvalidBarcode) - if item_barcode.barcode != item_barcode.name: - # if barcode is getting updated , the row name has to reset. - # Delete previous old row doc and re-enter row as if new to reset name in db. - item_barcode.set("__islocal", True) - item_barcode_entry_name = item_barcode.name - item_barcode.name = None - frappe.delete_doc("Item Barcode", item_barcode_entry_name) - def validate_warehouse_for_reorder(self): '''Validate Reorder level table for duplicate and conditional mandatory''' warehouse = [] From 80ea16395336da5dc9b12d561f90fab1eb2e0b00 Mon Sep 17 00:00:00 2001 From: ruthra Date: Sun, 23 Jan 2022 21:49:02 +0530 Subject: [PATCH 34/53] fix: linter issue --- .../test_opening_invoice_creation_tool.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py index 41c47c59cb..be34ce64f6 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py @@ -7,12 +7,13 @@ import frappe from frappe.cache_manager import clear_doctype_cache from frappe.custom.doctype.property_setter.property_setter import make_property_setter +from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import ( + create_dimension, +) from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import ( get_temporary_opening_account, ) -from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension - test_dependencies = ["Customer", "Supplier", "Accounting Dimension"] class TestOpeningInvoiceCreationTool(unittest.TestCase): From f122a47d0db5438cc1fc8b2138153af64a9a3bab Mon Sep 17 00:00:00 2001 From: ruthra Date: Mon, 24 Jan 2022 10:08:25 +0530 Subject: [PATCH 35/53] refactor: fix failing test cases --- .../test_opening_invoice_creation_tool.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py index be34ce64f6..6700e9b975 100644 --- a/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py +++ b/erpnext/accounts/doctype/opening_invoice_creation_tool/test_opening_invoice_creation_tool.py @@ -9,6 +9,7 @@ from frappe.custom.doctype.property_setter.property_setter import make_property_ from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import ( create_dimension, + disable_dimension, ) from erpnext.accounts.doctype.opening_invoice_creation_tool.opening_invoice_creation_tool import ( get_temporary_opening_account, @@ -20,6 +21,7 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase): def setUp(self): if not frappe.db.exists("Company", "_Test Opening Invoice Company"): make_company() + create_dimension() def make_invoices(self, invoice_type="Sales", company=None, party_1=None, party_2=None, invoice_number=None, department=None): doc = frappe.get_single("Opening Invoice Creation Tool") @@ -110,8 +112,6 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase): doc.cancel() def test_opening_invoice_with_accounting_dimension(self): - # new dimensions department and location are created - create_dimension() invoices = self.make_invoices(invoice_type="Sales", company="_Test Opening Invoice Company", department='Sales - _TOIC') expected_value = { @@ -121,6 +121,9 @@ class TestOpeningInvoiceCreationTool(unittest.TestCase): } self.check_expected_values(invoices, expected_value, invoice_type="Sales") + def tearDown(self): + disable_dimension() + def get_opening_invoice_creation_dict(**args): party = "Customer" if args.get("invoice_type", "Sales") == "Sales" else "Supplier" company = args.get("company", "_Test Company") From f8d232ac260383764fb31076e4993f4194191ed3 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Sun, 23 Jan 2022 23:20:40 +0530 Subject: [PATCH 36/53] fix: incorrect raw materials quantity in manufacture stock entry --- .../doctype/work_order/test_work_order.py | 48 +++++++++++++++++++ .../stock/doctype/stock_entry/stock_entry.py | 11 +++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index e7eb9c6149..a399edda70 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -911,6 +911,54 @@ class TestWorkOrder(ERPNextTestCase): self.assertEqual(wo1.operations[0].time_in_mins, wo2.operations[0].time_in_mins) + def test_partial_manufacture_entries(self): + cancel_stock_entry = [] + + frappe.db.set_value("Manufacturing Settings", None, + "backflush_raw_materials_based_on", "Material Transferred for Manufacture") + + wo_order = make_wo_order_test_record(planned_start_date=now(), qty=100) + ste1 = test_stock_entry.make_stock_entry(item_code="_Test Item", + target="_Test Warehouse - _TC", qty=120, basic_rate=5000.0) + ste2 = test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100", + target="_Test Warehouse - _TC", qty=240, basic_rate=1000.0) + + cancel_stock_entry.extend([ste1.name, ste2.name]) + + sm = frappe.get_doc(make_stock_entry(wo_order.name, "Material Transfer for Manufacture", 100)) + for row in sm.get('items'): + if row.get('item_code') == '_Test Item': + row.qty = 110 + + sm.submit() + cancel_stock_entry.append(sm.name) + + s = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 90)) + for row in s.get('items'): + if row.get('item_code') == '_Test Item': + self.assertEqual(row.get('qty'), 100) + s.submit() + cancel_stock_entry.append(s.name) + + s1 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 5)) + for row in s1.get('items'): + if row.get('item_code') == '_Test Item': + self.assertEqual(row.get('qty'), 5) + s1.submit() + cancel_stock_entry.append(s1.name) + + s2 = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 5)) + for row in s2.get('items'): + if row.get('item_code') == '_Test Item': + self.assertEqual(row.get('qty'), 5) + + cancel_stock_entry.reverse() + for ste in cancel_stock_entry: + doc = frappe.get_doc("Stock Entry", ste) + doc.cancel() + + frappe.db.set_value("Manufacturing Settings", None, + "backflush_raw_materials_based_on", "BOM") def update_job_card(job_card, jc_qty=None): employee = frappe.db.get_value('Employee', {'status': 'Active'}, 'name') diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index d1149ea6a2..c93edee7b7 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -1444,14 +1444,15 @@ class StockEntry(StockController): qty = req_qty_each * flt(self.fg_completed_qty) elif backflushed_materials.get(item.item_code): + precision = frappe.get_precision("Stock Entry Detail", "qty") for d in backflushed_materials.get(item.item_code): - if d.get(item.warehouse): + if d.get(item.warehouse) > 0: if (qty > req_qty): - qty = (qty/trans_qty) * flt(self.fg_completed_qty) + qty = ((flt(qty, precision) - flt(d.get(item.warehouse), precision)) + / (flt(trans_qty, precision) - flt(produced_qty, precision)) + ) * flt(self.fg_completed_qty) - if consumed_qty and frappe.db.get_single_value("Manufacturing Settings", - "material_consumption"): - qty -= consumed_qty + d[item.warehouse] -= qty if cint(frappe.get_cached_value('UOM', item.stock_uom, 'must_be_whole_number')): qty = frappe.utils.ceil(qty) From 78b6b29a57928d936181337d2ee5e85d951e5bce Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 24 Jan 2022 13:39:10 +0530 Subject: [PATCH 37/53] fix: Use get for conditionally available fields while setting missing values - Due to custom field "supplier" and missing field "supplier_address", dot operator breaks - Make sure to use "get" instead of just dot operator if field is in some doctypes, not all --- erpnext/controllers/buying_controller.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index f088b9ffc2..a181af7313 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -70,9 +70,18 @@ class BuyingController(StockController, Subcontracting): # 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, - doctype=self.doctype, company=self.company, party_address=self.supplier_address, shipping_address=self.get('shipping_address'), - fetch_payment_terms_template= not self.get('ignore_default_payment_terms_template'))) + self.update_if_missing( + get_party_details( + self.supplier, + party_type="Supplier", + doctype=self.doctype, + company=self.company, + party_address=self.get("supplier_address"), + shipping_address=self.get('shipping_address'), + fetch_payment_terms_template= not self.get('ignore_default_payment_terms_template'), + ignore_permissions=self.flags.ignore_permissions + ) + ) self.set_missing_item_details(for_validate) From 3d3f0139fd2df42a7753c7d2560e2451819dee92 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 24 Jan 2022 18:44:08 +0530 Subject: [PATCH 38/53] test: clear singles cache for changed settings (#29430) --- erpnext/tests/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/tests/utils.py b/erpnext/tests/utils.py index bc9f04e089..2bd7e9e71d 100644 --- a/erpnext/tests/utils.py +++ b/erpnext/tests/utils.py @@ -92,6 +92,8 @@ def change_settings(doctype, settings_dict): for key, value in settings_dict.items(): setattr(settings, key, value) settings.save() + # singles are cached by default, clear to avoid flake + frappe.db.value_cache[settings] = {} yield # yield control to calling function finally: From a1f0cb4ed1828d229ab631076ac655dece3b5601 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 24 Jan 2022 19:05:24 +0530 Subject: [PATCH 39/53] fix: honour 'include holidays' setting while marking attendance for leave application (#29425) --- .../leave_application/leave_application.py | 75 ++++++++---- .../test_leave_application.py | 115 ++++++++++++++++-- .../doctype/salary_slip/test_salary_slip.py | 2 + 3 files changed, 159 insertions(+), 33 deletions(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index 1dc5b31461..70250f5bcf 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -22,6 +22,7 @@ from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry from erpnext.hr.utils import ( + get_holiday_dates_for_employee, get_leave_period, set_employee_name, share_doc_with_approver, @@ -159,33 +160,57 @@ class LeaveApplication(Document): .format(formatdate(future_allocation[0].from_date), future_allocation[0].name)) def update_attendance(self): - if self.status == "Approved": - for dt in daterange(getdate(self.from_date), getdate(self.to_date)): - date = dt.strftime("%Y-%m-%d") - status = "Half Day" if self.half_day_date and getdate(date) == getdate(self.half_day_date) else "On Leave" - attendance_name = frappe.db.exists('Attendance', dict(employee = self.employee, - attendance_date = date, docstatus = ('!=', 2))) + if self.status != "Approved": + return + holiday_dates = [] + if not frappe.db.get_value("Leave Type", self.leave_type, "include_holiday"): + holiday_dates = get_holiday_dates_for_employee(self.employee, self.from_date, self.to_date) + + for dt in daterange(getdate(self.from_date), getdate(self.to_date)): + date = dt.strftime("%Y-%m-%d") + attendance_name = frappe.db.exists("Attendance", dict(employee = self.employee, + attendance_date = date, docstatus = ('!=', 2))) + + # don't mark attendance for holidays + # if leave type does not include holidays within leaves as leaves + if date in holiday_dates: if attendance_name: - # update existing attendance, change absent to on leave - doc = frappe.get_doc('Attendance', attendance_name) - if doc.status != status: - doc.db_set('status', status) - doc.db_set('leave_type', self.leave_type) - doc.db_set('leave_application', self.name) - else: - # make new attendance and submit it - doc = frappe.new_doc("Attendance") - doc.employee = self.employee - doc.employee_name = self.employee_name - doc.attendance_date = date - doc.company = self.company - doc.leave_type = self.leave_type - doc.leave_application = self.name - doc.status = status - doc.flags.ignore_validate = True - doc.insert(ignore_permissions=True) - doc.submit() + # cancel and delete existing attendance for holidays + attendance = frappe.get_doc("Attendance", attendance_name) + attendance.flags.ignore_permissions = True + if attendance.docstatus == 1: + attendance.cancel() + frappe.delete_doc("Attendance", attendance_name, force=1) + continue + + self.create_or_update_attendance(attendance_name, date) + + def create_or_update_attendance(self, attendance_name, date): + status = "Half Day" if self.half_day_date and getdate(date) == getdate(self.half_day_date) else "On Leave" + + if attendance_name: + # update existing attendance, change absent to on leave + doc = frappe.get_doc('Attendance', attendance_name) + if doc.status != status: + doc.db_set({ + 'status': status, + 'leave_type': self.leave_type, + 'leave_application': self.name + }) + else: + # make new attendance and submit it + doc = frappe.new_doc("Attendance") + doc.employee = self.employee + doc.employee_name = self.employee_name + doc.attendance_date = date + doc.company = self.company + doc.leave_type = self.leave_type + doc.leave_application = self.name + doc.status = status + doc.flags.ignore_validate = True + doc.insert(ignore_permissions=True) + doc.submit() def cancel_attendance(self): if self.docstatus == 2: diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py index 9b8d638452..75e99f8991 100644 --- a/erpnext/hr/doctype/leave_application/test_leave_application.py +++ b/erpnext/hr/doctype/leave_application/test_leave_application.py @@ -5,7 +5,16 @@ import unittest import frappe from frappe.permissions import clear_user_permissions_for_doctype -from frappe.utils import add_days, add_months, getdate, nowdate +from frappe.utils import ( + add_days, + add_months, + get_first_day, + get_last_day, + get_year_ending, + get_year_start, + getdate, + nowdate, +) from erpnext.hr.doctype.employee.test_employee import make_employee from erpnext.hr.doctype.leave_allocation.test_leave_allocation import create_leave_allocation @@ -19,6 +28,10 @@ from erpnext.hr.doctype.leave_policy_assignment.leave_policy_assignment import ( create_assignment_for_multiple_employees, ) from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type +from erpnext.payroll.doctype.salary_slip.test_salary_slip import ( + make_holiday_list, + make_leave_application, +) test_dependencies = ["Leave Allocation", "Leave Block List", "Employee"] @@ -61,13 +74,15 @@ class TestLeaveApplication(unittest.TestCase): for dt in ["Leave Application", "Leave Allocation", "Salary Slip", "Leave Ledger Entry"]: frappe.db.sql("DELETE FROM `tab%s`" % dt) #nosec + frappe.set_user("Administrator") + @classmethod def setUpClass(cls): set_leave_approver() frappe.db.sql("delete from tabAttendance where employee='_T-Employee-00001'") def tearDown(self): - frappe.set_user("Administrator") + frappe.db.rollback() def _clear_roles(self): frappe.db.sql("""delete from `tabHas Role` where parent in @@ -106,6 +121,72 @@ class TestLeaveApplication(unittest.TestCase): for d in ('2018-01-01', '2018-01-02', '2018-01-03'): self.assertTrue(getdate(d) in dates) + def test_attendance_for_include_holidays(self): + # Case 1: leave type with 'Include holidays within leaves as leaves' enabled + frappe.delete_doc_if_exists("Leave Type", "Test Include Holidays", force=1) + leave_type = frappe.get_doc(dict( + leave_type_name="Test Include Holidays", + doctype="Leave Type", + include_holiday=True + )).insert() + + date = getdate() + make_allocation_record(leave_type=leave_type.name, from_date=get_year_start(date), to_date=get_year_ending(date)) + + holiday_list = make_holiday_list() + frappe.db.set_value("Company", "_Test Company", "default_holiday_list", holiday_list) + first_sunday = get_first_sunday(holiday_list) + + leave_application = make_leave_application("_T-Employee-00001", first_sunday, add_days(first_sunday, 3), leave_type.name) + leave_application.reload() + self.assertEqual(leave_application.total_leave_days, 4) + self.assertEqual(frappe.db.count('Attendance', {'leave_application': leave_application.name}), 4) + + leave_application.cancel() + + def test_attendance_update_for_exclude_holidays(self): + # Case 2: leave type with 'Include holidays within leaves as leaves' disabled + frappe.delete_doc_if_exists("Leave Type", "Test Do Not Include Holidays", force=1) + leave_type = frappe.get_doc(dict( + leave_type_name="Test Do Not Include Holidays", + doctype="Leave Type", + include_holiday=False + )).insert() + + date = getdate() + make_allocation_record(leave_type=leave_type.name, from_date=get_year_start(date), to_date=get_year_ending(date)) + + holiday_list = make_holiday_list() + frappe.db.set_value("Company", "_Test Company", "default_holiday_list", holiday_list) + first_sunday = get_first_sunday(holiday_list) + + # already marked attendance on a holiday should be deleted in this case + config = { + "doctype": "Attendance", + "employee": "_T-Employee-00001", + "status": "Present" + } + attendance_on_holiday = frappe.get_doc(config) + attendance_on_holiday.attendance_date = first_sunday + attendance_on_holiday.save() + + # already marked attendance on a non-holiday should be updated + attendance = frappe.get_doc(config) + attendance.attendance_date = add_days(first_sunday, 3) + attendance.save() + + leave_application = make_leave_application("_T-Employee-00001", first_sunday, add_days(first_sunday, 3), leave_type.name) + leave_application.reload() + # holiday should be excluded while marking attendance + self.assertEqual(leave_application.total_leave_days, 3) + self.assertEqual(frappe.db.count("Attendance", {"leave_application": leave_application.name}), 3) + + # attendance on holiday deleted + self.assertFalse(frappe.db.exists("Attendance", attendance_on_holiday.name)) + + # attendance on non-holiday updated + self.assertEqual(frappe.db.get_value("Attendance", attendance.name, "status"), "On Leave") + def test_block_list(self): self._clear_roles() @@ -241,7 +322,13 @@ class TestLeaveApplication(unittest.TestCase): leave_period = get_leave_period() today = nowdate() holiday_list = 'Test Holiday List for Optional Holiday' - optional_leave_date = add_days(today, 7) + employee = get_employee() + + default_holiday_list = make_holiday_list() + frappe.db.set_value("Company", "_Test Company", "default_holiday_list", default_holiday_list) + first_sunday = get_first_sunday(default_holiday_list) + + optional_leave_date = add_days(first_sunday, 1) if not frappe.db.exists('Holiday List', holiday_list): frappe.get_doc(dict( @@ -253,7 +340,6 @@ class TestLeaveApplication(unittest.TestCase): dict(holiday_date = optional_leave_date, description = 'Test') ] )).insert() - employee = get_employee() frappe.db.set_value('Leave Period', leave_period.name, 'optional_holiday_list', holiday_list) leave_type = 'Test Optional Type' @@ -266,7 +352,7 @@ class TestLeaveApplication(unittest.TestCase): allocate_leaves(employee, leave_period, leave_type, 10) - date = add_days(today, 6) + date = add_days(first_sunday, 2) leave_application = frappe.get_doc(dict( doctype = 'Leave Application', @@ -637,13 +723,13 @@ def create_carry_forwarded_allocation(employee, leave_type): carry_forward=1) leave_allocation.submit() -def make_allocation_record(employee=None, leave_type=None): +def make_allocation_record(employee=None, leave_type=None, from_date=None, to_date=None): allocation = frappe.get_doc({ "doctype": "Leave Allocation", "employee": employee or "_T-Employee-00001", "leave_type": leave_type or "_Test Leave Type", - "from_date": "2013-01-01", - "to_date": "2019-12-31", + "from_date": from_date or "2013-01-01", + "to_date": to_date or "2019-12-31", "new_leaves_allocated": 30 }) @@ -692,3 +778,16 @@ def allocate_leaves(employee, leave_period, leave_type, new_leaves_allocated, el }).insert() allocate_leave.submit() + + +def get_first_sunday(holiday_list): + month_start_date = get_first_day(nowdate()) + month_end_date = get_last_day(nowdate()) + first_sunday = frappe.db.sql(""" + select holiday_date from `tabHoliday` + where parent = %s + and holiday_date between %s and %s + order by holiday_date + """, (holiday_list, month_start_date, month_end_date))[0][0] + + return first_sunday \ No newline at end of file diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py index c0e005ad99..bcf981b74d 100644 --- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py @@ -994,6 +994,8 @@ def make_leave_application(employee, from_date, to_date, leave_type, company=Non )) leave_application.submit() + return leave_application + def setup_test(): make_earning_salary_component(setup=True, company_list=["_Test Company"]) make_deduction_salary_component(setup=True, company_list=["_Test Company"]) From b72cdb4bcaf366b2a7261eca98d01419d01ef1af Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 21 Jan 2022 18:00:35 +0530 Subject: [PATCH 40/53] fix: Previous document currency getting overriden (cherry picked from commit ef782fd35b0717e3f7c50dbb6c5dde7c96ae9ef6) --- erpnext/accounts/party.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 6b4b43d30b..c13bc23c15 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -58,7 +58,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company= frappe.throw(_("Not permitted for {0}").format(party), frappe.PermissionError) party = frappe.get_doc(party_type, party) - currency = party.default_currency if party.get("default_currency") else get_company_currency(company) + currency = party.get("default_currency") or currency or get_company_currency(company) party_address, shipping_address = set_address_details(party_details, party, party_type, doctype, company, party_address, company_address, shipping_address) set_contact_details(party_details, party, party_type) From b8fbfed096a4e5f0e1ac97fd7a35a49b0a316b62 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 24 Jan 2022 21:45:51 +0530 Subject: [PATCH 41/53] fix: fetch "transfer material against" from BOM (#29435) --- erpnext/manufacturing/doctype/work_order/work_order.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json index 12cd58f418..9452a63d70 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.json +++ b/erpnext/manufacturing/doctype/work_order/work_order.json @@ -333,12 +333,13 @@ "options": "fa fa-wrench" }, { - "default": "Work Order", "depends_on": "operations", + "fetch_from": "bom_no.transfer_material_against", + "fetch_if_empty": 1, "fieldname": "transfer_material_against", "fieldtype": "Select", "label": "Transfer Material Against", - "options": "Work Order\nJob Card" + "options": "\nWork Order\nJob Card" }, { "fieldname": "operations", @@ -574,7 +575,7 @@ "image_field": "image", "is_submittable": 1, "links": [], - "modified": "2021-11-08 17:36:07.016300", + "modified": "2022-01-24 21:18:12.160114", "modified_by": "Administrator", "module": "Manufacturing", "name": "Work Order", @@ -607,6 +608,7 @@ ], "sort_field": "modified", "sort_order": "ASC", + "states": [], "title_field": "production_item", "track_changes": 1, "track_seen": 1 From f469ec87d94d4639ff4eb99a45496721c4779bf3 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 25 Jan 2022 11:14:08 +0530 Subject: [PATCH 42/53] fix: broken patches (backport #29067) (#29406) * chore: patch fixes (cherry picked from commit 8b5b146f6d2720587a16f78a8d47840be8dca2b7) # Conflicts: # erpnext/patches/v13_0/make_homepage_products_website_items.py * fix: remove desktop icons while deleting sales reports (cherry picked from commit 5f72026cb932d01fc827c382747e996a94b441fd) * refactor: dont ignore dangerous exceptions in patches (cherry picked from commit 0aa1ea8aeb7757592616bd491de98c69fef08854) * fix: make patch kinda idempotent with previous query rerunning would've caused all values to become 0. * chore: conflicts * fix: check type before patching Co-authored-by: Saurabh Co-authored-by: Ankush Menat --- .../v12_0/update_is_cancelled_field.py | 32 +++++++++++++------ .../patches/v13_0/delete_old_sales_reports.py | 7 ++++ ...fields_for_80g_certificate_and_donation.py | 3 ++ .../update_actual_start_and_end_date_in_wo.py | 2 +- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/erpnext/patches/v12_0/update_is_cancelled_field.py b/erpnext/patches/v12_0/update_is_cancelled_field.py index df7875079b..0401034874 100644 --- a/erpnext/patches/v12_0/update_is_cancelled_field.py +++ b/erpnext/patches/v12_0/update_is_cancelled_field.py @@ -2,14 +2,28 @@ import frappe def execute(): - try: - frappe.db.sql("UPDATE `tabStock Ledger Entry` SET is_cancelled = 0 where is_cancelled in ('', NULL, 'No')") - frappe.db.sql("UPDATE `tabSerial No` SET is_cancelled = 0 where is_cancelled in ('', NULL, 'No')") + #handle type casting for is_cancelled field + module_doctypes = ( + ('stock', 'Stock Ledger Entry'), + ('stock', 'Serial No'), + ('accounts', 'GL Entry') + ) - frappe.db.sql("UPDATE `tabStock Ledger Entry` SET is_cancelled = 1 where is_cancelled = 'Yes'") - frappe.db.sql("UPDATE `tabSerial No` SET is_cancelled = 1 where is_cancelled = 'Yes'") + for module, doctype in module_doctypes: + if (not frappe.db.has_column(doctype, "is_cancelled") + or frappe.db.get_column_type(doctype, "is_cancelled").lower() == "int(1)" + ): + continue - frappe.reload_doc("stock", "doctype", "stock_ledger_entry") - frappe.reload_doc("stock", "doctype", "serial_no") - except Exception: - pass + frappe.db.sql(""" + UPDATE `tab{doctype}` + SET is_cancelled = 0 + where is_cancelled in ('', NULL, 'No')""" + .format(doctype=doctype)) + frappe.db.sql(""" + UPDATE `tab{doctype}` + SET is_cancelled = 1 + where is_cancelled = 'Yes'""" + .format(doctype=doctype)) + + frappe.reload_doc(module, "doctype", frappe.scrub(doctype)) diff --git a/erpnext/patches/v13_0/delete_old_sales_reports.py b/erpnext/patches/v13_0/delete_old_sales_reports.py index c597fe8645..e6eba0a608 100644 --- a/erpnext/patches/v13_0/delete_old_sales_reports.py +++ b/erpnext/patches/v13_0/delete_old_sales_reports.py @@ -12,6 +12,7 @@ def execute(): for report in reports_to_delete: if frappe.db.exists("Report", report): + delete_links_from_desktop_icons(report) delete_auto_email_reports(report) check_and_delete_linked_reports(report) @@ -22,3 +23,9 @@ def delete_auto_email_reports(report): auto_email_reports = frappe.db.get_values("Auto Email Report", {"report": report}, ["name"]) for auto_email_report in auto_email_reports: frappe.delete_doc("Auto Email Report", auto_email_report[0]) + +def delete_links_from_desktop_icons(report): + """ Check for one or multiple Desktop Icons and delete """ + desktop_icons = frappe.db.get_values("Desktop Icon", {"_report": report}, ["name"]) + for desktop_icon in desktop_icons: + frappe.delete_doc("Desktop Icon", desktop_icon[0]) \ No newline at end of file diff --git a/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py b/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py index 7a2a253967..2d35ea3458 100644 --- a/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py +++ b/erpnext/patches/v13_0/setup_fields_for_80g_certificate_and_donation.py @@ -5,6 +5,9 @@ from erpnext.regional.india.setup import make_custom_fields def execute(): if frappe.get_all('Company', filters = {'country': 'India'}): + frappe.reload_doc('accounts', 'doctype', 'POS Invoice') + frappe.reload_doc('accounts', 'doctype', 'POS Invoice Item') + make_custom_fields() if not frappe.db.exists('Party Type', 'Donor'): diff --git a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py index 55fd465b20..60466eb86a 100644 --- a/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py +++ b/erpnext/patches/v13_0/update_actual_start_and_end_date_in_wo.py @@ -37,4 +37,4 @@ def execute(): jc.production_item = wo.production_item, jc.item_name = wo.item_name WHERE jc.work_order = wo.name and IFNULL(jc.production_item, "") = "" - """) + """) \ No newline at end of file From f5f3552abba2b8eb9ba57b4f9fd06ddc1c1b8a8c Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 24 Jan 2022 22:31:07 +0530 Subject: [PATCH 43/53] test: cover more reports in test --- erpnext/stock/report/test_reports.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/erpnext/stock/report/test_reports.py b/erpnext/stock/report/test_reports.py index 1dcf863a9d..525af40b41 100644 --- a/erpnext/stock/report/test_reports.py +++ b/erpnext/stock/report/test_reports.py @@ -1,6 +1,8 @@ import unittest from typing import List, Tuple +import frappe + from erpnext.tests.utils import ReportFilters, ReportName, execute_script_report DEFAULT_FILTERS = { @@ -10,8 +12,12 @@ DEFAULT_FILTERS = { } +batch = frappe.db.get_value("Batch", fieldname=["name"], as_dict=True, order_by="creation desc") + REPORT_FILTER_TEST_CASES: List[Tuple[ReportName, ReportFilters]] = [ ("Stock Ledger", {"_optional": True}), + ("Stock Ledger", {"batch_no": batch}), + ("Stock Ledger", {"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC"}), ("Stock Balance", {"_optional": True}), ("Stock Projected Qty", {"_optional": True}), ("Batch-Wise Balance History", {}), @@ -40,6 +46,13 @@ REPORT_FILTER_TEST_CASES: List[Tuple[ReportName, ReportFilters]] = [ ("Item Variant Details", {"item": "_Test Variant Item",}), ("Total Stock Summary", {"group_by": "warehouse",}), ("Batch Item Expiry Status", {}), + ("Incorrect Stock Value Report", {"company": "_Test Company with perpetual inventory"}), + ("Incorrect Serial No Valuation", {}), + ("Incorrect Balance Qty After Transaction", {}), + ("Supplier-Wise Sales Analytics", {}), + ("Item Prices", {"items": "Enabled Items only"}), + ("Delayed Item Report", {"based_on": "Sales Invoice"}), + ("Delayed Item Report", {"based_on": "Delivery Note"}), ("Stock Ageing", {"range1": 30, "range2": 60, "range3": 90, "_optional": True}), ("Stock Ledger Invariant Check", { From 7eab945d8cc207d531f9e850314922c6b4a2d6b7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 26 Jan 2022 12:40:21 +0530 Subject: [PATCH 44/53] refactor: move existing patches to post migration (#28940) Also remove duplicates :') --- erpnext/patches.txt | 23 ++++++++++--------- ...xit_questionnaire_notification_template.py | 3 --- .../patches/v14_0/rearrange_company_fields.py | 5 +--- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 83bab06b71..94ad2d6ac4 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -1,3 +1,4 @@ +[pre_model_sync] erpnext.patches.v12_0.update_is_cancelled_field erpnext.patches.v11_0.rename_production_order_to_work_order erpnext.patches.v11_0.refactor_naming_series @@ -226,7 +227,6 @@ erpnext.patches.v13_0.updates_for_multi_currency_payroll erpnext.patches.v13_0.update_reason_for_resignation_in_employee execute:frappe.delete_doc("Report", "Quoted Item Comparison") erpnext.patches.v13_0.update_member_email_address -erpnext.patches.v13_0.updates_for_multi_currency_payroll erpnext.patches.v13_0.create_leave_policy_assignment_based_on_employee_current_leave_policy erpnext.patches.v13_0.update_pos_closing_entry_in_merge_log erpnext.patches.v13_0.add_po_to_global_search @@ -266,7 +266,6 @@ erpnext.patches.v13_0.set_training_event_attendance erpnext.patches.v13_0.bill_for_rejected_quantity_in_purchase_invoice erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold erpnext.patches.v13_0.update_response_by_variance -erpnext.patches.v13_0.bill_for_rejected_quantity_in_purchase_invoice erpnext.patches.v13_0.update_job_card_details erpnext.patches.v13_0.update_level_in_bom #1234sswef erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry @@ -285,11 +284,9 @@ erpnext.patches.v13_0.reset_clearance_date_for_intracompany_payment_entries erpnext.patches.v13_0.einvoicing_deprecation_warning execute:frappe.reload_doc("erpnext_integrations", "doctype", "TaxJar Settings") execute:frappe.reload_doc("erpnext_integrations", "doctype", "Product Tax Category") -erpnext.patches.v14_0.delete_einvoicing_doctypes erpnext.patches.v13_0.custom_fields_for_taxjar_integration #08-11-2021 erpnext.patches.v13_0.set_operation_time_based_on_operating_cost erpnext.patches.v13_0.create_gst_payment_entry_fields #27-11-2021 -erpnext.patches.v14_0.delete_shopify_doctypes erpnext.patches.v13_0.fix_invoice_statuses erpnext.patches.v13_0.replace_supplier_item_group_with_party_specific_item erpnext.patches.v13_0.update_dates_in_tax_withholding_category @@ -312,24 +309,28 @@ erpnext.patches.v13_0.item_naming_series_not_mandatory erpnext.patches.v14_0.delete_healthcare_doctypes erpnext.patches.v13_0.update_category_in_ltds_certificate erpnext.patches.v13_0.create_pan_field_for_india #2 -erpnext.patches.v14_0.delete_hub_doctypes erpnext.patches.v13_0.update_maintenance_schedule_field_in_visit erpnext.patches.v13_0.create_ksa_vat_custom_fields # 07-01-2022 -erpnext.patches.v14_0.rename_ongoing_status_in_sla_documents erpnext.patches.v14_0.migrate_crm_settings erpnext.patches.v13_0.rename_ksa_qr_field erpnext.patches.v13_0.wipe_serial_no_field_for_0_qty erpnext.patches.v13_0.disable_ksa_print_format_for_others # 16-12-2021 -erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template erpnext.patches.v13_0.update_tax_category_for_rcm execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings') erpnext.patches.v14_0.set_payroll_cost_centers erpnext.patches.v13_0.agriculture_deprecation_warning -erpnext.patches.v14_0.delete_agriculture_doctypes erpnext.patches.v13_0.hospitality_deprecation_warning -erpnext.patches.v14_0.delete_hospitality_doctypes # 20-01-2022 erpnext.patches.v13_0.update_exchange_rate_settings -erpnext.patches.v14_0.rearrange_company_fields -erpnext.patches.v14_0.update_leave_notification_template erpnext.patches.v13_0.update_asset_quantity_field erpnext.patches.v13_0.delete_bank_reconciliation_detail + +[post_model_sync] +erpnext.patches.v14_0.rename_ongoing_status_in_sla_documents +erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template +erpnext.patches.v14_0.delete_einvoicing_doctypes +erpnext.patches.v14_0.delete_shopify_doctypes +erpnext.patches.v14_0.delete_hub_doctypes +erpnext.patches.v14_0.delete_hospitality_doctypes # 20-01-2022 +erpnext.patches.v14_0.delete_agriculture_doctypes +erpnext.patches.v14_0.rearrange_company_fields +erpnext.patches.v14_0.update_leave_notification_template diff --git a/erpnext/patches/v14_0/add_default_exit_questionnaire_notification_template.py b/erpnext/patches/v14_0/add_default_exit_questionnaire_notification_template.py index 120182a80e..2a8b6ef746 100644 --- a/erpnext/patches/v14_0/add_default_exit_questionnaire_notification_template.py +++ b/erpnext/patches/v14_0/add_default_exit_questionnaire_notification_template.py @@ -5,9 +5,6 @@ from frappe import _ def execute(): - frappe.reload_doc("email", "doctype", "email_template") - frappe.reload_doc("hr", "doctype", "hr_settings") - template = frappe.db.exists("Email Template", _("Exit Questionnaire Notification")) if not template: base_path = frappe.get_app_path("erpnext", "hr", "doctype") diff --git a/erpnext/patches/v14_0/rearrange_company_fields.py b/erpnext/patches/v14_0/rearrange_company_fields.py index dd953ffb0f..fd7eb7f750 100644 --- a/erpnext/patches/v14_0/rearrange_company_fields.py +++ b/erpnext/patches/v14_0/rearrange_company_fields.py @@ -1,10 +1,7 @@ -import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields def execute(): - frappe.reload_doc('setup', 'doctype', 'company') - custom_fields = { 'Company': [ dict(fieldname='hra_section', label='HRA Settings', @@ -28,4 +25,4 @@ def execute(): ] } - create_custom_fields(custom_fields, update=True) \ No newline at end of file + create_custom_fields(custom_fields, update=True) From 6c1c85be0c7318692dc3544b4be644b45c31143a Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 27 Jan 2022 00:51:29 +0530 Subject: [PATCH 45/53] feat: additional doctypes access for ESS user (#29317) --- erpnext/patches.txt | 2 +- .../v13_0/make_non_standard_user_type.py | 11 +++++++-- erpnext/setup/install.py | 24 ++++++++++++++++--- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 94ad2d6ac4..9f7e733af4 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -252,7 +252,7 @@ erpnext.patches.v12_0.add_gst_category_in_delivery_note erpnext.patches.v12_0.purchase_receipt_status erpnext.patches.v13_0.fix_non_unique_represents_company erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing -erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021 +erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021 #17-01-2022 erpnext.patches.v13_0.update_shipment_status erpnext.patches.v13_0.remove_attribute_field_from_item_variant_setting erpnext.patches.v13_0.germany_make_custom_fields diff --git a/erpnext/patches/v13_0/make_non_standard_user_type.py b/erpnext/patches/v13_0/make_non_standard_user_type.py index a7bdf93332..ff241a3fd9 100644 --- a/erpnext/patches/v13_0/make_non_standard_user_type.py +++ b/erpnext/patches/v13_0/make_non_standard_user_type.py @@ -10,8 +10,15 @@ from erpnext.setup.install import add_non_standard_user_types def execute(): doctype_dict = { 'projects': ['Timesheet'], - 'payroll': ['Salary Slip', 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission'], - 'hr': ['Employee', 'Expense Claim', 'Leave Application', 'Attendance Request', 'Compensatory Leave Request'] + 'payroll': [ + 'Salary Slip', 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission', + 'Employee Benefit Application', 'Employee Benefit Claim' + ], + 'hr': [ + 'Employee', 'Expense Claim', 'Leave Application', 'Attendance Request', 'Compensatory Leave Request', + 'Holiday List', 'Employee Advance', 'Training Program', 'Training Feedback', + 'Shift Request', 'Employee Grievance', 'Employee Referral', 'Travel Request' + ] } for module, doctypes in doctype_dict.items(): diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index bafaab814b..1d7bad2686 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -189,7 +189,7 @@ def add_non_standard_user_types(): user_type_limit = {} for user_type, data in user_types.items(): - user_type_limit.setdefault(frappe.scrub(user_type), 10) + user_type_limit.setdefault(frappe.scrub(user_type), 20) update_site_config('user_type_doctype_limit', user_type_limit) @@ -204,15 +204,33 @@ def get_user_types_data(): 'apply_user_permission_on': 'Employee', 'user_id_field': 'user_id', 'doctypes': { - 'Salary Slip': ['read'], + # masters + 'Holiday List': ['read'], 'Employee': ['read', 'write'], + # payroll + 'Salary Slip': ['read'], + 'Employee Benefit Application': ['read', 'write', 'create', 'delete'], + # expenses 'Expense Claim': ['read', 'write', 'create', 'delete'], + 'Employee Advance': ['read', 'write', 'create', 'delete'], + # leave and attendance 'Leave Application': ['read', 'write', 'create', 'delete'], 'Attendance Request': ['read', 'write', 'create', 'delete'], 'Compensatory Leave Request': ['read', 'write', 'create', 'delete'], + # tax 'Employee Tax Exemption Declaration': ['read', 'write', 'create', 'delete'], 'Employee Tax Exemption Proof Submission': ['read', 'write', 'create', 'delete'], - 'Timesheet': ['read', 'write', 'create', 'delete', 'submit', 'cancel', 'amend'] + # projects + 'Timesheet': ['read', 'write', 'create', 'delete', 'submit', 'cancel', 'amend'], + # trainings + 'Training Program': ['read'], + 'Training Feedback': ['read', 'write', 'create', 'delete', 'submit', 'cancel', 'amend'], + # shifts + 'Shift Request': ['read', 'write', 'create', 'delete', 'submit', 'cancel', 'amend'], + # misc + 'Employee Grievance': ['read', 'write', 'create', 'delete'], + 'Employee Referral': ['read', 'write', 'create', 'delete'], + 'Travel Request': ['read', 'write', 'create', 'delete'] } } } From 29c7947db05106cb87a0dfe0905dc3abc8c63cd4 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 27 Jan 2022 11:11:37 +0530 Subject: [PATCH 46/53] fix: Further sort sales_order_analysis to get consistent response Since the data was sorted by `transaction_date`, report sorting order used to be inconsistent everytime if there were lots of records with same transaction date. This used to create problems while exporting report as "Excel" with filters. --- .../selling/report/sales_order_analysis/sales_order_analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py index b2bf5464b5..3e22d0fa8c 100644 --- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py +++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py @@ -85,7 +85,7 @@ def get_data(conditions, filters): and so.docstatus = 1 {conditions} GROUP BY soi.name - ORDER BY so.transaction_date ASC + ORDER BY so.transaction_date ASC, soi.item_code ASC """.format(conditions=conditions), filters, as_dict=1) return data From b75b00fefccdfe960605f8ad5328f83687d6feea Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Thu, 27 Jan 2022 12:44:01 +0530 Subject: [PATCH 47/53] feat: provision to exclude exploded items in the BOM (#29450) --- erpnext/manufacturing/doctype/bom/bom.js | 12 ++++++++++-- erpnext/manufacturing/doctype/bom/bom.py | 11 ++++++++++- erpnext/manufacturing/doctype/bom/test_bom.py | 17 +++++++++++++++++ .../doctype/bom_item/bom_item.json | 13 +++++++++++-- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index 6d35d65bea..fc3b971bcb 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -331,7 +331,7 @@ frappe.ui.form.on("BOM", { }); }); - if (has_template_rm) { + if (has_template_rm && has_template_rm.length) { dialog.fields_dict.items.grid.refresh(); } }, @@ -467,7 +467,8 @@ var get_bom_material_detail = function(doc, cdt, cdn, scrap_items) { "uom": d.uom, "stock_uom": d.stock_uom, "conversion_factor": d.conversion_factor, - "sourced_by_supplier": d.sourced_by_supplier + "sourced_by_supplier": d.sourced_by_supplier, + "do_not_explode": d.do_not_explode }, callback: function(r) { d = locals[cdt][cdn]; @@ -640,6 +641,13 @@ frappe.ui.form.on("BOM Operation", "workstation", function(frm, cdt, cdn) { }); }); +frappe.ui.form.on("BOM Item", { + do_not_explode: function(frm, cdt, cdn) { + get_bom_material_detail(frm.doc, cdt, cdn, false); + } +}) + + frappe.ui.form.on("BOM Item", "qty", function(frm, cdt, cdn) { var d = locals[cdt][cdn]; d.stock_qty = d.qty * d.conversion_factor; diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 5a60fb751d..d953697e2e 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -203,6 +203,10 @@ class BOM(WebsiteGenerator): for item in self.get("items"): self.validate_bom_currency(item) + item.bom_no = '' + if not item.do_not_explode: + item.bom_no = item.bom_no + ret = self.get_bom_material_detail({ "company": self.company, "item_code": item.item_code, @@ -214,8 +218,10 @@ class BOM(WebsiteGenerator): "uom": item.uom, "stock_uom": item.stock_uom, "conversion_factor": item.conversion_factor, - "sourced_by_supplier": item.sourced_by_supplier + "sourced_by_supplier": item.sourced_by_supplier, + "do_not_explode": item.do_not_explode }) + for r in ret: if not item.get(r): item.set(r, ret[r]) @@ -267,6 +273,9 @@ class BOM(WebsiteGenerator): 'sourced_by_supplier' : args.get('sourced_by_supplier', 0) } + if args.get('do_not_explode'): + ret_item['bom_no'] = '' + return ret_item def validate_bom_currency(self, item): diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index 178d92c26c..7d90933dbc 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -385,6 +385,23 @@ class TestBOM(ERPNextTestCase): self.assertNotEqual(len(test_items), len(filtered), msg="Item filtering showing excessive results") self.assertTrue(0 < len(filtered) <= 3, msg="Item filtering showing excessive results") + def test_exclude_exploded_items_from_bom(self): + bom_no = get_default_bom() + new_bom = frappe.copy_doc(frappe.get_doc('BOM', bom_no)) + for row in new_bom.items: + if row.item_code == '_Test Item Home Desktop Manufactured': + self.assertTrue(row.bom_no) + row.do_not_explode = True + + new_bom.docstatus = 0 + new_bom.save() + new_bom.load_from_db() + + for row in new_bom.items: + if row.item_code == '_Test Item Home Desktop Manufactured' and row.do_not_explode: + self.assertFalse(row.bom_no) + + new_bom.delete() def get_default_bom(item_code="_Test FG Item 2"): return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1}) diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json index 4c9877f52b..3406215cbb 100644 --- a/erpnext/manufacturing/doctype/bom_item/bom_item.json +++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json @@ -10,6 +10,7 @@ "item_name", "operation", "column_break_3", + "do_not_explode", "bom_no", "source_warehouse", "allow_alternative_item", @@ -73,6 +74,7 @@ "fieldtype": "Column Break" }, { + "depends_on": "eval:!doc.do_not_explode", "fieldname": "bom_no", "fieldtype": "Link", "in_filter": 1, @@ -284,18 +286,25 @@ "fieldname": "sourced_by_supplier", "fieldtype": "Check", "label": "Sourced by Supplier" + }, + { + "default": "0", + "fieldname": "do_not_explode", + "fieldtype": "Check", + "label": "Do Not Explode" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2020-10-08 14:19:37.563300", + "modified": "2022-01-24 16:57:57.020232", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Item", "owner": "Administrator", "permissions": [], "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [] } \ No newline at end of file From b05287dea06f7f8a769268148d346d6dd4dd4796 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 27 Jan 2022 20:08:05 +0530 Subject: [PATCH 48/53] fix: drop `six` code (#29479) --- erpnext/accounts/doctype/bank_transaction/bank_transaction.py | 3 ++- .../accounts_receivable_summary/accounts_receivable_summary.py | 3 +-- erpnext/crm/doctype/linkedin_settings/linkedin_settings.py | 3 ++- .../doctype/amazon_mws_settings/amazon_methods.py | 2 +- .../doctype/gocardless_settings/gocardless_settings.py | 3 ++- .../doctype/woocommerce_settings/woocommerce_settings.py | 3 ++- erpnext/erpnext_integrations/utils.py | 2 +- erpnext/regional/germany/utils/datev/datev_csv.py | 2 +- erpnext/regional/report/datev/test_datev.py | 2 +- erpnext/setup/doctype/item_group/item_group.py | 2 +- 10 files changed, 14 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py index 44cea31ed3..51e1d6e9a0 100644 --- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py +++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py @@ -2,9 +2,10 @@ # For license information, please see license.txt +from functools import reduce + import frappe from frappe.utils import flt -from six.moves import reduce from erpnext.controllers.status_updater import StatusUpdater diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py index 4559fa94a4..8e3bd8be1b 100644 --- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py +++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py @@ -5,7 +5,6 @@ import frappe from frappe import _, scrub from frappe.utils import cint, flt -from six import iteritems from erpnext.accounts.party import get_partywise_advanced_payment_amount from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport @@ -40,7 +39,7 @@ class AccountsReceivableSummary(ReceivablePayableReport): if self.filters.show_gl_balance: gl_balance_map = get_gl_balance(self.filters.report_date) - for party, party_dict in iteritems(self.party_total): + for party, party_dict in self.party_total.items(): if party_dict.outstanding == 0: continue diff --git a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py index 8fd4978715..d2ac10adea 100644 --- a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py +++ b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py @@ -2,13 +2,14 @@ # For license information, please see license.txt +from urllib.parse import urlencode + import frappe import requests from frappe import _ from frappe.model.document import Document from frappe.utils import get_url_to_form from frappe.utils.file_manager import get_file_path -from six.moves.urllib.parse import urlencode class LinkedInSettings(Document): diff --git a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py index 66826ba8d7..03c1a1a0b5 100644 --- a/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py +++ b/erpnext/erpnext_integrations/doctype/amazon_mws_settings/amazon_methods.py @@ -5,11 +5,11 @@ import csv import math import time +from io import StringIO import dateutil import frappe from frappe import _ -from six import StringIO import erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_api as mws diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py index e242ace60f..a8119ac86c 100644 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py +++ b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py @@ -2,13 +2,14 @@ # For license information, please see license.txt +from urllib.parse import urlencode + import frappe import gocardless_pro from frappe import _ from frappe.integrations.utils import create_payment_gateway, create_request_log from frappe.model.document import Document from frappe.utils import call_hook_method, cint, flt, get_url -from six.moves.urllib.parse import urlencode class GoCardlessSettings(Document): diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py index 8da52f49f1..309d2cb0e3 100644 --- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py +++ b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py @@ -2,12 +2,13 @@ # For license information, please see license.txt +from urllib.parse import urlparse + import frappe from frappe import _ from frappe.custom.doctype.custom_field.custom_field import create_custom_field from frappe.model.document import Document from frappe.utils.nestedset import get_root_of -from six.moves.urllib.parse import urlparse class WoocommerceSettings(Document): diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py index d922d875fd..30d3948fee 100644 --- a/erpnext/erpnext_integrations/utils.py +++ b/erpnext/erpnext_integrations/utils.py @@ -1,10 +1,10 @@ import base64 import hashlib import hmac +from urllib.parse import urlparse import frappe from frappe import _ -from six.moves.urllib.parse import urlparse from erpnext import get_default_company diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py index 2d1e02eadb..ec271a1029 100644 --- a/erpnext/regional/germany/utils/datev/datev_csv.py +++ b/erpnext/regional/germany/utils/datev/datev_csv.py @@ -1,11 +1,11 @@ import datetime import zipfile from csv import QUOTE_NONNUMERIC +from io import BytesIO import frappe import pandas as pd from frappe import _ -from six import BytesIO from .datev_constants import DataCategory diff --git a/erpnext/regional/report/datev/test_datev.py b/erpnext/regional/report/datev/test_datev.py index 14d5495eed..052fb2a724 100644 --- a/erpnext/regional/report/datev/test_datev.py +++ b/erpnext/regional/report/datev/test_datev.py @@ -1,9 +1,9 @@ import zipfile +from io import BytesIO from unittest import TestCase import frappe from frappe.utils import cstr, now_datetime, today -from six import BytesIO from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.regional.germany.utils.datev.datev_constants import ( diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py index c94b3463fc..9f1eb753d9 100644 --- a/erpnext/setup/doctype/item_group/item_group.py +++ b/erpnext/setup/doctype/item_group/item_group.py @@ -3,6 +3,7 @@ import copy +from urllib.parse import quote import frappe from frappe import _ @@ -10,7 +11,6 @@ from frappe.utils import cint, cstr, nowdate from frappe.utils.nestedset import NestedSet from frappe.website.utils import clear_cache from frappe.website.website_generator import WebsiteGenerator -from six.moves.urllib.parse import quote from erpnext.shopping_cart.filters import ProductFiltersBuilder from erpnext.shopping_cart.product_info import set_product_info_for_website From 0dafa8a12a0c0745bbabceb457332075fd6db9f9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 27 Jan 2022 20:23:24 +0530 Subject: [PATCH 49/53] fix: stock ledger rendering glitch undefined Issue (cherry picked from commit f38004219518e901eb736780b181c19fe88ce823) Co-authored-by: smehata <53169014+smehata@users.noreply.github.com> --- erpnext/stock/report/stock_ledger/stock_ledger.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.js b/erpnext/stock/report/stock_ledger/stock_ledger.js index fe2417bba7..ef7c2cc7d9 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.js +++ b/erpnext/stock/report/stock_ledger/stock_ledger.js @@ -86,10 +86,10 @@ frappe.query_reports["Stock Ledger"] = { ], "formatter": function (value, row, column, data, default_formatter) { value = default_formatter(value, row, column, data); - if (column.fieldname == "out_qty" && data.out_qty < 0) { + if (column.fieldname == "out_qty" && data && data.out_qty < 0) { value = "" + value + ""; } - else if (column.fieldname == "in_qty" && data.in_qty > 0) { + else if (column.fieldname == "in_qty" && data && data.in_qty > 0) { value = "" + value + ""; } From 251576a6bb38c9b0f0793330e10e256fe7898e5c Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 28 Jan 2022 13:17:43 +0530 Subject: [PATCH 50/53] chore: disable annoying flake8 formatting for QB (#29488) [skip ci] --- .flake8 | 1 + 1 file changed, 1 insertion(+) diff --git a/.flake8 b/.flake8 index 56c9b9a369..5735456ae7 100644 --- a/.flake8 +++ b/.flake8 @@ -28,6 +28,7 @@ ignore = B007, B950, W191, + E124, # closing bracket, irritating while writing QB code max-line-length = 200 exclude=.github/helper/semgrep_rules From 86efa0dbfd45f21d72d047ef77ca0cb8ae2b8d94 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 28 Jan 2022 11:59:18 +0530 Subject: [PATCH 51/53] fix: ensure correct-ish transfer against --- erpnext/manufacturing/doctype/bom/bom.py | 7 +++++ erpnext/manufacturing/doctype/bom/test_bom.py | 29 +++++++++++++++++++ .../doctype/work_order/work_order.py | 12 ++++++++ 3 files changed, 48 insertions(+) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index d953697e2e..045e5bc95a 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -149,6 +149,7 @@ class BOM(WebsiteGenerator): self.set_bom_material_details() self.set_bom_scrap_items_detail() self.validate_materials() + self.validate_transfer_against() self.set_routing_operations() self.validate_operations() self.calculate_cost() @@ -690,6 +691,12 @@ class BOM(WebsiteGenerator): if act_pbom and act_pbom[0][0]: frappe.throw(_("Cannot deactivate or cancel BOM as it is linked with other BOMs")) + def validate_transfer_against(self): + if not self.with_operations: + self.transfer_material_against = "Work Order" + if not self.transfer_material_against and not self.is_new(): + frappe.throw(_("Setting {} is required").format(self.meta.get_label("transfer_material_against")), title=_("Missing value")) + def set_routing_operations(self): if self.routing and self.with_operations and not self.operations: self.get_routing() diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index 7d90933dbc..c77a0dd232 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -403,6 +403,35 @@ class TestBOM(ERPNextTestCase): new_bom.delete() + def test_valid_transfer_defaults(self): + bom_with_op = frappe.db.get_value("BOM", {"item": "_Test FG Item 2", "with_operations": 1, "is_active": 1}) + bom = frappe.copy_doc(frappe.get_doc("BOM", bom_with_op), ignore_no_copy=False) + + # test defaults + bom.docstatus = 0 + bom.transfer_material_against = None + bom.insert() + self.assertEqual(bom.transfer_material_against, "Work Order") + + bom.reload() + bom.transfer_material_against = None + with self.assertRaises(frappe.ValidationError): + bom.save() + bom.reload() + + # test saner default + bom.transfer_material_against = "Job Card" + bom.with_operations = 0 + bom.save() + self.assertEqual(bom.transfer_material_against, "Work Order") + + # test no value on existing doc + bom.transfer_material_against = None + bom.with_operations = 0 + bom.save() + self.assertEqual(bom.transfer_material_against, "Work Order") + + def get_default_bom(item_code="_Test FG Item 2"): return frappe.db.get_value("BOM", {"item": item_code, "is_active": 1, "is_default": 1}) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index 170454c823..93ca805e34 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -65,6 +65,7 @@ class WorkOrder(Document): self.validate_warehouse_belongs_to_company() self.calculate_operating_cost() self.validate_qty() + self.validate_transfer_against() self.validate_operation_time() self.status = self.get_status() @@ -72,6 +73,7 @@ class WorkOrder(Document): self.set_required_items(reset_only_qty = len(self.get("required_items"))) + def validate_sales_order(self): if self.sales_order: self.check_sales_order_on_hold_or_close() @@ -625,6 +627,16 @@ class WorkOrder(Document): if not self.qty > 0: frappe.throw(_("Quantity to Manufacture must be greater than 0.")) + def validate_transfer_against(self): + if not self.docstatus == 1: + # let user configure operations until they're ready to submit + return + if not self.operations: + self.transfer_material_against = "Work Order" + if not self.transfer_material_against: + frappe.throw(_("Setting {} is required").format(self.meta.get_label("transfer_material_against")), title=_("Missing value")) + + def validate_operation_time(self): for d in self.operations: if not d.time_in_mins > 0: From e4c220053f9732255a1af2361b0419230ade8ae6 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 28 Jan 2022 13:00:15 +0530 Subject: [PATCH 52/53] fix(patch): update BOMs to have correct transfer_material_against --- erpnext/patches.txt | 1 + erpnext/patches/v13_0/update_sane_transfer_against.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 erpnext/patches/v13_0/update_sane_transfer_against.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 9f7e733af4..ad5062fc0e 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -334,3 +334,4 @@ erpnext.patches.v14_0.delete_hospitality_doctypes # 20-01-2022 erpnext.patches.v14_0.delete_agriculture_doctypes erpnext.patches.v14_0.rearrange_company_fields erpnext.patches.v14_0.update_leave_notification_template +erpnext.patches.v13_0.update_sane_transfer_against diff --git a/erpnext/patches/v13_0/update_sane_transfer_against.py b/erpnext/patches/v13_0/update_sane_transfer_against.py new file mode 100644 index 0000000000..a163d38584 --- /dev/null +++ b/erpnext/patches/v13_0/update_sane_transfer_against.py @@ -0,0 +1,11 @@ +import frappe + + +def execute(): + bom = frappe.qb.DocType("BOM") + + (frappe.qb + .update(bom) + .set(bom.transfer_material_against, "Work Order") + .where(bom.with_operations == 0) + ).run() From 28994c0e7653f30025e90b84674a15e7434a0c52 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 28 Jan 2022 13:50:57 +0530 Subject: [PATCH 53/53] test: delete data after running test --- erpnext/manufacturing/doctype/bom/test_bom.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py index c77a0dd232..53437c8012 100644 --- a/erpnext/manufacturing/doctype/bom/test_bom.py +++ b/erpnext/manufacturing/doctype/bom/test_bom.py @@ -430,6 +430,7 @@ class TestBOM(ERPNextTestCase): bom.with_operations = 0 bom.save() self.assertEqual(bom.transfer_material_against, "Work Order") + bom.delete() def get_default_bom(item_code="_Test FG Item 2"):