From c5bd55f1cc0057fac8d13f07529eddceb21ebab8 Mon Sep 17 00:00:00 2001 From: smusaliy Date: Sun, 19 Jan 2025 21:18:18 +0300 Subject: [PATCH 01/22] fix in inn room card owner if today is none --- .../doctype/inn_room_booking/inn_room_card_owner_webcard.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py b/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py index 9b52e6db..174f3c72 100644 --- a/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py +++ b/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py @@ -234,7 +234,7 @@ def calculate_total_rate_and_sold(start_date, end_date): and transaction_type in {transaction_type} ''' total = frappe.db.sql(transaction_query, as_dict=1)[0] - if total.total == None: + if total.total is None: total.total = 0 count_query = f''' @@ -254,6 +254,8 @@ def calculate_total_rate_and_sold(start_date, end_date): ''' today = frappe.db.sql(today_query, as_dict=1) today = today[0] + if today.total is None: + today.total = 0 total.total += today.total count.count += today.count From a3167d5553acca9bcf894a68a1ec57123b23a26b Mon Sep 17 00:00:00 2001 From: smusaliy Date: Mon, 20 Jan 2025 08:55:17 +0300 Subject: [PATCH 02/22] add doctype inn folio transaction type seting and inn role and inn setting tools is chaild table in inn hotels setting --- .../__init__.py | 0 .../inn_folio_transaction_type_setting.json | 67 +++++++++++++++++++ .../inn_folio_transaction_type_setting.py | 9 +++ .../inn_hotels_setting.json | 30 ++++++++- inn/inn_hotels/doctype/inn_role/__init__.py | 0 inn/inn_hotels/doctype/inn_role/inn_role.json | 30 +++++++++ inn/inn_hotels/doctype/inn_role/inn_role.py | 9 +++ .../doctype/inn_setting_tools/__init__.py | 0 .../inn_setting_tools/inn_setting_tools.json | 36 ++++++++++ .../inn_setting_tools/inn_setting_tools.py | 9 +++ 10 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 inn/inn_hotels/doctype/inn_folio_transaction_type_setting/__init__.py create mode 100644 inn/inn_hotels/doctype/inn_folio_transaction_type_setting/inn_folio_transaction_type_setting.json create mode 100644 inn/inn_hotels/doctype/inn_folio_transaction_type_setting/inn_folio_transaction_type_setting.py create mode 100644 inn/inn_hotels/doctype/inn_role/__init__.py create mode 100644 inn/inn_hotels/doctype/inn_role/inn_role.json create mode 100644 inn/inn_hotels/doctype/inn_role/inn_role.py create mode 100644 inn/inn_hotels/doctype/inn_setting_tools/__init__.py create mode 100644 inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.json create mode 100644 inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.py diff --git a/inn/inn_hotels/doctype/inn_folio_transaction_type_setting/__init__.py b/inn/inn_hotels/doctype/inn_folio_transaction_type_setting/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/inn/inn_hotels/doctype/inn_folio_transaction_type_setting/inn_folio_transaction_type_setting.json b/inn/inn_hotels/doctype/inn_folio_transaction_type_setting/inn_folio_transaction_type_setting.json new file mode 100644 index 00000000..67dd1e0d --- /dev/null +++ b/inn/inn_hotels/doctype/inn_folio_transaction_type_setting/inn_folio_transaction_type_setting.json @@ -0,0 +1,67 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2025-01-19 21:48:27.587825", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "name1", + "type", + "module", + "included_in_dropdown", + "debit_account", + "credit_account" + ], + "fields": [ + { + "fieldname": "name1", + "fieldtype": "Data", + "label": "Name" + }, + { + "fieldname": "type", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Type", + "options": "Debit\nCredit", + "reqd": 1 + }, + { + "fieldname": "module", + "fieldtype": "Select", + "label": "Module ", + "options": "0\n1\n2\n3" + }, + { + "default": "0", + "fieldname": "included_in_dropdown", + "fieldtype": "Check", + "label": "Included in Dropdown?" + }, + { + "fieldname": "debit_account", + "fieldtype": "Link", + "label": "Debit Account", + "options": "Account" + }, + { + "fieldname": "credit_account", + "fieldtype": "Link", + "label": "Credit Account", + "options": "Account" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2025-01-20 07:50:13.955619", + "modified_by": "Administrator", + "module": "Inn Hotels", + "name": "Inn Folio Transaction Type Setting", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/inn/inn_hotels/doctype/inn_folio_transaction_type_setting/inn_folio_transaction_type_setting.py b/inn/inn_hotels/doctype/inn_folio_transaction_type_setting/inn_folio_transaction_type_setting.py new file mode 100644 index 00000000..dea33aa3 --- /dev/null +++ b/inn/inn_hotels/doctype/inn_folio_transaction_type_setting/inn_folio_transaction_type_setting.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Core Initiative and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class InnFolioTransactionTypeSetting(Document): + pass diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index 81a21450..b434faa8 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -62,11 +62,15 @@ "pos_receipt_remarks", "master_data_generator_sb", "bed_type_generator", + "bed_type", "room_type_generator", + "room_type", "role_generator", + "role", "cb4", "inn_hotels_account_generator", "folio_transaction_type_generator", + "folio_transaction_type", "supervisor_passcode" ], "fields": [ @@ -434,11 +438,35 @@ "fieldname": "maximum_payment_exclude", "fieldtype": "Currency", "label": "Maximum Payment Exclude" + }, + { + "fieldname": "bed_type", + "fieldtype": "Table", + "label": "Bed Type", + "options": "Inn Setting Tools" + }, + { + "fieldname": "room_type", + "fieldtype": "Table", + "label": "Room Type", + "options": "Inn Setting Tools" + }, + { + "fieldname": "role", + "fieldtype": "Table", + "label": "Role", + "options": "Inn Role" + }, + { + "fieldname": "folio_transaction_type", + "fieldtype": "Table", + "label": "Folio Transaction Type", + "options": "Inn Folio Transaction Type Setting" } ], "issingle": 1, "links": [], - "modified": "2024-08-13 14:06:36.577463", + "modified": "2025-01-20 07:51:20.331534", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_role/__init__.py b/inn/inn_hotels/doctype/inn_role/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/inn/inn_hotels/doctype/inn_role/inn_role.json b/inn/inn_hotels/doctype/inn_role/inn_role.json new file mode 100644 index 00000000..621385da --- /dev/null +++ b/inn/inn_hotels/doctype/inn_role/inn_role.json @@ -0,0 +1,30 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2025-01-19 21:42:38.406097", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "name1" + ], + "fields": [ + { + "fieldname": "name1", + "fieldtype": "Data", + "label": "Name" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2025-01-19 21:42:58.377713", + "modified_by": "Administrator", + "module": "Inn Hotels", + "name": "Inn Role", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/inn/inn_hotels/doctype/inn_role/inn_role.py b/inn/inn_hotels/doctype/inn_role/inn_role.py new file mode 100644 index 00000000..e3d22091 --- /dev/null +++ b/inn/inn_hotels/doctype/inn_role/inn_role.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Core Initiative and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class InnRole(Document): + pass diff --git a/inn/inn_hotels/doctype/inn_setting_tools/__init__.py b/inn/inn_hotels/doctype/inn_setting_tools/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.json b/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.json new file mode 100644 index 00000000..aee04907 --- /dev/null +++ b/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.json @@ -0,0 +1,36 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2025-01-19 21:31:50.073235", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "name1", + "description" + ], + "fields": [ + { + "fieldname": "name1", + "fieldtype": "Data", + "label": "Name" + }, + { + "fieldname": "description", + "fieldtype": "Data", + "label": "Description" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2025-01-19 21:32:25.445876", + "modified_by": "Administrator", + "module": "Inn Hotels", + "name": "Inn Setting Tools", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.py b/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.py new file mode 100644 index 00000000..98538730 --- /dev/null +++ b/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Core Initiative and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class InnSettingTools(Document): + pass From 315dd191a32732ff38aca3eeb0bf0e25ed72f164 Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Tue, 21 Jan 2025 12:39:07 +0300 Subject: [PATCH 03/22] (edit)in inn hotels setting and (add) doctype child table inn account setting --- inn/__init__.py | 2 +- .../doctype/inn_account_setting/__init__.py | 0 .../inn_account_setting.json | 70 ++++ .../inn_account_setting.py | 9 + .../inn_hotels_setting/inn_hotels_setting.js | 151 +++++--- .../inn_hotels_setting.json | 9 +- .../inn_hotels_setting/inn_hotels_setting.py | 332 ++++++++++++------ .../inn_setting_tools/inn_setting_tools.json | 4 +- 8 files changed, 431 insertions(+), 146 deletions(-) create mode 100644 inn/inn_hotels/doctype/inn_account_setting/__init__.py create mode 100644 inn/inn_hotels/doctype/inn_account_setting/inn_account_setting.json create mode 100644 inn/inn_hotels/doctype/inn_account_setting/inn_account_setting.py diff --git a/inn/__init__.py b/inn/__init__.py index 635d0fc2..6af7381a 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = '1.1.26' +__version__ = '1.0.0' diff --git a/inn/inn_hotels/doctype/inn_account_setting/__init__.py b/inn/inn_hotels/doctype/inn_account_setting/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/inn/inn_hotels/doctype/inn_account_setting/inn_account_setting.json b/inn/inn_hotels/doctype/inn_account_setting/inn_account_setting.json new file mode 100644 index 00000000..9c4851ee --- /dev/null +++ b/inn/inn_hotels/doctype/inn_account_setting/inn_account_setting.json @@ -0,0 +1,70 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2025-01-21 10:18:10.048150", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "account_name", + "parent_number", + "account_number", + "is_group", + "account_currency", + "account_type", + "root_type" + ], + "fields": [ + { + "fieldname": "account_name", + "fieldtype": "Data", + "label": "Account Name" + }, + { + "fieldname": "account_number", + "fieldtype": "Data", + "label": "Account Number" + }, + { + "default": "0", + "fieldname": "is_group", + "fieldtype": "Check", + "label": "Is Group" + }, + { + "fieldname": "account_type", + "fieldtype": "Select", + "label": "Account Type", + "options": "\nAccumulated Depreciation\nAsset Received But Not Billed\nBank\nCash\nChargeable\nCapital Work in Progress\nCost of Goods Sold\nCurrent Asset\nCurrent Liability\nDepreciation\nDirect Expense\nDirect Income\nEquity\nExpense Account\nExpenses Included In Asset Valuation\nExpenses Included In Valuation\nFixed Asset\nIncome Account\nIndirect Expense\nIndirect Income\nLiability\nPayable\nReceivable\nRound Off\nRound Off for Opening\nStock\nStock Adjustment\nStock Received But Not Billed\nService Received But Not Billed\nTax\nTemporary" + }, + { + "fieldname": "root_type", + "fieldtype": "Select", + "label": "Root Type", + "options": "\nAsset\nLiability\nIncome\nExpense\nEquity" + }, + { + "fieldname": "parent_number", + "fieldtype": "Data", + "label": "Parent Number" + }, + { + "fieldname": "account_currency", + "fieldtype": "Link", + "label": "Currency", + "options": "Currency" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2025-01-21 11:02:48.635981", + "modified_by": "Administrator", + "module": "Inn Hotels", + "name": "Inn Account Setting", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/inn/inn_hotels/doctype/inn_account_setting/inn_account_setting.py b/inn/inn_hotels/doctype/inn_account_setting/inn_account_setting.py new file mode 100644 index 00000000..c82c8307 --- /dev/null +++ b/inn/inn_hotels/doctype/inn_account_setting/inn_account_setting.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Core Initiative and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class InnAccountSetting(Document): + pass diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.js b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.js index c2ff6017..abe38ff2 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.js +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.js @@ -2,47 +2,118 @@ // For license information, please see license.txt frappe.ui.form.on('Inn Hotels Setting', { - refresh: function (frm) { - if (frappe.user.has_role('Hotel Manager') || - frappe.user.has_role('Hotel Reservation User') || - frappe.user.has_role('Administrator')) { - frm.add_custom_button(__('Show Supervisor Passcode'), function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.show_supervisor_passcode', - }); - }); - } - }, - folio_transaction_type_generator: function (frm) { + refresh: function (frm) { + if (frappe.user.has_role('Hotel Manager') || + frappe.user.has_role('Hotel Reservation User') || + frappe.user.has_role('Administrator')) { + frm.add_custom_button(__('Show Supervisor Passcode'), function () { + frappe.call({ + method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.show_supervisor_passcode', + }); + }); + } +}, + folio_transaction_type_generator: function (frm) { frappe.call({ method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_folio_transaction_type', }); }, - bed_type_generator: function (frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_bed_type', - }); - }, - room_type_generator: function (frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_room_type', - }); - }, - inn_hotels_account_generator: function (frm) { - frappe.confirm(__("This may take a while. Please don't refresh or change the page before the Success or Error Message popped up. Click Yes to continue"), function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_hotel_account', - }); - }); - }, - test: function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_supervisor_passcode' - }); - }, - role_generator: function (frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.insert_role' - }); - } -}); + + // bed_type_generator: function (frm) { + // frappe.call({ + // method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_bed_type', + // }); + // }, + + + bed_type_generator: function (frm) { + frappe.call({ + method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_bed_type', + args: { + bed_type: frm.doc.bed_type // Pass the child table data + }, + callback: function (r) { + if (r.message) { + frappe.msgprint(r.message); + frm.refresh(); // Refresh the form to reflect changes + } + } + }); + }, + + // room_type_generator: function (frm) { + // frappe.call({ + // method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_room_type', + // }); + // }, + + room_type_generator: function (frm) { + // Ensure bed_type is passed + frappe.call({ + method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_room_type', + args: { + room_type: frm.doc.room_type // Pass the child table data + }, + callback: function (r) { + if (r.message) { + frappe.msgprint(r.message); + frm.refresh(); // Refresh the form to reflect changes + } + } + }); + }, + // inn_hotels_account_generator: function (frm) { + // frappe.confirm(__("This may take a while. Please don't refresh or change the page before the Success or Error Message popped up. Click Yes to continue"), function () { + // frappe.call({ + // method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_hotel_account', + // }); + // }); + // }, + + + inn_hotels_account_generator: function (frm) { + frappe.call({ + method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_hotel_account', + args: { + inn_account_setting: frm.doc.inn_account_setting + }, + callback: function (r) { + if (r.message) { + frappe.msgprint(r.message); + frm.refresh(); + } + } + }); + }, + + + + test: function () { + frappe.call({ + method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.generate_supervisor_passcode' + }); + }, + // role_generator: function (frm) { + // frappe.call({ + // method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.insert_role' + // }); + // } + + + role_generator: function (frm) { + // Ensure bed_type is passed + frappe.call({ + method: 'inn.inn_hotels.doctype.inn_hotels_setting.inn_hotels_setting.insert_role', + args: { + role: frm.doc.role // Pass the child table data + }, + callback: function (r) { + if (r.message) { + frappe.msgprint(r.message); + frm.refresh(); // Refresh the form to reflect changes + } + } + }); + } + +}); \ No newline at end of file diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index b434faa8..c295ffa8 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -69,6 +69,7 @@ "role", "cb4", "inn_hotels_account_generator", + "inn_account_setting", "folio_transaction_type_generator", "folio_transaction_type", "supervisor_passcode" @@ -462,11 +463,17 @@ "fieldtype": "Table", "label": "Folio Transaction Type", "options": "Inn Folio Transaction Type Setting" + }, + { + "fieldname": "inn_account_setting", + "fieldtype": "Table", + "label": "Inn Account Setting", + "options": "Inn Account Setting" } ], "issingle": 1, "links": [], - "modified": "2025-01-20 07:51:20.331534", + "modified": "2025-01-21 10:27:44.239782", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.py b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.py index e0c3c827..fc7434e9 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.py +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.py @@ -15,7 +15,7 @@ class InnHotelsSetting(Document): - pass + pass @frappe.whitelist() def generate_folio_transaction_type(): @@ -298,110 +298,200 @@ def generate_folio_transaction_type(): make_records(folio_transaction_type_records) frappe.msgprint("Generating Default Folio Transaction Type Success") +# @frappe.whitelist() +# def generate_bed_type(): +# bed_records = [] +# if not frappe.db.exists('Inn Bed Type', {'name': 'Single'}): +# bed_records += [{ +# 'doctype': 'Inn Bed Type', +# 'name': _('Single'), +# 'description': _('Single Bed') +# }] +# if not frappe.db.exists('Inn Bed Type', {'name': 'Double'}): +# bed_records += [{ +# 'doctype': 'Inn Bed Type', +# 'name': _('Double'), +# 'description': _('Double Bed') +# }] +# if not frappe.db.exists('Inn Bed Type', {'name': 'Twin'}): +# bed_records += [{ +# 'doctype': 'Inn Bed Type', +# 'name': _('Twin'), +# 'description': _('Twin Bed') +# }] +# make_records(bed_records) +# frappe.msgprint("Generating Default Bed Type Success") + @frappe.whitelist() -def generate_bed_type(): - bed_records = [] - if not frappe.db.exists('Inn Bed Type', {'name': 'Single'}): - bed_records += [{ - 'doctype': 'Inn Bed Type', - 'name': _('Single'), - 'description': _('Single Bed') - }] - if not frappe.db.exists('Inn Bed Type', {'name': 'Double'}): - bed_records += [{ - 'doctype': 'Inn Bed Type', - 'name': _('Double'), - 'description': _('Double Bed') - }] - if not frappe.db.exists('Inn Bed Type', {'name': 'Twin'}): - bed_records += [{ - 'doctype': 'Inn Bed Type', - 'name': _('Twin'), - 'description': _('Twin Bed') - }] - make_records(bed_records) - frappe.msgprint("Generating Default Bed Type Success") +def generate_bed_type(bed_type): + + if not bed_type: + frappe.throw(_("No bed type data provided.")) + + bed_type = frappe.parse_json(bed_type) + + for bed in bed_type: + # Perform validation for required fields + if "name1" not in bed or "description" not in bed: + frappe.throw(_("Each bed type must have a name and description.")) + + # Check if the bed type already exists + if not frappe.db.exists("Inn Bed Type", bed.get("name1")): + new_bed = frappe.get_doc({ + "doctype": "Inn Bed Type", + "name": bed.get("name1"), + "description": bed.get("description") + }) + new_bed.insert() + else: + frappe.msgprint(_("Bed Type '{0}' already exists. Skipping.").format(bed.get("name1"))) + + return _("Bed types generated successfully.") + + +# @frappe.whitelist() +# def generate_room_type(): +# room_type_records = [] +# if not frappe.db.exists('Inn Room Type', {'name': 'Studio'}): +# room_type_records += [{ +# 'doctype': 'Inn Room Type', +# 'name': _('Studio'), +# 'description': _('Studio Room') +# }] +# if not frappe.db.exists('Inn Room Type', {'name': 'Superior'}): +# room_type_records += [{ +# 'doctype': 'Inn Room Type', +# 'name': _('Superior'), +# 'description': _('Superior Room') +# }] +# if not frappe.db.exists('Inn Room Type', {'name': 'Deluxe'}): +# room_type_records += [{ +# 'doctype': 'Inn Room Type', +# 'name': _('Deluxe'), +# 'description': _('Deluxe Room') +# }] +# if not frappe.db.exists('Inn Room Type', {'name': 'Executive'}): +# room_type_records += [{ +# 'doctype': 'Inn Room Type', +# 'name': _('Executive'), +# 'description': _('Executive Room') +# }] +# if not frappe.db.exists('Inn Room Type', {'name': 'Suite'}): +# room_type_records += [{ +# 'doctype': 'Inn Room Type', +# 'name': _('Suite'), +# 'description': _('Suite Room') +# }] +# make_records(room_type_records) +# frappe.msgprint("Generating Default Room Type Success") + + + + + + @frappe.whitelist() -def generate_room_type(): - room_type_records = [] - if not frappe.db.exists('Inn Room Type', {'name': 'Studio'}): - room_type_records += [{ - 'doctype': 'Inn Room Type', - 'name': _('Studio'), - 'description': _('Studio Room') - }] - if not frappe.db.exists('Inn Room Type', {'name': 'Superior'}): - room_type_records += [{ - 'doctype': 'Inn Room Type', - 'name': _('Superior'), - 'description': _('Superior Room') - }] - if not frappe.db.exists('Inn Room Type', {'name': 'Deluxe'}): - room_type_records += [{ - 'doctype': 'Inn Room Type', - 'name': _('Deluxe'), - 'description': _('Deluxe Room') - }] - if not frappe.db.exists('Inn Room Type', {'name': 'Executive'}): - room_type_records += [{ - 'doctype': 'Inn Room Type', - 'name': _('Executive'), - 'description': _('Executive Room') - }] - if not frappe.db.exists('Inn Room Type', {'name': 'Suite'}): - room_type_records += [{ - 'doctype': 'Inn Room Type', - 'name': _('Suite'), - 'description': _('Suite Room') - }] - make_records(room_type_records) - frappe.msgprint("Generating Default Room Type Success") +def generate_room_type(room_type): + + if not room_type: + frappe.throw(_("No bed type data provided.")) + + room_type = frappe.parse_json(room_type) + + for bed in room_type: + if "name1" not in bed or "description" not in bed: + frappe.throw(_("Each bed type must have a name and description.")) + + # Check if the Room type already exists + if not frappe.db.exists("Inn Room Type", bed.get("name1")): + new_bed = frappe.get_doc({ + "doctype": "Inn Room Type", + "name": bed.get("name1"), + "description": bed.get("description") + }) + new_bed.insert() + else: + frappe.msgprint(_("Room Type '{0}' already exists. Skipping.").format(bed.get("name1"))) + + return _("Room types generated successfully.") + + -def create_account(account_name, parent_number, account_number, is_group, account_currency, account_type, root_type=None, company_name=None): - print('Create account start') - if company_name is None: - company_name = frappe.get_doc("Global Defaults").default_company - - if frappe.db.exists('Account', {'account_number': account_number}): - update_account_number(frappe.db.get_list('Account', filters={'account_number': account_number})[0].name, account_name, account_number) - print('account '+ account_number +' name updated') - this_account = frappe.get_doc('Account', {'account_number': account_number}) - print('this_account group = '+ str(this_account.is_group)) - if int(is_group) == 1 and int(this_account.is_group) != int(is_group): - print("This non-group account need to changed to group") - this_account.account_type = '' - this_account.is_group = 1 - this_account.save() - print("Account changed to group") - else: - new_account = frappe.new_doc("Account") - new_account.account_name = account_name - new_account.company = company_name - if parent_number == '': - new_account.flags.ignore_mandatory = True - new_account.parent_account = None - else: - new_account.parent_account = frappe.db.get_list('Account', filters={'account_number': parent_number})[0].name - new_account.account_number = account_number - new_account.is_group = is_group - new_account.account_currency = account_currency - new_account.account_type = account_type - if root_type is not None: - new_account.root_type = root_type - new_account.insert() - print('new account inserted') - print('Create account end') - print('===================') - print('===================') @frappe.whitelist() -def generate_hotel_account(): - accounts = get_account() - for item in accounts: - create_account(item['account_name'], item['parent_number'], item['account_number'], item['is_group'], - item['account_currency'], item['account_type'], item['root_type']) - frappe.msgprint("Generating Account Success") +def insert_role(role): + + if not role: + frappe.throw(_("No Role data provided.")) + + role = frappe.parse_json(role) + + for bed in role: + if "name1" not in bed: + frappe.throw(_("Each Rolemust have a name ")) + + if not frappe.db.exists("Role", bed.get("name1")): + new_bed = frappe.get_doc({ + "doctype": "Role", + "role_name": bed.get("name1"), + }) + new_bed.insert() + else: + frappe.msgprint(_("Role '{0}' already exists. Skipping.").format(bed.get("name1"))) + + return _("Role generated successfully.") + + + +def create_account(account_name, parent_number, account_number, is_group, account_currency, account_type, root_type=None, company_name=None): + print('Create account start') + if company_name is None: + company_name = frappe.get_doc("Global Defaults").default_company + + # Check if the account already exists + existing_account = frappe.db.get_list('Account', filters={'account_number': account_number}, fields=['name']) + if existing_account: + account_name_in_db = existing_account[0].name + update_account_number(account_name_in_db, account_name, account_number) + print('Account ' + account_number + ' name updated') + this_account = frappe.get_doc('Account', account_name_in_db) + print('this_account group = ' + str(this_account.is_group)) + if int(is_group) == 1 and int(this_account.is_group) != int(is_group): + print("This non-group account needs to be changed to group") + this_account.account_type = '' + this_account.is_group = 1 + this_account.save() + print("Account changed to group") + else: + # If parent_number is provided, ensure the parent account exists + parent_account = None + if parent_number: + parent_account_query = frappe.db.get_list('Account', filters={'account_number': parent_number}, fields=['name']) + if not parent_account_query: + frappe.throw(_("Parent account with number {0} not found.").format(parent_number)) + parent_account = parent_account_query[0].name + + new_account = frappe.new_doc("Account") + new_account.account_name = account_name + new_account.company = company_name + new_account.parent_account = parent_account + new_account.account_number = account_number + new_account.is_group = is_group + new_account.account_currency = account_currency + new_account.account_type = account_type + new_account.root_type = root_type + new_account.insert() + # print('New account inserted') + # print('Create account end') + # print('===================') +# @frappe.whitelist() +# def generate_hotel_account(): +# accounts = get_account() +# for item in accounts: +# create_account(item['account_name'], item['parent_number'], item['account_number'], item['is_group'], +# item['account_currency'], item['account_type'], item['root_type']) +# frappe.msgprint("Generating Account Success") # create_account('Payroll', '', '6000.000', 1, 'IDR', '', frappe.get_doc("Global Defaults").default_company, 'Expense') # if frappe.db.exists('Account', {'account_number': '6000.000'}) and frappe.db.exists('Account', {'account_number': '7000.000'}): # accounts = get_account() @@ -411,6 +501,44 @@ def generate_hotel_account(): # else: # frappe.msgprint("Please Create account 6000.0000 and 7000.000 in the Chart of Account First") + + + +@frappe.whitelist() +def generate_hotel_account(inn_account_setting): + if not inn_account_setting: + frappe.throw(_("No inn_account_setting data provided.")) + + try: + inn_account_setting = frappe.parse_json(inn_account_setting) + except Exception as e: + frappe.throw(_("Invalid JSON format: {0}").format(str(e))) + + if not isinstance(inn_account_setting, list): + frappe.throw(_("Input data must be a list of account settings.")) + + for item in inn_account_setting: + try: + required_keys = ['account_name', 'parent_number', 'account_number', 'is_group', 'account_currency', 'account_type', 'root_type'] + for key in required_keys: + if key not in item: + frappe.throw(_("Missing required key: {0} in account setting").format(key)) + + create_account( + account_name=item['account_name'], + parent_number=item['parent_number'], + account_number=item['account_number'], + is_group=item['is_group'], + account_currency=item['account_currency'], + account_type=item['account_type'], + root_type=item['root_type'] + ) + except Exception as e: + frappe.msgprint(_("Failed to create account: {0}. Error: {1}").format(item.get('account_name', 'Unknown'), str(e))) + + frappe.msgprint(_("Account generation process completed.")) + + @frappe.whitelist() def generate_supervisor_passcode(): digits = string.digits @@ -425,6 +553,6 @@ def show_supervisor_passcode(): generate_supervisor_passcode() show_supervisor_passcode() -@frappe.whitelist() -def insert_role(): - role.insert_role() \ No newline at end of file +# @frappe.whitelist() +# def insert_role(): +# role.insert_role() \ No newline at end of file diff --git a/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.json b/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.json index aee04907..325344e5 100644 --- a/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.json +++ b/inn/inn_hotels/doctype/inn_setting_tools/inn_setting_tools.json @@ -1,6 +1,5 @@ { "actions": [], - "allow_rename": 1, "creation": "2025-01-19 21:31:50.073235", "doctype": "DocType", "editable_grid": 1, @@ -13,6 +12,7 @@ { "fieldname": "name1", "fieldtype": "Data", + "in_list_view": 1, "label": "Name" }, { @@ -24,7 +24,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-01-19 21:32:25.445876", + "modified": "2025-01-20 21:01:20.654354", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Setting Tools", From b045026cd0e347bac4c1fa629d3139bf9c7a1bf7 Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Tue, 21 Jan 2025 23:29:55 +0300 Subject: [PATCH 04/22] (edit) in inn room charge posting update filed static to Dynamic --- .../inn_hotels_setting.json | 197 +++++++++++++++++- .../inn_room_charge_posting.py | 94 +++++++-- 2 files changed, 271 insertions(+), 20 deletions(-) diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index c295ffa8..4c3bd5e9 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -72,7 +72,34 @@ "inn_account_setting", "folio_transaction_type_generator", "folio_transaction_type", - "supervisor_passcode" + "supervisor_passcode", + "folio_default_tab", + "package_tax", + "room_charge_taxservice", + "breakfast_charge_taxservice", + "credit_card_administration_fee", + "package", + "room_charge", + "breakfast_charge", + "refund", + "dp_kamar", + "room_payment", + "deposit", + "down_payment", + "payment", + "additional_charge", + "restaurant_food", + "restaurant_beverages", + "restaurant_other", + "room_service_food", + "room_service_beverage", + "fbs__service_10_", + "fbs__tax_11_", + "round_off", + "laundry", + "cancellation_fee", + "late_checkout", + "early_checkin" ], "fields": [ { @@ -443,37 +470,203 @@ { "fieldname": "bed_type", "fieldtype": "Table", + "hidden": 1, "label": "Bed Type", "options": "Inn Setting Tools" }, { "fieldname": "room_type", "fieldtype": "Table", + "hidden": 1, "label": "Room Type", "options": "Inn Setting Tools" }, { "fieldname": "role", "fieldtype": "Table", + "hidden": 1, "label": "Role", "options": "Inn Role" }, { "fieldname": "folio_transaction_type", "fieldtype": "Table", + "hidden": 1, "label": "Folio Transaction Type", "options": "Inn Folio Transaction Type Setting" }, { "fieldname": "inn_account_setting", "fieldtype": "Table", + "hidden": 1, "label": "Inn Account Setting", "options": "Inn Account Setting" + }, + { + "fieldname": "folio_default_tab", + "fieldtype": "Tab Break", + "label": "Folio Default" + }, + { + "fieldname": "room_charge_taxservice", + "fieldtype": "Link", + "label": "Room Charge Tax/Service", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "breakfast_charge_taxservice", + "fieldtype": "Link", + "label": "Breakfast Charge Tax/Service", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "credit_card_administration_fee", + "fieldtype": "Link", + "label": "Credit Card Administration Fee", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "package", + "fieldtype": "Link", + "label": "Package", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "room_charge", + "fieldtype": "Link", + "label": "Room Charge", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "breakfast_charge", + "fieldtype": "Link", + "label": "Breakfast Charge", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "refund", + "fieldtype": "Link", + "label": "Refund", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "dp_kamar", + "fieldtype": "Link", + "label": "DP Kamar", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "room_payment", + "fieldtype": "Link", + "label": "Room Payment", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "deposit", + "fieldtype": "Link", + "label": "Deposit", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "down_payment", + "fieldtype": "Link", + "label": "Down Payment", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "payment", + "fieldtype": "Link", + "label": "Payment", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "additional_charge", + "fieldtype": "Link", + "label": "Additional Charge", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "restaurant_food", + "fieldtype": "Link", + "label": "Restaurant Food", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "restaurant_beverages", + "fieldtype": "Link", + "label": "Restaurant Beverages", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "restaurant_other", + "fieldtype": "Link", + "label": "Restaurant Other", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "room_service_food", + "fieldtype": "Link", + "label": "Room Service Food", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "room_service_beverage", + "fieldtype": "Link", + "label": "Room Service Beverage", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "fbs__service_10_", + "fieldtype": "Link", + "label": "FBS Service 10 %", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "fbs__tax_11_", + "fieldtype": "Link", + "label": "FBS Tax 11 %", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "round_off", + "fieldtype": "Link", + "label": "Round Off", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "laundry", + "fieldtype": "Link", + "label": "Laundry", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "cancellation_fee", + "fieldtype": "Link", + "label": "Cancellation Fee", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "late_checkout", + "fieldtype": "Link", + "label": "Late Checkout", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "early_checkin", + "fieldtype": "Link", + "label": "Early Checkin", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "package_tax", + "fieldtype": "Link", + "label": "Package Tax", + "options": "Inn Folio Transaction Type" } ], "issingle": 1, "links": [], - "modified": "2025-01-21 10:27:44.239782", + "modified": "2025-01-21 22:07:25.990438", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py index 0deb3505..67056456 100644 --- a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py +++ b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py @@ -1,4 +1,3 @@ - # -*- coding: utf-8 -*- # Copyright (c) 2020, Core Initiative and contributors # For license information, please see license.txt @@ -59,11 +58,41 @@ def populate_tobe_posted(): @frappe.whitelist() def post_individual_room_charges(parent_id, tobe_posted_list): + # Fetch all transaction types from Inn Hotels Setting + hotel_settings = frappe.get_doc("Inn Hotels Setting") + transaction_types = { + "room_charge_tax_service": hotel_settings.room_charge_tax_service, + "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, + "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, + "package": hotel_settings.package, + "room_charge": hotel_settings.room_charge, + "breakfast_charge": hotel_settings.breakfast_charge, + "refund": hotel_settings.refund, + "dp_kamar": hotel_settings.dp_kamar, + "room_payment": hotel_settings.room_payment, + "deposit": hotel_settings.deposit, + "down_payment": hotel_settings.down_payment, + "payment": hotel_settings.payment, + "additional_charge": hotel_settings.additional_charge, + "restaurant_food": hotel_settings.restaurant_food, + "restaurant_beverages": hotel_settings.restaurant_beverages, + "restaurant_other": hotel_settings.restaurant_other, + "room_service_food": hotel_settings.room_service_food, + "room_service_beverage": hotel_settings.room_service_beverage, + "fbs_service_10": hotel_settings.fbs_service_10, + "fbs_tax_11": hotel_settings.fbs_tax_11, + "round_off": hotel_settings.round_off, + "laundry": hotel_settings.laundry, + "cancellation_fee": hotel_settings.cancellation_fee, + "late_checkout": hotel_settings.late_checkout, + "early_checkin": hotel_settings.early_checkin, + } # to exclude service charge from reduced because of commision / cashback room_post_settings = frappe.db.get_values_from_single(doctype="Inn Hotels Setting", filters="", fields=["profit_sharing_account", "profit_sharing_transaction_type"], as_dict=True)[0] PROFIT_SHARING_ACCOUNT = room_post_settings.profit_sharing_account - COMMISION_TRANSACTION_TYPE = room_post_settings.profit_sharing_transaction_type + COMMISION_TRANSACTION_TYPE = room_post_settings.profit_sharing_transaction_type + channel_exclude_tax = frappe.get_list("Inn Channel Tax Exclude", parent_doctype='Inn Hotels Setting', filters = { @@ -83,13 +112,13 @@ def post_individual_room_charges(parent_id, tobe_posted_list): for item in list_json: # Create Inn Folio Transaction Bundle ftb_doc = frappe.new_doc('Inn Folio Transaction Bundle') - ftb_doc.transaction_type = 'Room Charge' + ftb_doc.transaction_type = transaction_types["room_charge"] # Use dynamic value ftb_doc.insert() # Posting Room Charge item_doc = frappe.get_doc('Inn Room Charge To Be Posted', item) accumulated_amount = 0.00 - room_charge_debit_account, room_charge_credit_account = get_accounts_from_id('Room Charge') + room_charge_debit_account, room_charge_credit_account = get_accounts_from_id(transaction_types["room_charge"]) # Use dynamic value reservation = frappe.get_doc('Inn Reservation', item_doc.reservation_id) is_exclude_tax = False if (reservation.channel in channel_exclude_tax) or (reservation.actual_room_rate <= flt(maximum_price_exclude_tax)): @@ -110,7 +139,7 @@ def post_individual_room_charges(parent_id, tobe_posted_list): room_charge_folio_trx.flag = 'Debit' room_charge_folio_trx.is_void = 0 room_charge_folio_trx.idx = get_idx(item_doc.folio_id) - room_charge_folio_trx.transaction_type = 'Room Charge' + room_charge_folio_trx.transaction_type = transaction_types["room_charge"] # Use dynamic value room_charge_folio_trx.amount = float(int(reservation.nett_actual_room_rate)) accumulated_amount += float(int(reservation.nett_actual_room_rate)) room_charge_folio_trx.debit_account = room_charge_debit_account @@ -179,7 +208,7 @@ def post_individual_room_charges(parent_id, tobe_posted_list): room_tax_doc.flag = 'Debit' room_tax_doc.is_void = 0 room_tax_doc.idx = get_idx(item_doc.folio_id) - room_tax_doc.transaction_type = 'Room Charge Tax/Service' + room_tax_doc.transaction_type = transaction_types["room_charge_tax_service"] room_tax_doc.amount = room_tb_amount[index] accumulated_amount += room_tb_amount[index] room_tax_doc.credit_account = frappe.get_doc('Inn Tax Breakdown', room_tax_item_name).breakdown_account @@ -205,12 +234,12 @@ def post_individual_room_charges(parent_id, tobe_posted_list): breakfast_price = float(int(reservation.nett_actual_breakfast_rate)) if breakfast_price > 0: # Posting Breakfast Charge - breakfast_charge_debit_account, breakfast_charge_credit_account = get_accounts_from_id('Breakfast Charge') + breakfast_charge_debit_account, breakfast_charge_credit_account = get_accounts_from_id(transaction_types["breakfast_charge"]) breakfast_charge_folio_trx = frappe.new_doc('Inn Folio Transaction') breakfast_charge_folio_trx.flag = 'Debit' breakfast_charge_folio_trx.is_void = 0 breakfast_charge_folio_trx.idx = get_idx(item_doc.folio_id) - breakfast_charge_folio_trx.transaction_type = 'Breakfast Charge' + breakfast_charge_folio_trx.transaction_type = transaction_types["breakfast_charge"] breakfast_charge_folio_trx.amount = float(int(reservation.nett_actual_breakfast_rate)) accumulated_amount += float(int(reservation.nett_actual_breakfast_rate)) breakfast_charge_folio_trx.debit_account = breakfast_charge_debit_account @@ -264,7 +293,7 @@ def post_individual_room_charges(parent_id, tobe_posted_list): breakfast_tax_doc.flag = 'Debit' breakfast_tax_doc.is_void = 0 breakfast_tax_doc.idx = get_idx(item_doc.folio_id) - breakfast_tax_doc.transaction_type = 'Breakfast Charge Tax/Service' + breakfast_tax_doc.transaction_type = transaction_types["breakfast_charge_tax_service"] breakfast_tax_doc.amount = breakfast_tb_amount[index] accumulated_amount += breakfast_tb_amount[index] breakfast_tax_doc.credit_account = frappe.get_doc('Inn Tax Breakdown', @@ -356,11 +385,41 @@ def post_individual_room_charges(parent_id, tobe_posted_list): @frappe.whitelist() def post_room_charges(parent_id, tobe_posted_list): + # Fetch all transaction types from Inn Hotels Setting + hotel_settings = frappe.get_doc("Inn Hotels Setting") + transaction_types = { + "room_charge_tax_service": hotel_settings.room_charge_tax_service, + "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, + "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, + "package": hotel_settings.package, + "room_charge": hotel_settings.room_charge, + "breakfast_charge": hotel_settings.breakfast_charge, + "refund": hotel_settings.refund, + "dp_kamar": hotel_settings.dp_kamar, + "room_payment": hotel_settings.room_payment, + "deposit": hotel_settings.deposit, + "down_payment": hotel_settings.down_payment, + "payment": hotel_settings.payment, + "additional_charge": hotel_settings.additional_charge, + "restaurant_food": hotel_settings.restaurant_food, + "restaurant_beverages": hotel_settings.restaurant_beverages, + "restaurant_other": hotel_settings.restaurant_other, + "room_service_food": hotel_settings.room_service_food, + "room_service_beverage": hotel_settings.room_service_beverage, + "fbs_service_10": hotel_settings.fbs_service_10, + "fbs_tax_11": hotel_settings.fbs_tax_11, + "round_off": hotel_settings.round_off, + "laundry": hotel_settings.laundry, + "cancellation_fee": hotel_settings.cancellation_fee, + "late_checkout": hotel_settings.late_checkout, + "early_checkin": hotel_settings.early_checkin, + } # to exclude service charge from reduced because of commision / cashback room_post_settings = frappe.db.get_values_from_single(doctype="Inn Hotels Setting", filters="", fields=["room_revenue_account", "breakfast_revenue_account", "profit_sharing_account", "profit_sharing_transaction_type"], as_dict=True)[0] PROFIT_SHARING_ACCOUNT = room_post_settings.profit_sharing_account - COMMISION_TRANSACTION_TYPE = room_post_settings.profit_sharing_transaction_type + COMMISION_TRANSACTION_TYPE = room_post_settings.profit_sharing_transaction_type + channel_exclude_tax = frappe.get_list("Inn Channel Tax Exclude", { "parenttype": "Inn Hotels Setting", @@ -383,12 +442,12 @@ def post_room_charges(parent_id, tobe_posted_list): for item in list_json: # Create Inn Folio Transaction Bundle ftb_doc = frappe.new_doc('Inn Folio Transaction Bundle') - ftb_doc.transaction_type = 'Room Charge' + ftb_doc.transaction_type = transaction_types["room_charge"] ftb_doc.insert() # Posting Room Charge accumulated_amount = 0.00 - room_charge_debit_account, room_charge_credit_account = get_accounts_from_id('Room Charge') + room_charge_debit_account, room_charge_credit_account = get_accounts_from_id(transaction_types["room_charge"]) reservation = frappe.get_doc('Inn Reservation', item['reservation_id']) fdc_reservation = reservation is_exclude_tax = False @@ -408,7 +467,7 @@ def post_room_charges(parent_id, tobe_posted_list): room_charge_folio_trx.flag = 'Debit' room_charge_folio_trx.is_void = 0 room_charge_folio_trx.idx = get_idx(item['folio_id']) - room_charge_folio_trx.transaction_type = 'Room Charge' + room_charge_folio_trx.transaction_type = transaction_types["room_charge"] room_charge_folio_trx.amount = float(int(reservation.nett_actual_room_rate)) accumulated_amount += float(int(reservation.nett_actual_room_rate)) room_charge_folio_trx.debit_account = room_charge_debit_account @@ -477,7 +536,7 @@ def post_room_charges(parent_id, tobe_posted_list): room_tax_doc.flag = 'Debit' room_tax_doc.is_void = 0 room_tax_doc.idx = get_idx(item['folio_id']) - room_tax_doc.transaction_type = 'Room Charge Tax/Service' + room_tax_doc.transaction_type = transaction_types["room_charge_tax_service"] room_tax_doc.amount = room_tb_amount[index] accumulated_amount += room_tb_amount[index] room_tax_doc.credit_account = frappe.get_doc('Inn Tax Breakdown', room_tax_item_name).breakdown_account @@ -498,12 +557,11 @@ def post_room_charges(parent_id, tobe_posted_list): if breakfast_price > 0: # Posting Breakfast Charge - breakfast_charge_debit_account, breakfast_charge_credit_account = get_accounts_from_id('Breakfast Charge') - breakfast_charge_folio_trx = frappe.new_doc('Inn Folio Transaction') + breakfast_charge_debit_account, breakfast_charge_credit_account = get_accounts_from_id(transaction_types["breakfast_charge"]) breakfast_charge_folio_trx.flag = 'Debit' breakfast_charge_folio_trx.is_void = 0 breakfast_charge_folio_trx.idx = get_idx(item['folio_id']) - breakfast_charge_folio_trx.transaction_type = 'Breakfast Charge' + breakfast_charge_folio_trx.transaction_type = transaction_types["breakfast_charge"] breakfast_charge_folio_trx.amount = float(int(reservation.nett_actual_breakfast_rate)) accumulated_amount += float(int(reservation.nett_actual_breakfast_rate)) breakfast_charge_folio_trx.debit_account = breakfast_charge_debit_account @@ -555,7 +613,7 @@ def post_room_charges(parent_id, tobe_posted_list): breakfast_tax_doc.flag = 'Debit' breakfast_tax_doc.is_void = 0 breakfast_tax_doc.idx = get_idx(item['folio_id']) - breakfast_tax_doc.transaction_type = 'Breakfast Charge Tax/Service' + breakfast_tax_doc.transaction_type = transaction_types["breakfast_charge_tax_service"] breakfast_tax_doc.amount = breakfast_tb_amount[index] accumulated_amount += breakfast_tb_amount[index] breakfast_tax_doc.credit_account = frappe.get_doc('Inn Tax Breakdown', From 956a5a45812726d30adfb5205e00ffba3f52bf84 Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Wed, 22 Jan 2025 22:08:00 +0300 Subject: [PATCH 05/22] (edit) Converting fields in Inn Hotels Setting from static to dynamic --- inn/__init__.py | 2 +- .../inn_dayend_close/inn_dayend_close.json | 2 +- .../inn_dayend_close/inn_dayend_close.py | 61 +- .../inn_hotels_setting.json | 58 +- .../inn_reservation/inn_reservation.py | 26 +- .../inn_room_card_owner_webcard.py | 280 ++--- .../inn_room_charge_posting.py | 4 - inn/inn_hotels/doctype/inn_shift/inn_shift.py | 958 +++++++++--------- .../page/pos_extended/pos_extended.py | 97 +- .../report/audit_report/audit_report.py | 94 +- 10 files changed, 821 insertions(+), 761 deletions(-) diff --git a/inn/__init__.py b/inn/__init__.py index 6af7381a..73381fd2 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = '1.0.0' +__version__ = '1.1.1' diff --git a/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.json b/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.json index f23d2bb4..cd3e532f 100644 --- a/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.json +++ b/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.json @@ -86,7 +86,7 @@ } ], "links": [], - "modified": "2024-03-14 11:35:48.623600", + "modified": "2025-01-22 19:31:51.872837", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Dayend Close", diff --git a/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.py b/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.py index 6e305bd3..784bf5b6 100644 --- a/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.py +++ b/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.py @@ -25,7 +25,37 @@ def is_there_open_dayend_close(): def process_dayend_close(doc_id): need_resolve_flag = False - COMMISSION_TRANSACTION_TYPE = frappe.db.get_single_value("Inn Hotels Setting", fieldname="profit_sharing_transaction_type") + # Fetch transaction types from Inn Hotels Setting + hotel_settings = frappe.get_doc("Inn Hotels Setting") + transaction_types = { + "room_charge_tax_service": hotel_settings.room_charge_tax_service, + "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, + "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, + "package": hotel_settings.package, + "room_charge": hotel_settings.room_charge, + "breakfast_charge": hotel_settings.breakfast_charge, + "refund": hotel_settings.refund, + "dp_kamar": hotel_settings.dp_kamar, + "room_payment": hotel_settings.room_payment, + "deposit": hotel_settings.deposit, + "down_payment": hotel_settings.down_payment, + "payment": hotel_settings.payment, + "additional_charge": hotel_settings.additional_charge, + "restaurant_food": hotel_settings.restaurant_food, + "restaurant_beverages": hotel_settings.restaurant_beverages, + "restaurant_other": hotel_settings.restaurant_other, + "room_service_food": hotel_settings.room_service_food, + "room_service_beverage": hotel_settings.room_service_beverage, + "fbs_service_10": hotel_settings.fbs_service_10, + "fbs_tax_11": hotel_settings.fbs_tax_11, + "round_off": hotel_settings.round_off, + "laundry": hotel_settings.laundry, + "cancellation_fee": hotel_settings.cancellation_fee, + "late_checkout": hotel_settings.late_checkout, + "early_checkin": hotel_settings.early_checkin, + } + + COMMISSION_TRANSACTION_TYPE = hotel_settings.profit_sharing_transaction_type # Create Journal Entry Pairing for Every Eligible Inn Folio Transactions folio_list = frappe.get_all('Inn Folio', filters={'status': ['in', ['Open', 'Closed']], 'journal_entry_id_closed': ['=', '']}, fields=["name", "reservation_id"]) @@ -159,8 +189,7 @@ def process_dayend_close(doc_id): # Create Journal Entry for Inn Restaurant Finished Order # Get all finished order that not transfered to folio and not paired with journal entry yet - # create_je_for_inn_restaurant_finished_order() - + create_je_for_inn_restaurant_finished_order(transaction_types) doc_audit_log = frappe.new_doc('Inn Audit Log') doc_audit_log.naming_series = 'AL.DD.-.MM.-.YYYY.-' @@ -265,7 +294,7 @@ def create_journal_entry(title, remark, debit_account, credit_account, amount): doc_je.save() doc_je.submit() -def create_je_for_inn_restaurant_finished_order(): +def create_je_for_inn_restaurant_finished_order(transaction_types): order_list = frappe.get_all('Inn Restaurant Finished Order', filters={ 'transfer_charges_folio': ('=', ''), @@ -303,44 +332,44 @@ def create_je_for_inn_restaurant_finished_order(): print("entry restaurant food") food_title = 'Restaurant Food of ' + order.name food_remark = 'Restaurant Food Charges from Restaurant Order: ' + order.name - food_debit_account = frappe.get_doc('Inn Folio Transaction Type', 'Restaurant Food').debit_account - food_credit_account = frappe.get_doc('Inn Folio Transaction Type', 'Restaurant Food').credit_account + food_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_food"]).debit_account + food_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_food"]).credit_account create_journal_entry(food_title, food_remark, food_debit_account, food_credit_account, restaurant_food) if restaurant_beverage > 0: print("entry restaurant beverage") bev_title = 'Restaurant Beverages of ' + order.name bev_remark = 'Restaurant Beverage Charges from Restaurant Order: ' + order.name - bev_debit_account = frappe.get_doc('Inn Folio Transaction Type', 'Restaurant Beverages').debit_account - bev_credit_account = frappe.get_doc('Inn Folio Transaction Type', 'Restaurant Beverages').credit_account + bev_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_beverages"]).debit_account + bev_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_beverages"]).credit_account create_journal_entry(bev_title, bev_remark, bev_debit_account, bev_credit_account, restaurant_beverage) if restaurant_other > 0: print("entry Other Restaurant") other_title = 'Other Restaurant of ' + order.name other_remark = 'Other Restaurant Charges from Restaurant Order: ' + order.name - other_debit_account = frappe.get_doc('Inn Folio Transaction Type', 'Other Restaurant').debit_account - other_credit_account = frappe.get_doc('Inn Folio Transaction Type', 'Other Restaurant').credit_account + other_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_other"]).debit_account + other_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_other"]).credit_account create_journal_entry(other_title, other_remark, other_debit_account, other_credit_account, restaurant_other) # Create Journal Entry for Round Off Charges if float(order.rounding_amount) > 0: ro_title = 'Round Off of ' + order.name ro_remark = 'Rounding off Amount of Restaurant Charges from Restaurant Order: ' + order.name - ro_debit_account = frappe.get_doc('Inn Folio Transaction Type', 'Round Off').debit_account - ro_credit_account = frappe.get_doc('Inn Folio Transaction Type', 'Round Off').credit_account + ro_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["round_off"]).debit_account + ro_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["round_off"]).credit_account create_journal_entry(ro_title, ro_remark, ro_debit_account, ro_credit_account, order.rounding_amount) # Create Journal Entry for Service service_title = 'FBS -- Service 10 % of ' + order.name service_remark = 'Service of Restaurant Charges from Restaurant Order: ' + order.name - srv_debit_account = frappe.get_doc('Inn Folio Transaction Type', 'FBS -- Service 10 %').debit_account - srv_credit_account = frappe.get_doc('Inn Folio Transaction Type', 'FBS -- Service 10 %').credit_account + srv_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["fbs_service_10"]).debit_account + srv_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["fbs_service_10"]).credit_account create_journal_entry(service_title, service_remark, srv_debit_account, srv_credit_account, order.service_amount) # Create Journal Entry for Tax tax_title = 'FBS -- Tax 11 %' + order.name tax_remark = 'Tax of Restaurant Charges from Restaurant Order: ' + order.name - tax_debit_account = frappe.get_doc('Inn Folio Transaction Type', 'FBS -- Tax 11 %').debit_account - tax_credit_account = frappe.get_doc('Inn Folio Transaction Type', 'FBS -- Tax 11 %').credit_account + tax_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["fbs_tax_11"]).debit_account + tax_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["fbs_tax_11"]).credit_account create_journal_entry(tax_title, tax_remark, tax_debit_account, tax_credit_account, order.tax_amount) # 2. ORDER PAYMENT IN RESTAURANT FINISHED ORDER diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index 4c3bd5e9..3c51ea94 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -75,8 +75,8 @@ "supervisor_passcode", "folio_default_tab", "package_tax", - "room_charge_taxservice", - "breakfast_charge_taxservice", + "room_charge_tax_service", + "breakfast_charge_tax_service", "credit_card_administration_fee", "package", "room_charge", @@ -93,8 +93,8 @@ "restaurant_other", "room_service_food", "room_service_beverage", - "fbs__service_10_", - "fbs__tax_11_", + "fbs_service_10", + "fbs_tax_11", "round_off", "laundry", "cancellation_fee", @@ -507,18 +507,6 @@ "fieldtype": "Tab Break", "label": "Folio Default" }, - { - "fieldname": "room_charge_taxservice", - "fieldtype": "Link", - "label": "Room Charge Tax/Service", - "options": "Inn Folio Transaction Type" - }, - { - "fieldname": "breakfast_charge_taxservice", - "fieldtype": "Link", - "label": "Breakfast Charge Tax/Service", - "options": "Inn Folio Transaction Type" - }, { "fieldname": "credit_card_administration_fee", "fieldtype": "Link", @@ -615,18 +603,6 @@ "label": "Room Service Beverage", "options": "Inn Folio Transaction Type" }, - { - "fieldname": "fbs__service_10_", - "fieldtype": "Link", - "label": "FBS Service 10 %", - "options": "Inn Folio Transaction Type" - }, - { - "fieldname": "fbs__tax_11_", - "fieldtype": "Link", - "label": "FBS Tax 11 %", - "options": "Inn Folio Transaction Type" - }, { "fieldname": "round_off", "fieldtype": "Link", @@ -662,11 +638,35 @@ "fieldtype": "Link", "label": "Package Tax", "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "room_charge_tax_service", + "fieldtype": "Link", + "label": "Room Charge Tax/Service", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "breakfast_charge_tax_service", + "fieldtype": "Link", + "label": "Breakfast Charge Tax/Service", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "fbs_tax_11", + "fieldtype": "Link", + "label": "FBS Tax 11 %", + "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "fbs_service_10", + "fieldtype": "Link", + "label": "FBS Service 10 %", + "options": "Inn Folio Transaction Type" } ], "issingle": 1, "links": [], - "modified": "2025-01-21 22:07:25.990438", + "modified": "2025-01-22 19:51:25.793321", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.py b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.py index 14971ac6..267ef46c 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.py +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.py @@ -256,19 +256,33 @@ def allowed_to_in_house(reservation_id): @frappe.whitelist() def get_total_deposit(doc): - if doc.group_id != None: - return frappe.db.sql("""SELECT SUM(amount) AS amount + """ + Get the total deposit for a reservation or group. + The transaction type (e.g., 'Down Payment') is dynamically fetched from Inn Hotels Setting. + """ + # Fetch the transaction type from Inn Hotels Setting + transaction_type = frappe.db.get_single_value('Inn Hotels Setting', 'down_payment') + + if not transaction_type: + frappe.throw("Transaction type for deposit is not set in Inn Hotels Setting.") + + if doc.group_id: + return frappe.db.sql(""" + SELECT SUM(amount) AS amount FROM `tabInn Folio Transaction` ft LEFT JOIN `tabInn Folio` f ON f.name=ft.parent LEFT JOIN `tabInn Reservation` r ON r.name=f.reservation_id - WHERE r.group_id=%s AND ft.transaction_type='Down Payment'""", doc.group_id, as_dict=True) + WHERE r.group_id=%s AND ft.transaction_type=%s + """, (doc.group_id, transaction_type), as_dict=True) else: - return frappe.db.sql("""SELECT sum(amount) as amount + return frappe.db.sql(""" + SELECT SUM(amount) AS amount FROM `tabInn Folio Transaction` ft LEFT JOIN `tabInn Folio` f ON f.name=ft.parent LEFT JOIN `tabInn Reservation` r ON r.name=f.reservation_id - WHERE r.name=%s AND ft.transaction_type='Down Payment'""", doc.name, as_dict=True) - + WHERE r.name=%s AND ft.transaction_type=%s + """, (doc.name, transaction_type), as_dict=True) + @frappe.whitelist() def get_date(): return datetime.datetime.now().strftime("%d/%m/%Y") \ No newline at end of file diff --git a/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py b/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py index 174f3c72..f4c61040 100644 --- a/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py +++ b/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py @@ -9,6 +9,19 @@ from datetime import date, timedelta, datetime +def get_transaction_types(): + """ + Fetch transaction types dynamically from Inn Hotels Setting. + """ + hotel_settings = frappe.get_doc("Inn Hotels Setting") + return { + "room_charge_tax_service": hotel_settings.room_charge_tax_service, + "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, + "room_charge": hotel_settings.room_charge, + "breakfast_charge": hotel_settings.breakfast_charge, + } + + def count_all_room(start_date, end_date): default_availability = frappe.db.count("Inn Room") try: @@ -30,29 +43,32 @@ def count_all_room(start_date, end_date): @frappe.whitelist() def count_sold_room(start_date=None, end_date=None): - if start_date == None and end_date == None: + if start_date is None and end_date is None: start_date = date.today().isoformat() - end_date = date.today() + timedelta(days=1) - end_date = end_date.isoformat() + end_date = (date.today() + timedelta(days=1)).isoformat() try: start_date = parse(start_date, False).date() except ValueError: - raise frappe.ValidationError("{start_date} is not a valid date string") + raise frappe.ValidationError(f"{start_date} is not a valid date string") try: end_date = parse(end_date, False).date() except ValueError: - raise frappe.ValidationError("{end_date} is not a valid date string") + raise frappe.ValidationError(f"{end_date} is not a valid date string") delta = end_date - start_date if delta.days < 0: - raise frappe.ValidationError("start date must before end date") + raise frappe.ValidationError("start date must be before end date") total_sold = 0 - # calculate reservation start before start_date and reservation end after start date - current_sold = frappe.db.get_values(doctype="Inn Room Booking", filters={"start": ["<", start_date], "end": [ - ">", start_date], "room_availability": "Room Sold"}, fieldname=["start", "end"], as_dict=True) + # Calculate reservations that start before start_date and end after start_date + current_sold = frappe.db.get_values( + doctype="Inn Room Booking", + filters={"start": ["<", start_date], "end": [">", start_date], "room_availability": "Room Sold"}, + fieldname=["start", "end"], + as_dict=True, + ) for ii in current_sold: room_end_date = ii.end if room_end_date > end_date: @@ -61,9 +77,14 @@ def count_sold_room(start_date=None, end_date=None): days_sold = (room_end_date - start_date).days total_sold += days_sold - # calculate reservation start after start_date and reservations start before before_date - current_sold = frappe.db.get_values(doctype="Inn Room Booking", filters=[["start", "between", [start_date, end_date]], [ - "room_availability", "=", "Room Sold"]], fieldname=["start", "end"], as_dict=True) + + # Calculate reservations that start after start_date and before end_date + current_sold = frappe.db.get_values( + doctype="Inn Room Booking", + filters=[["start", "between", [start_date, end_date]], ["room_availability", "=", "Room Sold"]], + fieldname=["start", "end"], + as_dict=True, + ) for ii in current_sold: room_start_date = ii.start room_end_date = ii.end @@ -81,187 +102,188 @@ def count_sold_room(start_date=None, end_date=None): @frappe.whitelist() def count_available_room(start_date=None, end_date=None): - if start_date == None and end_date == None: + if start_date is None and end_date is None: start_date = date.today().isoformat() - end_date = date.today() + timedelta(days=1) - end_date = end_date.isoformat() + end_date = (date.today() + timedelta(days=1)).isoformat() default_availability = frappe.db.count("Inn Room") try: start_date = parse(start_date, False).date() except ValueError: - raise frappe.ValidationError("{start_date} is not a valid date string") + raise frappe.ValidationError(f"{start_date} is not a valid date string") try: end_date = parse(end_date, False).date() except ValueError: - raise frappe.ValidationError("{end_date} is not a valid date string") + raise frappe.ValidationError(f"{end_date} is not a valid date string") delta = end_date - start_date if delta.days < 0: - raise frappe.ValidationError("start date must before end date") + raise frappe.ValidationError("start date must be before end date") all_room = default_availability * delta.days - total_sold = 0 - # calculate reservation start before start_date and reservation end after start date - current_used = frappe.db.get_values(doctype="Inn Room Booking", filters={"start": ["<", start_date], "end": [ - ">", start_date], "status": ["!=", "Finished"]}, fieldname=["start", "end"], as_dict=True) - for ii in current_used: - room_end_date = ii.end - if room_end_date > end_date: - room_end_date = end_date + # Calculate reservations that start before start_date and end after start_date + current_used = frappe.db.get_values( + doctype="Inn Room Booking", + filters={"start": ["<", start_date], "end": [">", start_date], "status": ["!=", "Finished"]}, + fieldname=["start", "end"], + as_dict=True, + ) + for item in current_used: + room_end_date = item.end if item.end <= end_date else end_date days_sold = (room_end_date - start_date).days total_sold += days_sold - # calculate reservation start after start_date and reservations start before before_date - current_used = frappe.db.get_values(doctype="Inn Room Booking", filters=[["start", "between", [ - start_date, end_date]], ["status", "!=", "Finished"]], fieldname=["start", "end"], as_dict=True) - for ii in current_used: - room_start_date = ii.start - room_end_date = ii.end - if room_end_date > end_date: - room_end_date = end_date - + # Calculate reservations that start after start_date and before end_date + current_used = frappe.db.get_values( + doctype="Inn Room Booking", + filters=[["start", "between", [start_date, end_date]], ["status", "!=", "Finished"]], + fieldname=["start", "end"], + as_dict=True, + ) + for item in current_used: + room_start_date = item.start + room_end_date = item.end if item.end <= end_date else end_date days_sold = (room_end_date - room_start_date).days total_sold += days_sold - return { - "value": all_room - total_sold, - "fieldtype": "Int" - } + return {"value": all_room - total_sold, "fieldtype": "Int"} @frappe.whitelist() def count_ooo_room(start_date=None, end_date=None): - if start_date == None and end_date == None: + if start_date is None and end_date is None: start_date = date.today().isoformat() - end_date = date.today() + timedelta(days=1) - end_date = end_date.isoformat() + end_date = (date.today() + timedelta(days=1)).isoformat() try: start_date = parse(start_date, False).date() except ValueError: - raise frappe.ValidationError("{start_date} is not a valid date string") + raise frappe.ValidationError(f"{start_date} is not a valid date string") try: end_date = parse(end_date, False).date() except ValueError: - raise frappe.ValidationError("{end_date} is not a valid date string") + raise frappe.ValidationError(f"{end_date} is not a valid date string") delta = end_date - start_date if delta.days < 0: - raise frappe.ValidationError("start date must before end date") + raise frappe.ValidationError("start date must be before end date") total_sold = 0 - # calculate reservation start before start_date and reservation end after start date - current_ooo = frappe.db.get_values(doctype="Inn Room Booking", filters={"start": ["<", start_date], "end": [ - ">", start_date], "room_availability": "Out of Order", "status": ["!=", "Finished"]}, fieldname=["start", "end"], as_dict=True) - for ii in current_ooo: - room_end_date = ii.end - if room_end_date > end_date: - room_end_date = end_date - + # Calculate reservations that start before start_date and end after start_date + current_ooo = frappe.db.get_values( + doctype="Inn Room Booking", + filters={"start": ["<", start_date], "end": [">", start_date], "room_availability": "Out of Order", "status": ["!=", "Finished"]}, + fieldname=["start", "end"], + as_dict=True, + ) + for item in current_ooo: + room_end_date = item.end if item.end <= end_date else end_date days_sold = (room_end_date - start_date).days total_sold += days_sold - # calculate reservation start after start_date and reservations start before before_date - current_ooo = frappe.db.get_values(doctype="Inn Room Booking", filters=[["start", "between", [start_date, end_date]], [ - "room_availability", "=", "Out of Order"], ["status", "!=", "Finished"]], fieldname=["start", "end"], as_dict=True) - for ii in current_ooo: - room_start_date = ii.start - room_end_date = ii.end - if room_end_date > end_date: - room_end_date = end_date - + # Calculate reservations that start after start_date and before end_date + current_ooo = frappe.db.get_values( + doctype="Inn Room Booking", + filters=[["start", "between", [start_date, end_date]], ["room_availability", "=", "Out of Order"], ["status", "!=", "Finished"]], + fieldname=["start", "end"], + as_dict=True, + ) + for item in current_ooo: + room_start_date = item.start + room_end_date = item.end if item.end <= end_date else end_date days_sold = (room_end_date - room_start_date).days total_sold += days_sold - return { - "value": total_sold, - "fieldtype": "Int" - } + return {"value": total_sold, "fieldtype": "Int"} def calculate_total_rate_and_sold(start_date, end_date): from frappe.utils import now_datetime + try: start_date = parse(start_date, False).date() except ValueError: - raise frappe.ValidationError("{start_date} is not a valid date string") + raise frappe.ValidationError(f"{start_date} is not a valid date string") try: end_date = parse(end_date, False).date() except ValueError: - raise frappe.ValidationError("{end_date} is not a valid date string") + raise frappe.ValidationError(f"{end_date} is not a valid date string") delta = end_date - start_date if delta.days < 0: - raise frappe.ValidationError("start date must before end date") - - # total_sold = 0 - # total_rate = 0 - # cached_rate = {} - # get today because today charge is not yet posted - get_today = False - if start_date <= now_datetime().date() < end_date: - get_today = True - - transaction_type = ('Breakfast Charge Tax/Service', - 'Breakfast Charge', 'Room Charge', 'Room Charge Tax/Service') - reservation_query = f''' - select tif.name as folio_id - from `tabInn Reservation` as ir - left join `tabInn Folio` as tif - on tif.reservation_id = ir.name - where - (ir.arrival <= '{start_date}' and ir.expected_departure > '{start_date}') or - (ir.expected_arrival >= '{start_date}' and ir.expected_arrival < '{end_date}') - ''' - - folio_id = frappe.db.sql(reservation_query, as_dict=1) - folio_id = tuple([x.folio_id for x in folio_id]) - if len(folio_id) == 0: - # so no need to parse further - folio_id = tuple(["", ""]) - - transaction_query = f''' - select sum(amount) as total - from `tabInn Folio Transaction` - where audit_date < '{end_date}' and audit_date >= '{start_date}' - and parent in {folio_id} - and transaction_type in {transaction_type} - ''' - total = frappe.db.sql(transaction_query, as_dict=1)[0] - if total.total is None: - total.total = 0 - - count_query = f''' - select count(*) as count - from `tabInn Folio Transaction` - where audit_date < '{end_date}' and audit_date >= '{start_date}' - and parent in {folio_id} - and transaction_type = 'Room Charge' - ''' - count = frappe.db.sql(count_query, as_dict=1)[0] - + raise frappe.ValidationError("start date must be before end date") + + # Fetch transaction types dynamically + transaction_types = get_transaction_types() + transaction_type_list = tuple(filter(None, [ + transaction_types["room_charge_tax_service"], + transaction_types["breakfast_charge_tax_service"], + transaction_types["room_charge"], + transaction_types["breakfast_charge"], + ])) + + if not transaction_type_list: + return 0, 0 + + # Check if today's charges need to be included + get_today = start_date <= now_datetime().date() < end_date + + # Query to fetch folio IDs for reservations within the date range + reservation_query = f""" + SELECT tif.name AS folio_id + FROM `tabInn Reservation` AS ir + LEFT JOIN `tabInn Folio` AS tif + ON tif.reservation_id = ir.name + WHERE + (ir.arrival <= '{start_date}' AND ir.expected_departure > '{start_date}') OR + (ir.expected_arrival >= '{start_date}' AND ir.expected_arrival < '{end_date}') + """ + folio_ids = frappe.db.sql(reservation_query, as_dict=True) + folio_ids = tuple([x.folio_id for x in folio_ids]) if folio_ids else ("0", "0") + + if not folio_ids: + return 0, 0 + + # Query to calculate total revenue from transactions + transaction_query = f""" + SELECT SUM(amount) AS total + FROM `tabInn Folio Transaction` + WHERE audit_date < '{end_date}' AND audit_date >= '{start_date}' + AND parent IN {folio_ids} + AND transaction_type IN {transaction_type_list} + """ + total = frappe.db.sql(transaction_query, as_dict=True)[0] + total_revenue = total.total if total.total is not None else 0 + + # Query to count the number of room charges + count_query = f""" + SELECT COUNT(*) AS count + FROM `tabInn Folio Transaction` + WHERE audit_date < '{end_date}' AND audit_date >= '{start_date}' + AND parent IN {folio_ids} + AND transaction_type = '{transaction_types["room_charge"]}' + """ + count = frappe.db.sql(count_query, as_dict=True)[0] + + # Include today's charges if applicable if get_today: - today_query = f''' - select sum(actual_room_rate) as total, count(*) as count - from `tabInn Reservation` ir - where ir.status = 'In House' and ir.expected_arrival <= '{start_date}' - ''' - today = frappe.db.sql(today_query, as_dict=1) - today = today[0] - if today.total is None: - today.total = 0 - total.total += today.total + today_query = f""" + SELECT SUM(actual_room_rate) AS total, COUNT(*) AS count + FROM `tabInn Reservation` ir + WHERE ir.status = 'In House' AND ir.expected_arrival <= '{start_date}' + """ + today = frappe.db.sql(today_query, as_dict=True)[0] + total_revenue += today.total if today.total is not None else 0 count.count += today.count - return total.total, count.count + return total_revenue, count.count - # # calculate reservation start before start_date and reservation end after start date + # # calculate reservation start before start_date and reservation end after start date # current_sold = frappe.db.get_values(doctype="Inn Reservation", filters={"arrival": ["<", start_date], "expected_departure": [ # ">", start_date]}, fieldname=["name", "arrival", "expected_departure", "room_rate"], as_dict=True) # reservation_id = [x.name for x in current_sold] @@ -301,6 +323,8 @@ def calculate_total_rate_and_sold(start_date, end_date): # return total_rate, total_sold + + @frappe.whitelist() def calculate_average_rate(start_date=None, end_date=None): if start_date == None and end_date == None: diff --git a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py index 67056456..9b73c648 100644 --- a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py +++ b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py @@ -1,7 +1,3 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2020, Core Initiative and contributors -# For license information, please see license.txt - from __future__ import unicode_literals import json diff --git a/inn/inn_hotels/doctype/inn_shift/inn_shift.py b/inn/inn_hotels/doctype/inn_shift/inn_shift.py index a59172e6..46a6a44c 100644 --- a/inn/inn_hotels/doctype/inn_shift/inn_shift.py +++ b/inn/inn_hotels/doctype/inn_shift/inn_shift.py @@ -11,485 +11,515 @@ from frappe.model.document import Document class InnShift(Document): - def before_insert(self): - self.status = "Open" + def before_insert(self): + self.status = "Open" @frappe.whitelist() def is_there_open_shift(): - if frappe.get_all('Inn Shift', {'status': 'Open'}): - return 1 - else: - return 2 + if frappe.get_all('Inn Shift', {'status': 'Open'}): + return 1 + else: + return 2 def get_last_closed_shift(): - d = frappe.get_all('Inn Shift', filters={'status': 'Closed'}, order_by='creation desc', limit_page_length=1) - if d: - return frappe.get_doc('Inn Shift', d[0].name) - else: - return None + d = frappe.get_all('Inn Shift', filters={'status': 'Closed'}, order_by='creation desc', limit_page_length=1) + if d: + return frappe.get_doc('Inn Shift', d[0].name) + else: + return None @frappe.whitelist() def populate_cr_payment(shift_id): - returned_cr_payment_detail_list = [] - cr_payment_detail_list = [] - transaction_list = [] - list_of_payment_type = ['Deposit', 'DP Kamar', 'Room Payment', 'Down Payment', 'Payment'] - mode_of_payment = frappe.get_all('Mode of Payment') - reservation_list = frappe.get_all('Inn Reservation', filters={'status': ['in', ['Reserved', 'In House', 'Finish', 'Cancel']]}, fields=['*']) - if shift_id: - last_shift = get_last_closed_shift() - if last_shift is None: - # Get Guest Folio Transaction type Payment that appear from the beginning - for reservation_item in reservation_list: - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'parent': folio_name, - 'transaction_type': ['in', list_of_payment_type], - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') - payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment - payment_detail_doc.amount = folio_trx_item.amount - cr_payment_detail_list.append(payment_detail_doc) - - payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') - payment_transaction_doc.type = folio_trx_item.transaction_type - payment_transaction_doc.transaction_id = folio_trx_item.name - payment_transaction_doc.reservation_id = reservation_item.name - payment_transaction_doc.folio_id = folio_name - payment_transaction_doc.customer_id = reservation_item.customer_id - payment_transaction_doc.account = folio_trx_item.debit_account - payment_transaction_doc.amount = folio_trx_item.amount - payment_transaction_doc.user = payment_transaction_doc.owner - transaction_list.append(payment_transaction_doc) - - # Get Master/Desk Folio transactions type Payment that appear from the beginning - master_desk_folio_list = frappe.get_all('Inn Folio', - filters={'type': ['in', ['Master', 'Desk']], - 'status': ['in', ['Open', 'Closed']]}, - fields=['*']) - for item in master_desk_folio_list: - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'parent': item.name, - 'transaction_type': ['in', list_of_payment_type], - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') - payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment - payment_detail_doc.amount = folio_trx_item.amount - cr_payment_detail_list.append(payment_detail_doc) - - payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') - payment_transaction_doc.type = folio_trx_item.transaction_type - payment_transaction_doc.transaction_id = folio_trx_item.name - payment_transaction_doc.folio_id = item.name - payment_transaction_doc.customer_id = item.customer_id - payment_transaction_doc.account = folio_trx_item.debit_account - payment_transaction_doc.amount = folio_trx_item.amount - payment_transaction_doc.user = payment_transaction_doc.owner - transaction_list.append(payment_transaction_doc) - - else: - # Get Guest Folio Transactions type Payment that appear since last shift - for reservation_item in reservation_list: - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'creation': ['>=', last_shift.time_out], - 'parent': folio_name, - 'transaction_type': ['in', list_of_payment_type], - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') - payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment - payment_detail_doc.amount = folio_trx_item.amount - cr_payment_detail_list.append(payment_detail_doc) - - payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') - payment_transaction_doc.type = folio_trx_item.transaction_type - payment_transaction_doc.transaction_id = folio_trx_item.name - payment_transaction_doc.reservation_id = reservation_item.name - payment_transaction_doc.folio_id = folio_name - payment_transaction_doc.customer_id = reservation_item.customer_id - payment_transaction_doc.account = folio_trx_item.debit_account - payment_transaction_doc.amount = folio_trx_item.amount - payment_transaction_doc.user = payment_transaction_doc.owner - transaction_list.append(payment_transaction_doc) - - # Get Master/Desk Folio transactions type Payment that appear since last shift - master_desk_folio_list = frappe.get_all('Inn Folio', - filters={'type': ['in', ['Master', 'Desk']], - 'status': ['in', ['Open', 'Closed']]}, - fields=['*']) - for item in master_desk_folio_list: - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'creation': ['>=', last_shift.time_out], - 'parent': item.name, - 'transaction_type': ['in', list_of_payment_type], - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') - payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment - payment_detail_doc.amount = folio_trx_item.amount - cr_payment_detail_list.append(payment_detail_doc) - - payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') - payment_transaction_doc.type = folio_trx_item.transaction_type - payment_transaction_doc.transaction_id = folio_trx_item.name - payment_transaction_doc.folio_id = item.name - payment_transaction_doc.customer_id = item.customer_id - payment_transaction_doc.account = folio_trx_item.debit_account - payment_transaction_doc.amount = folio_trx_item.amount - payment_transaction_doc.user = payment_transaction_doc.owner - transaction_list.append(payment_transaction_doc) - else: - if len(frappe.get_all('Inn Shift')) > 0: - last_shift = get_last_closed_shift() - # Get Guest Folio Transactions type Payment that appear since last shift - for reservation_item in reservation_list: - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'creation': ['>=', last_shift.time_out], - 'parent': folio_name, - 'transaction_type': ['in', list_of_payment_type], - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') - payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment - payment_detail_doc.amount = folio_trx_item.amount - cr_payment_detail_list.append(payment_detail_doc) - - payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') - payment_transaction_doc.type = folio_trx_item.transaction_type - payment_transaction_doc.transaction_id = folio_trx_item.name - payment_transaction_doc.reservation_id = reservation_item.name - payment_transaction_doc.folio_id = folio_name - payment_transaction_doc.customer_id = reservation_item.customer_id - payment_transaction_doc.account = folio_trx_item.debit_account - payment_transaction_doc.amount = folio_trx_item.amount - payment_transaction_doc.user = payment_transaction_doc.owner - transaction_list.append(payment_transaction_doc) - - # Get Master/Desk Folio transactions type Payment that appear since last shift - master_desk_folio_list = frappe.get_all('Inn Folio', - filters={'type': ['in', ['Master', 'Desk']], - 'status': ['in', ['Open', 'Closed']]}, - fields=['*']) - for item in master_desk_folio_list: - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'creation': ['>=', last_shift.time_out], - 'parent': item.name, - 'transaction_type': ['in', list_of_payment_type], - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') - payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment - payment_detail_doc.amount = folio_trx_item.amount - cr_payment_detail_list.append(payment_detail_doc) - - payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') - payment_transaction_doc.type = folio_trx_item.transaction_type - payment_transaction_doc.transaction_id = folio_trx_item.name - payment_transaction_doc.folio_id = item.name - payment_transaction_doc.customer_id = item.customer_id - payment_transaction_doc.account = folio_trx_item.debit_account - payment_transaction_doc.amount = folio_trx_item.amount - payment_transaction_doc.user = payment_transaction_doc.owner - transaction_list.append(payment_transaction_doc) - - else: - # Get Guest Folio Transaction type Payment that appear from the beginning - for reservation_item in reservation_list: - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'parent': folio_name, - 'transaction_type': ['in', list_of_payment_type], - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') - payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment - payment_detail_doc.amount = folio_trx_item.amount - cr_payment_detail_list.append(payment_detail_doc) - - payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') - payment_transaction_doc.type = folio_trx_item.transaction_type - payment_transaction_doc.transaction_id = folio_trx_item.name - payment_transaction_doc.reservation_id = reservation_item.name - payment_transaction_doc.folio_id = folio_name - payment_transaction_doc.customer_id = reservation_item.customer_id - payment_transaction_doc.account = folio_trx_item.debit_account - payment_transaction_doc.amount = folio_trx_item.amount - payment_transaction_doc.user = payment_transaction_doc.owner - transaction_list.append(payment_transaction_doc) - - # Get Master/Desk Folio transactions type Payment that appear from the beginning - master_desk_folio_list = frappe.get_all('Inn Folio', - filters={'type': ['in', ['Master', 'Desk']], - 'status': ['in', ['Open', 'Closed']]}, - fields=['*']) - for item in master_desk_folio_list: - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'parent': item.name, - 'transaction_type': ['in', list_of_payment_type], - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') - payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment - payment_detail_doc.amount = folio_trx_item.amount - cr_payment_detail_list.append(payment_detail_doc) - - payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') - payment_transaction_doc.type = folio_trx_item.transaction_type - payment_transaction_doc.transaction_id = folio_trx_item.name - payment_transaction_doc.folio_id = item.name - payment_transaction_doc.customer_id = item.customer_id - payment_transaction_doc.account = folio_trx_item.debit_account - payment_transaction_doc.amount = folio_trx_item.amount - payment_transaction_doc.user = payment_transaction_doc.owner - transaction_list.append(payment_transaction_doc) - - for mode_of_payment_item in mode_of_payment: - new_payment_detail = frappe.new_doc('Inn CR Payment Detail') - new_payment_detail.mode_of_payment = mode_of_payment_item.name - new_payment_detail.amount = 0 - for cr_payment_detail_item in cr_payment_detail_list: - if cr_payment_detail_item.mode_of_payment == new_payment_detail.mode_of_payment: - new_payment_detail.amount += float(cr_payment_detail_item.amount) - if new_payment_detail.amount > 0: - returned_cr_payment_detail_list.append(new_payment_detail) - - - return transaction_list, returned_cr_payment_detail_list + returned_cr_payment_detail_list = [] + cr_payment_detail_list = [] + transaction_list = [] + + # Fetch transaction types from Inn Hotels Setting + hotel_settings = frappe.get_doc("Inn Hotels Setting") + list_of_payment_type = [ + hotel_settings.room_charge_tax_service, + hotel_settings.breakfast_charge_tax_service, + hotel_settings.credit_card_administration_fee, + hotel_settings.package, + hotel_settings.room_charge, + hotel_settings.breakfast_charge, + hotel_settings.refund, + hotel_settings.dp_kamar, + hotel_settings.room_payment, + hotel_settings.deposit, + hotel_settings.down_payment, + hotel_settings.payment, + hotel_settings.additional_charge, + hotel_settings.restaurant_food, + hotel_settings.restaurant_beverages, + hotel_settings.restaurant_other, + hotel_settings.room_service_food, + hotel_settings.room_service_beverage, + hotel_settings.fbs_service_10, + hotel_settings.fbs_tax_11, + hotel_settings.round_off, + hotel_settings.laundry, + hotel_settings.cancellation_fee, + hotel_settings.late_checkout, + hotel_settings.early_checkin, + ] + + mode_of_payment = frappe.get_all('Mode of Payment') + reservation_list = frappe.get_all('Inn Reservation', filters={'status': ['in', ['Reserved', 'In House', 'Finish', 'Cancel']]}, fields=['*']) + + if shift_id: + last_shift = get_last_closed_shift() + if last_shift is None: + # Get Guest Folio Transaction type Payment that appear from the beginning + for reservation_item in reservation_list: + folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'parent': folio_name, + 'transaction_type': ['in', list_of_payment_type], + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') + payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment + payment_detail_doc.amount = folio_trx_item.amount + cr_payment_detail_list.append(payment_detail_doc) + + payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') + payment_transaction_doc.type = folio_trx_item.transaction_type + payment_transaction_doc.transaction_id = folio_trx_item.name + payment_transaction_doc.reservation_id = reservation_item.name + payment_transaction_doc.folio_id = folio_name + payment_transaction_doc.customer_id = reservation_item.customer_id + payment_transaction_doc.account = folio_trx_item.debit_account + payment_transaction_doc.amount = folio_trx_item.amount + payment_transaction_doc.user = payment_transaction_doc.owner + transaction_list.append(payment_transaction_doc) + + # Get Master/Desk Folio transactions type Payment that appear from the beginning + master_desk_folio_list = frappe.get_all('Inn Folio', + filters={'type': ['in', ['Master', 'Desk']], + 'status': ['in', ['Open', 'Closed']]}, + fields=['*']) + for item in master_desk_folio_list: + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'parent': item.name, + 'transaction_type': ['in', list_of_payment_type], + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') + payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment + payment_detail_doc.amount = folio_trx_item.amount + cr_payment_detail_list.append(payment_detail_doc) + + payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') + payment_transaction_doc.type = folio_trx_item.transaction_type + payment_transaction_doc.transaction_id = folio_trx_item.name + payment_transaction_doc.folio_id = item.name + payment_transaction_doc.customer_id = item.customer_id + payment_transaction_doc.account = folio_trx_item.debit_account + payment_transaction_doc.amount = folio_trx_item.amount + payment_transaction_doc.user = payment_transaction_doc.owner + transaction_list.append(payment_transaction_doc) + + else: + # Get Guest Folio Transactions type Payment that appear since last shift + for reservation_item in reservation_list: + folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'creation': ['>=', last_shift.time_out], + 'parent': folio_name, + 'transaction_type': ['in', list_of_payment_type], + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') + payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment + payment_detail_doc.amount = folio_trx_item.amount + cr_payment_detail_list.append(payment_detail_doc) + + payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') + payment_transaction_doc.type = folio_trx_item.transaction_type + payment_transaction_doc.transaction_id = folio_trx_item.name + payment_transaction_doc.reservation_id = reservation_item.name + payment_transaction_doc.folio_id = folio_name + payment_transaction_doc.customer_id = reservation_item.customer_id + payment_transaction_doc.account = folio_trx_item.debit_account + payment_transaction_doc.amount = folio_trx_item.amount + payment_transaction_doc.user = payment_transaction_doc.owner + transaction_list.append(payment_transaction_doc) + + # Get Master/Desk Folio transactions type Payment that appear since last shift + master_desk_folio_list = frappe.get_all('Inn Folio', + filters={'type': ['in', ['Master', 'Desk']], + 'status': ['in', ['Open', 'Closed']]}, + fields=['*']) + for item in master_desk_folio_list: + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'creation': ['>=', last_shift.time_out], + 'parent': item.name, + 'transaction_type': ['in', list_of_payment_type], + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') + payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment + payment_detail_doc.amount = folio_trx_item.amount + cr_payment_detail_list.append(payment_detail_doc) + + payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') + payment_transaction_doc.type = folio_trx_item.transaction_type + payment_transaction_doc.transaction_id = folio_trx_item.name + payment_transaction_doc.folio_id = item.name + payment_transaction_doc.customer_id = item.customer_id + payment_transaction_doc.account = folio_trx_item.debit_account + payment_transaction_doc.amount = folio_trx_item.amount + payment_transaction_doc.user = payment_transaction_doc.owner + transaction_list.append(payment_transaction_doc) + else: + if len(frappe.get_all('Inn Shift')) > 0: + last_shift = get_last_closed_shift() + # Get Guest Folio Transactions type Payment that appear since last shift + for reservation_item in reservation_list: + folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'creation': ['>=', last_shift.time_out], + 'parent': folio_name, + 'transaction_type': ['in', list_of_payment_type], + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') + payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment + payment_detail_doc.amount = folio_trx_item.amount + cr_payment_detail_list.append(payment_detail_doc) + + payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') + payment_transaction_doc.type = folio_trx_item.transaction_type + payment_transaction_doc.transaction_id = folio_trx_item.name + payment_transaction_doc.reservation_id = reservation_item.name + payment_transaction_doc.folio_id = folio_name + payment_transaction_doc.customer_id = reservation_item.customer_id + payment_transaction_doc.account = folio_trx_item.debit_account + payment_transaction_doc.amount = folio_trx_item.amount + payment_transaction_doc.user = payment_transaction_doc.owner + transaction_list.append(payment_transaction_doc) + + # Get Master/Desk Folio transactions type Payment that appear since last shift + master_desk_folio_list = frappe.get_all('Inn Folio', + filters={'type': ['in', ['Master', 'Desk']], + 'status': ['in', ['Open', 'Closed']]}, + fields=['*']) + for item in master_desk_folio_list: + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'creation': ['>=', last_shift.time_out], + 'parent': item.name, + 'transaction_type': ['in', list_of_payment_type], + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') + payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment + payment_detail_doc.amount = folio_trx_item.amount + cr_payment_detail_list.append(payment_detail_doc) + + payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') + payment_transaction_doc.type = folio_trx_item.transaction_type + payment_transaction_doc.transaction_id = folio_trx_item.name + payment_transaction_doc.folio_id = item.name + payment_transaction_doc.customer_id = item.customer_id + payment_transaction_doc.account = folio_trx_item.debit_account + payment_transaction_doc.amount = folio_trx_item.amount + payment_transaction_doc.user = payment_transaction_doc.owner + transaction_list.append(payment_transaction_doc) + + else: + # Get Guest Folio Transaction type Payment that appear from the beginning + for reservation_item in reservation_list: + folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'parent': folio_name, + 'transaction_type': ['in', list_of_payment_type], + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') + payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment + payment_detail_doc.amount = folio_trx_item.amount + cr_payment_detail_list.append(payment_detail_doc) + + payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') + payment_transaction_doc.type = folio_trx_item.transaction_type + payment_transaction_doc.transaction_id = folio_trx_item.name + payment_transaction_doc.reservation_id = reservation_item.name + payment_transaction_doc.folio_id = folio_name + payment_transaction_doc.customer_id = reservation_item.customer_id + payment_transaction_doc.account = folio_trx_item.debit_account + payment_transaction_doc.amount = folio_trx_item.amount + payment_transaction_doc.user = payment_transaction_doc.owner + transaction_list.append(payment_transaction_doc) + + # Get Master/Desk Folio transactions type Payment that appear from the beginning + master_desk_folio_list = frappe.get_all('Inn Folio', + filters={'type': ['in', ['Master', 'Desk']], + 'status': ['in', ['Open', 'Closed']]}, + fields=['*']) + for item in master_desk_folio_list: + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'parent': item.name, + 'transaction_type': ['in', list_of_payment_type], + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + payment_detail_doc = frappe.new_doc('Inn CR Payment Detail') + payment_detail_doc.mode_of_payment = folio_trx_item.mode_of_payment + payment_detail_doc.amount = folio_trx_item.amount + cr_payment_detail_list.append(payment_detail_doc) + + payment_transaction_doc = frappe.new_doc('Inn CR Payment Transaction') + payment_transaction_doc.type = folio_trx_item.transaction_type + payment_transaction_doc.transaction_id = folio_trx_item.name + payment_transaction_doc.folio_id = item.name + payment_transaction_doc.customer_id = item.customer_id + payment_transaction_doc.account = folio_trx_item.debit_account + payment_transaction_doc.amount = folio_trx_item.amount + payment_transaction_doc.user = payment_transaction_doc.owner + transaction_list.append(payment_transaction_doc) + + for mode_of_payment_item in mode_of_payment: + new_payment_detail = frappe.new_doc('Inn CR Payment Detail') + new_payment_detail.mode_of_payment = mode_of_payment_item.name + new_payment_detail.amount = 0 + for cr_payment_detail_item in cr_payment_detail_list: + if cr_payment_detail_item.mode_of_payment == new_payment_detail.mode_of_payment: + new_payment_detail.amount += float(cr_payment_detail_item.amount) + if new_payment_detail.amount > 0: + returned_cr_payment_detail_list.append(new_payment_detail) + + return transaction_list, returned_cr_payment_detail_list @frappe.whitelist() def populate_cr_refund(shift_id): - returned_cr_refund_detail_list = [] - transaction_list = [] - cr_refund = frappe.new_doc('Inn CR Refund Detail') - cr_refund.type = 'Refund' - cr_refund.amount = 0 - reservation_list = frappe.get_all('Inn Reservation', filters={'status': ['in', ['In House', 'Finish', 'Cancel']]}, - fields=['*']) - - if shift_id: - last_shift = get_last_closed_shift() - if last_shift is None: - # Get all Guest Folio Transactions Refund that appear from beginning - for reservation_item in reservation_list: - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'transaction_type': 'Refund', - 'parent': folio_name, - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - cr_refund.amount += folio_trx_item.amount - - refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') - refund_detail_doc.type = folio_trx_item.transaction_type - refund_detail_doc.transaction_id = folio_trx_item.name - refund_detail_doc.reservation_id = reservation_item.name - refund_detail_doc.folio_id = folio_name - refund_detail_doc.customer_id = reservation_item.customer_id - refund_detail_doc.account = folio_trx_item.credit_account - refund_detail_doc.amount = folio_trx_item.amount - refund_detail_doc.user = refund_detail_doc.owner - transaction_list.append(refund_detail_doc) - - # Get all Master/Desk Folio Transactions Refund that appear from beginning - master_desk_folio_list = frappe.get_all('Inn Folio', - filters={'type': ['in', ['Master', 'Desk']], - 'status': ['in', ['Open', 'Closed']]}, - fields=['*']) - for item in master_desk_folio_list: - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'transaction_type': 'Refund', - 'parent': item.name, - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - cr_refund.amount += folio_trx_item.amount - - refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') - refund_detail_doc.type = folio_trx_item.transaction_type - refund_detail_doc.transaction_id = folio_trx_item.name - refund_detail_doc.folio_id = item.name - refund_detail_doc.customer_id = item.customer_id - refund_detail_doc.account = folio_trx_item.credit_account - refund_detail_doc.amount = folio_trx_item.amount - refund_detail_doc.user = refund_detail_doc.owner - transaction_list.append(refund_detail_doc) - - else: - # Get all Guest Folio Transactions Refund that appear since last shift - for reservation_item in reservation_list: - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'transaction_type': 'Refund', - 'creation': ['>=', last_shift.time_out], - 'parent': folio_name, - 'flag': 'Debit', - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - cr_refund.amount += folio_trx_item.amount - - refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') - refund_detail_doc.type = folio_trx_item.transaction_type - refund_detail_doc.transaction_id = folio_trx_item.name - refund_detail_doc.reservation_id = reservation_item.name - refund_detail_doc.folio_id = folio_name - refund_detail_doc.customer_id = reservation_item.customer_id - refund_detail_doc.account = folio_trx_item.credit_account - refund_detail_doc.amount = folio_trx_item.amount - refund_detail_doc.user = refund_detail_doc.owner - transaction_list.append(refund_detail_doc) - - # Get all Master/Desk Folio Transactions Refund that appear since last shift - master_desk_folio_list = frappe.get_all('Inn Folio', - filters={'type': ['in', ['Master', 'Desk']], - 'status': ['in', ['Open', 'Closed']]}, - fields=['*']) - for item in master_desk_folio_list: - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'transaction_type': 'Refund', - 'creation': ['>=', last_shift.time_out], - 'parent': item.name, - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - cr_refund.amount += folio_trx_item.amount - - refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') - refund_detail_doc.type = folio_trx_item.transaction_type - refund_detail_doc.transaction_id = folio_trx_item.name - refund_detail_doc.folio_id = item.name - refund_detail_doc.customer_id = item.customer_id - refund_detail_doc.account = folio_trx_item.credit_account - refund_detail_doc.amount = folio_trx_item.amount - refund_detail_doc.user = refund_detail_doc.owner - transaction_list.append(refund_detail_doc) - else: - if len(frappe.get_all('Inn Shift')) > 0: - last_shift = get_last_closed_shift() - # Get all Guest Folio Transactions Refund that appear since last shift - for reservation_item in reservation_list: - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'transaction_type': 'Refund', - 'creation': ['>=', last_shift.time_out], - 'parent': folio_name, - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - cr_refund.amount += folio_trx_item.amount - - refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') - refund_detail_doc.type = folio_trx_item.transaction_type - refund_detail_doc.transaction_id = folio_trx_item.name - refund_detail_doc.reservation_id = reservation_item.name - refund_detail_doc.folio_id = folio_name - refund_detail_doc.customer_id = reservation_item.customer_id - refund_detail_doc.account = folio_trx_item.credit_account - refund_detail_doc.amount = folio_trx_item.amount - refund_detail_doc.user = refund_detail_doc.owner - transaction_list.append(refund_detail_doc) - - # Get all Master/Desk Folio Transactions Refund that appear since last shift - master_desk_folio_list = frappe.get_all('Inn Folio', - filters={'type': ['in', ['Master', 'Desk']], - 'status': ['in', ['Open', 'Closed']]}, - fields=['*']) - for item in master_desk_folio_list: - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'transaction_type': 'Refund', - 'creation': ['>=', last_shift.time_out], - 'parent': item.name, - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - cr_refund.amount += folio_trx_item.amount - - refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') - refund_detail_doc.type = folio_trx_item.transaction_type - refund_detail_doc.transaction_id = folio_trx_item.name - refund_detail_doc.folio_id = item.name - refund_detail_doc.customer_id = item.customer_id - refund_detail_doc.account = folio_trx_item.credit_account - refund_detail_doc.amount = folio_trx_item.amount - refund_detail_doc.user = refund_detail_doc.owner - transaction_list.append(refund_detail_doc) - else: - # Get all Guest Folio Transactions Refund that appear from beginning - for reservation_item in reservation_list: - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'transaction_type': 'Refund', - 'parent': folio_name, - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - cr_refund.amount += folio_trx_item.amount - - refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') - refund_detail_doc.type = folio_trx_item.transaction_type - refund_detail_doc.transaction_id = folio_trx_item.name - refund_detail_doc.reservation_id = reservation_item.name - refund_detail_doc.folio_id = folio_name - refund_detail_doc.customer_id = reservation_item.customer_id - refund_detail_doc.account = folio_trx_item.credit_account - refund_detail_doc.amount = folio_trx_item.amount - refund_detail_doc.user = refund_detail_doc.owner - transaction_list.append(refund_detail_doc) - - # Get all Master/Desk Folio Transactions Refund that appear from beginning - master_desk_folio_list = frappe.get_all('Inn Folio', - filters={'type': ['in', ['Master', 'Desk']], - 'status': ['in', ['Open', 'Closed']]}, - fields=['*']) - for item in master_desk_folio_list: - folio_transaction_list = frappe.get_all('Inn Folio Transaction', - filters={'transaction_type': 'Refund', - 'parent': item.name, - 'is_void': 0}, - fields=['*']) - for folio_trx_item in folio_transaction_list: - cr_refund.amount += folio_trx_item.amount - - refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') - refund_detail_doc.type = folio_trx_item.transaction_type - refund_detail_doc.transaction_id = folio_trx_item.name - refund_detail_doc.folio_id = item.name - refund_detail_doc.customer_id = item.customer_id - refund_detail_doc.account = folio_trx_item.credit_account - refund_detail_doc.amount = folio_trx_item.amount - refund_detail_doc.user = refund_detail_doc.owner - transaction_list.append(refund_detail_doc) - - returned_cr_refund_detail_list.append(cr_refund) - - return transaction_list, returned_cr_refund_detail_list + returned_cr_refund_detail_list = [] + transaction_list = [] + cr_refund = frappe.new_doc('Inn CR Refund Detail') + cr_refund.type = 'Refund' + cr_refund.amount = 0 + reservation_list = frappe.get_all('Inn Reservation', filters={'status': ['in', ['In House', 'Finish', 'Cancel']]}, + fields=['*']) + + if shift_id: + last_shift = get_last_closed_shift() + if last_shift is None: + # Get all Guest Folio Transactions Refund that appear from beginning + for reservation_item in reservation_list: + folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'transaction_type': 'Refund', + 'parent': folio_name, + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + cr_refund.amount += folio_trx_item.amount + + refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') + refund_detail_doc.type = folio_trx_item.transaction_type + refund_detail_doc.transaction_id = folio_trx_item.name + refund_detail_doc.reservation_id = reservation_item.name + refund_detail_doc.folio_id = folio_name + refund_detail_doc.customer_id = reservation_item.customer_id + refund_detail_doc.account = folio_trx_item.credit_account + refund_detail_doc.amount = folio_trx_item.amount + refund_detail_doc.user = refund_detail_doc.owner + transaction_list.append(refund_detail_doc) + + # Get all Master/Desk Folio Transactions Refund that appear from beginning + master_desk_folio_list = frappe.get_all('Inn Folio', + filters={'type': ['in', ['Master', 'Desk']], + 'status': ['in', ['Open', 'Closed']]}, + fields=['*']) + for item in master_desk_folio_list: + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'transaction_type': 'Refund', + 'parent': item.name, + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + cr_refund.amount += folio_trx_item.amount + + refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') + refund_detail_doc.type = folio_trx_item.transaction_type + refund_detail_doc.transaction_id = folio_trx_item.name + refund_detail_doc.folio_id = item.name + refund_detail_doc.customer_id = item.customer_id + refund_detail_doc.account = folio_trx_item.credit_account + refund_detail_doc.amount = folio_trx_item.amount + refund_detail_doc.user = refund_detail_doc.owner + transaction_list.append(refund_detail_doc) + + else: + # Get all Guest Folio Transactions Refund that appear since last shift + for reservation_item in reservation_list: + folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'transaction_type': 'Refund', + 'creation': ['>=', last_shift.time_out], + 'parent': folio_name, + 'flag': 'Debit', + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + cr_refund.amount += folio_trx_item.amount + + refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') + refund_detail_doc.type = folio_trx_item.transaction_type + refund_detail_doc.transaction_id = folio_trx_item.name + refund_detail_doc.reservation_id = reservation_item.name + refund_detail_doc.folio_id = folio_name + refund_detail_doc.customer_id = reservation_item.customer_id + refund_detail_doc.account = folio_trx_item.credit_account + refund_detail_doc.amount = folio_trx_item.amount + refund_detail_doc.user = refund_detail_doc.owner + transaction_list.append(refund_detail_doc) + + # Get all Master/Desk Folio Transactions Refund that appear since last shift + master_desk_folio_list = frappe.get_all('Inn Folio', + filters={'type': ['in', ['Master', 'Desk']], + 'status': ['in', ['Open', 'Closed']]}, + fields=['*']) + for item in master_desk_folio_list: + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'transaction_type': 'Refund', + 'creation': ['>=', last_shift.time_out], + 'parent': item.name, + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + cr_refund.amount += folio_trx_item.amount + + refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') + refund_detail_doc.type = folio_trx_item.transaction_type + refund_detail_doc.transaction_id = folio_trx_item.name + refund_detail_doc.folio_id = item.name + refund_detail_doc.customer_id = item.customer_id + refund_detail_doc.account = folio_trx_item.credit_account + refund_detail_doc.amount = folio_trx_item.amount + refund_detail_doc.user = refund_detail_doc.owner + transaction_list.append(refund_detail_doc) + else: + if len(frappe.get_all('Inn Shift')) > 0: + last_shift = get_last_closed_shift() + # Get all Guest Folio Transactions Refund that appear since last shift + for reservation_item in reservation_list: + folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'transaction_type': 'Refund', + 'creation': ['>=', last_shift.time_out], + 'parent': folio_name, + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + cr_refund.amount += folio_trx_item.amount + + refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') + refund_detail_doc.type = folio_trx_item.transaction_type + refund_detail_doc.transaction_id = folio_trx_item.name + refund_detail_doc.reservation_id = reservation_item.name + refund_detail_doc.folio_id = folio_name + refund_detail_doc.customer_id = reservation_item.customer_id + refund_detail_doc.account = folio_trx_item.credit_account + refund_detail_doc.amount = folio_trx_item.amount + refund_detail_doc.user = refund_detail_doc.owner + transaction_list.append(refund_detail_doc) + + # Get all Master/Desk Folio Transactions Refund that appear since last shift + master_desk_folio_list = frappe.get_all('Inn Folio', + filters={'type': ['in', ['Master', 'Desk']], + 'status': ['in', ['Open', 'Closed']]}, + fields=['*']) + for item in master_desk_folio_list: + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'transaction_type': 'Refund', + 'creation': ['>=', last_shift.time_out], + 'parent': item.name, + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + cr_refund.amount += folio_trx_item.amount + + refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') + refund_detail_doc.type = folio_trx_item.transaction_type + refund_detail_doc.transaction_id = folio_trx_item.name + refund_detail_doc.folio_id = item.name + refund_detail_doc.customer_id = item.customer_id + refund_detail_doc.account = folio_trx_item.credit_account + refund_detail_doc.amount = folio_trx_item.amount + refund_detail_doc.user = refund_detail_doc.owner + transaction_list.append(refund_detail_doc) + else: + # Get all Guest Folio Transactions Refund that appear from beginning + for reservation_item in reservation_list: + folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_item.name}, ['name']) + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'transaction_type': 'Refund', + 'parent': folio_name, + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + cr_refund.amount += folio_trx_item.amount + + refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') + refund_detail_doc.type = folio_trx_item.transaction_type + refund_detail_doc.transaction_id = folio_trx_item.name + refund_detail_doc.reservation_id = reservation_item.name + refund_detail_doc.folio_id = folio_name + refund_detail_doc.customer_id = reservation_item.customer_id + refund_detail_doc.account = folio_trx_item.credit_account + refund_detail_doc.amount = folio_trx_item.amount + refund_detail_doc.user = refund_detail_doc.owner + transaction_list.append(refund_detail_doc) + + # Get all Master/Desk Folio Transactions Refund that appear from beginning + master_desk_folio_list = frappe.get_all('Inn Folio', + filters={'type': ['in', ['Master', 'Desk']], + 'status': ['in', ['Open', 'Closed']]}, + fields=['*']) + for item in master_desk_folio_list: + folio_transaction_list = frappe.get_all('Inn Folio Transaction', + filters={'transaction_type': 'Refund', + 'parent': item.name, + 'is_void': 0}, + fields=['*']) + for folio_trx_item in folio_transaction_list: + cr_refund.amount += folio_trx_item.amount + + refund_detail_doc = frappe.new_doc('Inn CR Refund Transaction') + refund_detail_doc.type = folio_trx_item.transaction_type + refund_detail_doc.transaction_id = folio_trx_item.name + refund_detail_doc.folio_id = item.name + refund_detail_doc.customer_id = item.customer_id + refund_detail_doc.account = folio_trx_item.credit_account + refund_detail_doc.amount = folio_trx_item.amount + refund_detail_doc.user = refund_detail_doc.owner + transaction_list.append(refund_detail_doc) + + returned_cr_refund_detail_list.append(cr_refund) + + return transaction_list, returned_cr_refund_detail_list @frappe.whitelist() def close_shift(shift_id): - doc = frappe.get_doc('Inn Shift', shift_id) - doc.time_out = now() - doc.username = frappe.session.user - doc.status = 'Closed' - doc.save() + doc = frappe.get_doc('Inn Shift', shift_id) + doc.time_out = now() + doc.username = frappe.session.user + doc.status = 'Closed' + doc.save() - if frappe.db.get_value('Inn Shift', {'name': shift_id}, ['status']) == 'Closed': - return True - else: - return False + if frappe.db.get_value('Inn Shift', {'name': shift_id}, ['status']) == 'Closed': + return True + else: + return False @frappe.whitelist() def get_max_opening_cash(): - return frappe.db.get_single_value('Inn Hotels Setting', 'max_opening') \ No newline at end of file + return frappe.db.get_single_value('Inn Hotels Setting', 'max_opening') \ No newline at end of file diff --git a/inn/inn_hotels/page/pos_extended/pos_extended.py b/inn/inn_hotels/page/pos_extended/pos_extended.py index 80837b2c..964c91dc 100644 --- a/inn/inn_hotels/page/pos_extended/pos_extended.py +++ b/inn/inn_hotels/page/pos_extended/pos_extended.py @@ -1,4 +1,3 @@ - import frappe from inn.inn_hotels.doctype.inn_tax.inn_tax import calculate_inn_tax_and_charges import json @@ -11,7 +10,7 @@ NEW_ORDER = 1 @frappe.whitelist() -def save_pos_usage(invoice_name, action, table = None): +def save_pos_usage(invoice_name, action, table=None): if action not in ["save_draft", "print_captain", "print_table", "save_submit"]: raise TypeError("argument error: action not found") @@ -33,7 +32,7 @@ def save_pos_usage(invoice_name, action, table = None): doc = frappe.get_last_doc("Inn POS Usage", filters={"pos_invoice": invoice_name}) # move table if doc.table != table: - if doc.table != "" and doc.table != None: + if doc.table != "" and doc.table is not None: doc_table = frappe.get_doc("Inn Point Of Sale Table", doc.table) doc_table.status = "Empty" doc_table.save() @@ -43,16 +42,16 @@ def save_pos_usage(invoice_name, action, table = None): doc_table = frappe.get_doc("Inn Point Of Sale Table", doc.table) doc_table.status = "Occupied" doc_table.save() - + # mainly change state except when flow repeated, will move tracked item to processed item and add new item to tracked item if action in ["save_draft", "print_captain"] and doc.print_status == PRINT_STATUS_TABLE and not new: - # case if customer want to add the order + # case if customer wants to add the order # then new item will be added to processed item # then new item will be empty to reset the tracked item items = doc.new_item doc.new_item = {} - new_item = {x.item_name : x for x in items} + new_item = {x.item_name: x for x in items} tracked_item = {x.item_name: x for x in doc.processed_item} for i in new_item: @@ -61,7 +60,7 @@ def save_pos_usage(invoice_name, action, table = None): else: tracked_item[i] = new_item[i] tracked_item[i].parentfield = "processed_item" - + tracked_item[i].save() doc.print_status = PRINT_STATUS_DRAFT @@ -78,18 +77,17 @@ def save_pos_usage(invoice_name, action, table = None): else: raise frappe.DataError("print error: status not match") - + if action in ["save_draft", "print_captain"]: # add untracked child - all_item = frappe.db.get_values(doctype="POS Invoice Item", filters={"parenttype":"POS Invoice", "parent":invoice_name}, fieldname=["item_name", "qty"], as_dict=True) + all_item = frappe.db.get_values(doctype="POS Invoice Item", filters={"parenttype": "POS Invoice", "parent": invoice_name}, fieldname=["item_name", "qty"], as_dict=True) - if not 'tracked_item' in locals(): + if 'tracked_item' not in locals(): tracked_item = {x.item_name: x for x in doc.processed_item} - + new_item_name = {item.item_name: item for item in doc.new_item} doc.save() - add_item = False for item in all_item: item_name = "" @@ -102,7 +100,7 @@ def save_pos_usage(invoice_name, action, table = None): quantity = diff else: - add_item = True + add_item = True item_name = item.item_name quantity = item.qty @@ -120,21 +118,16 @@ def save_pos_usage(invoice_name, action, table = None): new_item.parentfield = "new_item" new_item.insert() add_item = False - elif action in ["print_table", "save_submit"]: # no change. print table will use same data as print_captain doc.save() - pass - - return {"message": "success"} @frappe.whitelist() def get_table_number(invoice_name): - return frappe.db.get_value(doctype="Inn POS Usage", filters={"pos_invoice": invoice_name }, fieldname=["table", "transfer_to_folio"], as_dict=True) - + return frappe.db.get_value(doctype="Inn POS Usage", filters={"pos_invoice": invoice_name}, fieldname=["table", "transfer_to_folio"], as_dict=True) @frappe.whitelist() def clean_table_number(invoice_name): @@ -148,7 +141,6 @@ def clean_table_number(invoice_name): doc_table.save() return - @frappe.whitelist() def transfer_to_folio(invoice_doc, folio_name): invoice_doc = json.loads(invoice_doc) @@ -158,57 +150,64 @@ def transfer_to_folio(invoice_doc, folio_name): pos_usage = frappe.get_last_doc("Inn POS Usage", filters={"pos_invoice": invoice_doc["name"]}) pos_usage.transfer_to_folio = folio_name pos_usage.save() - + + # Fetch transaction types from Inn Hotels Setting + hotel_settings = frappe.get_doc("Inn Hotels Setting") + transaction_types = { + "restaurant_food": hotel_settings.restaurant_food, + "fbs_service_10": hotel_settings.fbs_service_10, + "fbs_tax_11": hotel_settings.fbs_tax_11, + "round_off": hotel_settings.round_off, + } + # Create Inn Folio Transaction Bundle ftb_doc = frappe.new_doc('Inn Folio Transaction Bundle') ftb_doc.transaction_type = 'Restaurant Transfer Charges' ftb_doc.insert() - idx = frappe.get_all('Inn Folio Transaction', filters={'parent': folio_name, 'parenttype': 'Inn Folio', 'parentfield': 'folio_transaction'}) idx = len(idx) - # create folio transaction restaurant charge + + # Create folio transaction restaurant charge food_remark = 'Transfer Restaurant Food Charges from POS Order: ' + invoice_doc["name"] - create_folio_trx(invoice_doc["name"], folio_name, invoice_doc["net_total"], "Restaurant Food", ftb_doc, food_remark, idx) + create_folio_trx(invoice_doc["name"], folio_name, invoice_doc["net_total"], transaction_types["restaurant_food"], ftb_doc, food_remark, idx) idx = idx + 1 - # create folio transaction restaurant tax 1 dst - guest_account_receiveable = frappe.db.get_single_value("Inn Hotels Setting", "guest_account_receiveable") + # Create folio transaction restaurant tax and service + guest_account_receivable = frappe.db.get_single_value("Inn Hotels Setting", "guest_account_receivable") + + # Dynamic tax types and remarks + tax_type = [transaction_types["fbs_service_10"], transaction_types["fbs_tax_11"]] + remarks = [ + 'Service of Transfer Restaurant Charges from POS Order: ' + invoice_doc["name"], + 'Tax of Transfer Restaurant Charges from POS Order: ' + invoice_doc["name"] + ] - # HARDCODED - # todo make dynamic - tax_type = ["FBS -- Service 10 %", "FBS -- Tax 11 %"] - remarks = ['Service of Transfer Restaurant Charges from POS Order: ' + invoice_doc["name"], - 'Tax of Transfer Restaurant Charges from POS Order: ' + invoice_doc["name"] - ] - if len(invoice_doc["taxes"]) == 1: - # if the tax is only one, its probably just a tax charge + # If the tax is only one, it's probably just a tax charge tax_type.pop(0) remarks.pop(0) - for ii in range(len(invoice_doc["taxes"])): taxe = invoice_doc["taxes"][ii] - create_folio_trx(invoice_doc["name"], folio_name, taxe["tax_amount_after_discount_amount"], tax_type[ii], ftb_doc, remarks[ii], idx, guest_account_receiveable, taxe["account_head"]) + create_folio_trx(invoice_doc["name"], folio_name, taxe["tax_amount_after_discount_amount"], tax_type[ii], ftb_doc, remarks[ii], idx, guest_account_receivable, taxe["account_head"]) idx = idx + 1 - + if "rounding_adjustment" in invoice_doc and invoice_doc["rounding_adjustment"] != 0: roundoff_remark = 'Rounding off Amount of Transfer Restaurant Charges from Restaurant Order: ' + invoice_doc["name"] - create_folio_trx(invoice_doc["name"], folio_name, invoice_doc["rounding_adjustment"], "Round Off", ftb_doc, roundoff_remark, idx, guest_account_receiveable) + create_folio_trx(invoice_doc["name"], folio_name, invoice_doc["rounding_adjustment"], transaction_types["round_off"], ftb_doc, roundoff_remark, idx, guest_account_receivable) ftb_doc.save() remove_pos_invoice_bill(invoice_doc["name"], folio_name) +def create_folio_trx(invoice_name, folio, amount, type, ftb_doc, remark, index, debit_account=None, credit_account=None): + if credit_account is None: + credit_account = frappe.get_value('Inn Folio Transaction Type', filters={"name": type}, fieldname="credit_account") + if debit_account is None: + debit_account = frappe.get_value('Inn Folio Transaction Type', filters={"name": type}, fieldname="debit_account") -def create_folio_trx(invoice_name, folio, amount, type, ftb_doc, remark, index, debit_account = None , credit_account = None): - if credit_account == None: - credit_account = frappe.get_value('Inn Folio Transaction Type', filters={"name": type}, fieldname = "credit_account") - if debit_account == None: - debit_account = frappe.get_value('Inn Folio Transaction Type', filters={"name": type}, fieldname = "debit_account") - - # Create Inn Folio Transaction + # Create Inn Folio Transaction new_doc = frappe.new_doc('Inn Folio Transaction') new_doc.flag = 'Debit' new_doc.is_void = 0 @@ -223,15 +222,15 @@ def create_folio_trx(invoice_name, folio, amount, type, ftb_doc, remark, index, new_doc.parenttype = 'Inn Folio' new_doc.parentfield = 'folio_transaction' new_doc.ftb_id = ftb_doc.name - new_doc.insert() - + new_doc.insert() + # Create Inn Folio Transaction Bundle Detail ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') ftbd_doc.transaction_type = new_doc.transaction_type ftbd_doc.transaction_id = new_doc.name ftb_doc.append('transaction_detail', ftbd_doc) -def remove_pos_invoice_bill(invoice_name : str, folio_name: str): +def remove_pos_invoice_bill(invoice_name: str, folio_name: str): pos_invoice = frappe.get_doc("POS Invoice", invoice_name) for payment in pos_invoice.payments: frappe.db.set_value("Sales Invoice Payment", payment.name, "amount", 0) @@ -243,4 +242,4 @@ def remove_pos_invoice_bill(invoice_name : str, folio_name: str): frappe.db.set_value("POS Invoice", invoice_name, "in_words", 0) frappe.db.set_value("POS Invoice", invoice_name, "paid_amount", 0) frappe.db.set_value("POS Invoice", invoice_name, "consolidated_invoice", f"Transferred to {folio_name}") - frappe.db.set_value("POS Invoice", invoice_name, "status", f"Consolidated") + frappe.db.set_value("POS Invoice", invoice_name, "status", "Consolidated") \ No newline at end of file diff --git a/inn/inn_hotels/report/audit_report/audit_report.py b/inn/inn_hotels/report/audit_report/audit_report.py index 2111f34d..19820594 100644 --- a/inn/inn_hotels/report/audit_report/audit_report.py +++ b/inn/inn_hotels/report/audit_report/audit_report.py @@ -1,5 +1,5 @@ import frappe -from datetime import date, timedelta +from datetime import date from dateutil.parser import parse FILTER_FIELD_DATE = "expected_arrival" @@ -34,7 +34,6 @@ ''' - def execute(filters=None): columns = [ { @@ -133,14 +132,12 @@ def execute(filters=None): return columns, data - def get_data(filters): - if filters.date == None: + if filters.date is None: filters.date = date.today().isoformat() return get_data_detail(filters.date, filters.fill_mode_payment) - def get_data_detail(start_date, is_show_mode_payment): query = f""" select ir.name, ir.status, ir.customer_id, ir.room_type, ir.actual_room_id, ir.channel, ir.actual_room_rate, if.name as folio, if.bill_instructions @@ -200,10 +197,8 @@ def get_data_detail(start_date, is_show_mode_payment): for x in reservation] return res - - -def get_folio_detail(folio_id: list, start_date: str): - # folio detail +def get_folio_detail(folio_ids, start_date): +# folio detail # need data: # actual room nett, breakfast revenue, mode of payment, total_amount (payment_amount?), payment_date @@ -211,21 +206,22 @@ def get_folio_detail(folio_id: list, start_date: str): transaction_type_list = (TRANSACTION_TYPE_COMISSION, TRANSACTION_TYPE_ROOM_REVENUE, TRANSACTION_TYPE_BREAKFAST_REVENUE, TRANSACTION_TYPE_PAYMENT, TRANSACTION_TYPE_ROOM_PAYMENT) - if (len(folio_id) == 1): - folio_id_query = f"= '{folio_id[0]}'" + if len(folio_ids) == 1: + folio_id_query = "= %(folio_id)s" + params = {'folio_id': folio_ids[0], 'start_date': start_date} else: - folio_id_query = f'in {folio_id}' + folio_id_query = "IN %(folio_ids)s" + params = {'folio_ids': folio_ids, 'start_date': start_date} query = f""" - select parent, transaction_type, amount, mode_of_payment, creation, actual_room_rate - from `tabInn Folio Transaction` as ift - where ift.parent {folio_id_query} - and - ift.transaction_type in {transaction_type_list} and - ift.audit_date = '{start_date}' + SELECT parent, transaction_type, amount, mode_of_payment, creation, actual_room_rate + FROM `tabInn Folio Transaction` AS ift + WHERE ift.parent {folio_id_query} + AND ift.transaction_type IN %(transaction_types)s + AND ift.audit_date = %(start_date)s """ - print(query) - folio_detail = frappe.db.sql(query=query, as_dict=1) + + folio_detail = frappe.db.sql(query, {**params, 'transaction_types': transaction_type_list}, as_dict=True) res = {folio: { "actual_room_rate": 0, "actual_room_nett": 0, @@ -234,17 +230,14 @@ def get_folio_detail(folio_id: list, start_date: str): "total_amount": 0, "payment_date": "", "comission": 0 - } for folio in folio_id} + } for folio in folio_ids} for data in folio_detail: - # populate aggrate folio data detail, grouped by folio number if data.transaction_type == TRANSACTION_TYPE_ROOM_REVENUE: res[data.parent]["actual_room_nett"] += data.amount - print(data) res[data.parent]["actual_room_rate"] = data.actual_room_rate - elif data.transaction_type == TRANSACTION_TYPE_PAYMENT or data.transaction_type == TRANSACTION_TYPE_ROOM_PAYMENT: - res[data.parent]["mode_of_payment"] += f"BY {data.mode_of_payment} {data.amount:,}".replace( - ",", ".") + ", " + elif data.transaction_type in (TRANSACTION_TYPE_PAYMENT, TRANSACTION_TYPE_ROOM_PAYMENT): + res[data.parent]["mode_of_payment"] += f"BY {data.mode_of_payment} {data.amount:,}, ".replace(",", ".") res[data.parent]["total_amount"] += data.amount res[data.parent]["payment_date"] += f"{data.creation}, " elif data.transaction_type == TRANSACTION_TYPE_BREAKFAST_REVENUE: @@ -254,45 +247,20 @@ def get_folio_detail(folio_id: list, start_date: str): return res - def fill_setting_data(): - # get data setting global TRANSACTION_TYPE_COMISSION, TRANSACTION_TYPE_ROOM_REVENUE, TRANSACTION_TYPE_BREAKFAST_REVENUE, TRANSACTION_TYPE_PAYMENT, TRANSACTION_TYPE_ROOM_PAYMENT, BREAKFAST_REVENUE_ACCOUNT, ROOM_REVENUE_ACCOUNT - transaction_type = frappe.db.get_values_from_single(fields=["profit_sharing_transaction_type", "room_revenue_transaction_type", "breakfast_revenue_transaction_type", "customer_payment_transaction_type", - "customer_room_payment_transaction_type", "breakfast_revenue_account", "room_revenue_account"], filters="", doctype="Inn Hotels Setting", as_dict=True)[0] - if transaction_type.profit_sharing_transaction_type == None: - TRANSACTION_TYPE_COMISSION = "Comission Channel" - else: - TRANSACTION_TYPE_COMISSION = transaction_type.profit_sharing_transaction_type - if transaction_type.room_revenue_transaction_type == None: - TRANSACTION_TYPE_ROOM_REVENUE = "Room Charge" - else: - TRANSACTION_TYPE_ROOM_REVENUE = transaction_type.room_revenue_transaction_type + setting = frappe.get_single("Inn Hotels Setting") + TRANSACTION_TYPE_COMISSION = setting.comission_channel or "Comission Channel" + TRANSACTION_TYPE_ROOM_REVENUE = setting.room_charge or "Room Charge" + TRANSACTION_TYPE_BREAKFAST_REVENUE = setting.breakfast_charge or "Breakfast Charge" + TRANSACTION_TYPE_PAYMENT = setting.payment or "Payment" + TRANSACTION_TYPE_ROOM_PAYMENT = setting.room_payment or "Room Payment" - if transaction_type.breakfast_revenue_transaction_type == None: - TRANSACTION_TYPE_BREAKFAST_REVENUE = "Breakfast Charge" - else: - TRANSACTION_TYPE_BREAKFAST_REVENUE = transaction_type.breakfast_revenue_transaction_type - - if transaction_type.customer_payment_transaction_type == None: - TRANSACTION_TYPE_PAYMENT = "Payment" - else: - TRANSACTION_TYPE_PAYMENT = transaction_type.customer_payment_transaction_type - - if transaction_type.customer_room_payment_transaction_type == None: - TRANSACTION_TYPE_ROOM_PAYMENT = "Room Payment" - else: - TRANSACTION_TYPE_ROOM_PAYMENT = transaction_type.customer_room_payment_transaction_type - - if transaction_type.breakfast_revenue_account == None: - raise ImportError( - "Breakfast Revenue Account in Inn Hotels Setting not set yet") - else: - BREAKFAST_REVENUE_ACCOUNT = transaction_type.breakfast_revenue_account + if not setting.breakfast_revenue_account: + frappe.throw("Breakfast Revenue Account in Inn Hotels Setting not set yet") + BREAKFAST_REVENUE_ACCOUNT = setting.breakfast_revenue_account - if transaction_type.room_revenue_account == None: - raise ImportError( - "Room Revenue Account in Inn Hotels Setting not set yet") - else: - ROOM_REVENUE_ACCOUNT = transaction_type.room_revenue_account + if not setting.room_revenue_account: + frappe.throw("Room Revenue Account in Inn Hotels Setting not set yet") + ROOM_REVENUE_ACCOUNT = setting.room_revenue_account \ No newline at end of file From e7d732c6fda1b6584054412a80a4228e02de101e Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Fri, 24 Jan 2025 22:13:50 +0300 Subject: [PATCH 06/22] (edit) Converting fields room type and role in Inn Hotels Setting from static to dynamic --- inn/__init__.py | 2 +- .../inn_hotels_setting.json | 96 ++- inn/inn_hotels/doctype/inn_room/inn_room.js | 118 +-- inn/inn_hotels/doctype/inn_room/inn_room.py | 41 +- .../daily_flash_report/daily_flash_report.py | 766 +++++++++--------- 5 files changed, 572 insertions(+), 451 deletions(-) diff --git a/inn/__init__.py b/inn/__init__.py index 73381fd2..87ede6f1 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = '1.1.1' +__version__ = '1.1.2' diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index 3c51ea94..242bd24c 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -74,6 +74,20 @@ "folio_transaction_type", "supervisor_passcode", "folio_default_tab", + "bed_type_section", + "studio", + "superior", + "deluxe", + "executive", + "suite", + "column_break_pekg", + "housekeeping", + "housekeeping_assistant", + "restaurant_user", + "restaurant_supervisor", + "housekeeping_supervisor", + "booking_approver", + "folio_transaction_type_section", "package_tax", "room_charge_tax_service", "breakfast_charge_tax_service", @@ -662,11 +676,91 @@ "fieldtype": "Link", "label": "FBS Service 10 %", "options": "Inn Folio Transaction Type" + }, + { + "fieldname": "folio_transaction_type_section", + "fieldtype": "Section Break", + "label": "Folio Transaction Type" + }, + { + "fieldname": "bed_type_section", + "fieldtype": "Section Break", + "label": "Room Type & Role" + }, + { + "fieldname": "studio", + "fieldtype": "Link", + "label": "Studio", + "options": "Inn Room Type" + }, + { + "fieldname": "superior", + "fieldtype": "Link", + "label": "Superior", + "options": "Inn Room Type" + }, + { + "fieldname": "deluxe", + "fieldtype": "Link", + "label": "Deluxe", + "options": "Inn Room Type" + }, + { + "fieldname": "executive", + "fieldtype": "Link", + "label": "Executive", + "options": "Inn Room Type" + }, + { + "fieldname": "suite", + "fieldtype": "Link", + "label": "Suite", + "options": "Inn Room Type" + }, + { + "fieldname": "column_break_pekg", + "fieldtype": "Column Break" + }, + { + "fieldname": "housekeeping", + "fieldtype": "Link", + "label": "Housekeeping", + "options": "Role" + }, + { + "fieldname": "housekeeping_assistant", + "fieldtype": "Link", + "label": "Housekeeping Assistant", + "options": "Role" + }, + { + "fieldname": "restaurant_user", + "fieldtype": "Link", + "label": "Restaurant User", + "options": "Role" + }, + { + "fieldname": "restaurant_supervisor", + "fieldtype": "Link", + "label": "Restaurant Supervisor", + "options": "Role" + }, + { + "fieldname": "housekeeping_supervisor", + "fieldtype": "Link", + "label": "Housekeeping Supervisor", + "options": "Role" + }, + { + "fieldname": "booking_approver", + "fieldtype": "Link", + "label": "Booking Approver", + "options": "Role" } ], "issingle": 1, "links": [], - "modified": "2025-01-22 19:51:25.793321", + "modified": "2025-01-24 21:07:55.122096", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_room/inn_room.js b/inn/inn_hotels/doctype/inn_room/inn_room.js index ef0650df..450f3fe3 100644 --- a/inn/inn_hotels/doctype/inn_room/inn_room.js +++ b/inn/inn_hotels/doctype/inn_room/inn_room.js @@ -3,58 +3,78 @@ frappe.ui.form.on('Inn Room', { refresh: function (frm, cdt, cdn) { - set_option_floor_plan(frm) - if (frappe.user.has_role('Housekeeping') || - frappe.user.has_role('Housekeeping Assistant') || - frappe.user.has_role('Housekeeping Supervisor') || - frappe.user.has_role('Administrator')) { - if (frm.doc.room_status == 'Occupied Dirty' || - frm.doc.room_status == 'Vacant Dirty' || - frm.doc.room_status == 'Vacant Clean') { - frm.page.add_menu_item(__('Clean Room'), function () { - frappe.confirm( - __('You are about to update status of Room ' + frm.doc.name + ', are you sure?'), - () => { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room.inn_room.update_single_room_status', - args: { - room: frm.doc.name, - mode: 'clean' - }, - callback: (r) => { - if (r.message) { - frm.reload_doc(); - frappe.msgprint(r.message); - } - } - }); + set_option_floor_plan(frm); + + // Fetch role names from Inn Hotels Setting + frappe.call({ + method: 'frappe.client.get_value', + args: { + doctype: 'Inn Hotels Setting', + fieldname: ['housekeeping', 'housekeeping_assistant', 'housekeeping_supervisor'] + }, + callback: function(response) { + const roles = response.message; + const housekeepingRole = roles.housekeeping; + const housekeepingAssistantRole = roles.housekeeping_assistant; + const housekeepingSupervisorRole = roles.housekeeping_supervisor; + + // Check if the user has any of the required roles + const hasPermission = frappe.user.has_role(housekeepingRole) || + frappe.user.has_role(housekeepingAssistantRole) || + frappe.user.has_role(housekeepingSupervisorRole) || + frappe.user.has_role('Administrator'); + + if (hasPermission) { + if (frm.doc.room_status == 'Occupied Dirty' || + frm.doc.room_status == 'Vacant Dirty' || + frm.doc.room_status == 'Vacant Clean') { + frm.page.add_menu_item(__('Clean Room'), function () { + frappe.confirm( + __('You are about to update status of Room ' + frm.doc.name + ', are you sure?'), + () => { + frappe.call({ + method: 'inn.inn_hotels.doctype.inn_room.inn_room.update_single_room_status', + args: { + room: frm.doc.name, + mode: 'clean' + }, + callback: (r) => { + if (r.message) { + frm.reload_doc(); + frappe.msgprint(r.message); + } + } + }); + }); }); - }) - } - else if (frm.doc.room_status == 'Vacant Clean' || - frm.doc.room_status == 'Vacant Ready' || - frm.doc.room_status == 'Occupied Clean') { - frm.page.add_menu_item(__('Dirty Room'), function () { - frappe.confirm( - __('You are about to update status of Room ' + frm.doc.name + ', are you sure?'), - () => { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room.inn_room.update_single_room_status', - args: { - room: frm.doc.name, - mode: 'dirty' - }, - callback: (r) => { - if (r.message) { - frm.reload_doc(); - frappe.msgprint(r.message); - } - } - }); + } + else if (frm.doc.room_status == 'Vacant Clean' || + frm.doc.room_status == 'Vacant Ready' || + frm.doc.room_status == 'Occupied Clean') { + frm.page.add_menu_item(__('Dirty Room'), function () { + frappe.confirm( + __('You are about to update status of Room ' + frm.doc.name + ', are you sure?'), + () => { + frappe.call({ + method: 'inn.inn_hotels.doctype.inn_room.inn_room.update_single_room_status', + args: { + room: frm.doc.name, + mode: 'dirty' + }, + callback: (r) => { + if (r.message) { + frm.reload_doc(); + frappe.msgprint(r.message); + } + } + }); + }); }); - }) + } + } } - } + }); + frm.add_custom_button(__('Clear Door Status'), function () { frappe.db.set_value(cdt, cdn, 'door_status', 'No Status'); frappe.show_alert('Door Status Cleared'); diff --git a/inn/inn_hotels/doctype/inn_room/inn_room.py b/inn/inn_hotels/doctype/inn_room/inn_room.py index dea4ae31..ca55072d 100644 --- a/inn/inn_hotels/doctype/inn_room/inn_room.py +++ b/inn/inn_hotels/doctype/inn_room/inn_room.py @@ -54,12 +54,18 @@ def update_room_status(rooms, mode): is_housekeeping_supervisor = False is_administrator = False + # Fetch role names from Inn Hotels Setting + roles = frappe.get_doc("Inn Hotels Setting") + housekeeping_assistant_role = roles.housekeeping_assistant + housekeeping_supervisor_role = roles.housekeeping_supervisor + administrator_role = "Administrator" + for role in frappe.get_roles(frappe.session.user): - if role == 'Housekeeping Assistant': + if role == housekeeping_assistant_role: is_housekeeping_assistant = True - elif role == 'Housekeeping Supervisor': + elif role == housekeeping_supervisor_role: is_housekeeping_supervisor = True - elif role == 'Administrator': + elif role == administrator_role: is_administrator = True if mode == 'clean': @@ -108,27 +114,22 @@ def update_single_room_status(room, mode): is_housekeeping_supervisor = False is_administrator = False + # Fetch role names from Inn Hotels Setting + roles = frappe.get_doc("Inn Hotels Setting") + housekeeping_role = roles.housekeeping + housekeeping_assistant_role = roles.housekeeping_assistant + housekeeping_supervisor_role = roles.housekeeping_supervisor + administrator_role = "Administrator" + for role in frappe.get_roles(frappe.session.user): - if role == 'Housekeeping': + if role == housekeeping_role: is_housekeeping = True - is_housekeeping_assistant = False - is_housekeeping_supervisor = False - is_administrator = False - elif role == 'Housekeeping Assistant': + elif role == housekeeping_assistant_role: is_housekeeping_assistant = True - is_housekeeping = False - is_housekeeping_supervisor = False - is_administrator = False - elif role == 'Housekeeping Supervisor': - is_housekeeping_assistant = False - is_housekeeping = False + elif role == housekeeping_supervisor_role: is_housekeeping_supervisor = True - is_administrator = False - elif role == 'Administrator': + elif role == administrator_role: is_administrator = True - is_housekeeping = False - is_housekeeping_assistant = False - is_housekeeping_supervisor = False if mode == 'clean': door_status = frappe.db.get_value('Inn Room', room, 'door_status') @@ -139,7 +140,7 @@ def update_single_room_status(room, mode): elif room_status == 'Occupied Dirty': frappe.db.set_value('Inn Room', room, 'room_status', 'Occupied Clean') elif room_status == 'Vacant Clean': - if not is_housekeeping and ( is_housekeeping_supervisor or is_housekeeping_assistant or is_administrator): + if not is_housekeeping and (is_housekeeping_supervisor or is_housekeeping_assistant or is_administrator): frappe.db.set_value('Inn Room', room, 'room_status', 'Vacant Ready') else: pass diff --git a/inn/inn_hotels/report/daily_flash_report/daily_flash_report.py b/inn/inn_hotels/report/daily_flash_report/daily_flash_report.py index ac711ae9..7befe8b0 100644 --- a/inn/inn_hotels/report/daily_flash_report/daily_flash_report.py +++ b/inn/inn_hotels/report/daily_flash_report/daily_flash_report.py @@ -7,425 +7,431 @@ import calendar def execute(filters=None): - columns = [ - { + columns = [ + { 'fieldname': 'statistic', 'label': 'Statistic', 'fieldtype': 'Data', - 'width': 150, + 'width': 150, }, - { + { 'fieldname': 'today_actual', 'label': 'Today Actual', 'fieldtype': 'Data', - 'width': 100, + 'width': 100, }, - { + { 'fieldname': 'mtd_actual', 'label': 'MTD Actual', 'fieldtype': 'Data', - 'width': 100, + 'width': 100, }, - { + { 'fieldname': 'mtd_last_month', 'label': 'MTD Last Month', 'fieldtype': 'Data', - 'width': 100, + 'width': 100, }, - { + { 'fieldname': 'year_to_date', 'label': 'Year To Date', 'fieldtype': 'Data', - 'width': 100, + 'width': 100, }, - ] + ] - data = get_data(filters) + data = get_data(filters) - return columns, data + return columns, data def get_total_room(): - return frappe.db.sql(""" - SELECT - SUM(CASE WHEN rt.name = 'Studio' THEN 1 ELSE 0 END) AS studio, - SUM(CASE WHEN rt.name = 'Superior' THEN 1 ELSE 0 END) AS superior, - SUM(CASE WHEN rt.name = 'Deluxe' THEN 1 ELSE 0 END) AS deluxe, - SUM(CASE WHEN rt.name = 'Executive' THEN 1 ELSE 0 END) AS executive, - SUM(CASE WHEN rt.name = 'Suite' THEN 1 ELSE 0 END) AS suite, - COUNT(*) AS total - FROM `tabInn Room` r - LEFT JOIN `tabInn Room Type` rt ON r.room_type=rt.name""", as_dict=True) + return frappe.db.sql(""" + SELECT + SUM(CASE WHEN rt.name = %s THEN 1 ELSE 0 END) AS studio, + SUM(CASE WHEN rt.name = %s THEN 1 ELSE 0 END) AS superior, + SUM(CASE WHEN rt.name = %s THEN 1 ELSE 0 END) AS deluxe, + SUM(CASE WHEN rt.name = %s THEN 1 ELSE 0 END) AS executive, + SUM(CASE WHEN rt.name = %s THEN 1 ELSE 0 END) AS suite, + COUNT(*) AS total + FROM `tabInn Room` r + LEFT JOIN `tabInn Room Type` rt ON r.room_type=rt.name""", + (get_setting_value('studio'), get_setting_value('superior'), get_setting_value('deluxe'), get_setting_value('executive'), get_setting_value('suite')), + as_dict=True) def get_room_booking(current_year, next_year): - return frappe.db.sql(""" - select rb.start, rb.end, rb.room_availability, r.room_type, rb.status - from `tabInn Room Booking` rb - left join `tabInn Room` r on r.name = rb.room_id - where end>=%s and start<%s""", (current_year, next_year), as_dict=True) + return frappe.db.sql(""" + select rb.start, rb.end, rb.room_availability, r.room_type, rb.status + from `tabInn Room Booking` rb + left join `tabInn Room` r on r.name = rb.room_id + where end>=%s and start<%s""", (current_year, next_year), as_dict=True) def get_reservation(current_year, next_year): - return frappe.db.sql(""" - select arrival, departure, status, channel, actual_room_rate - from `tabInn Reservation` - where departure>=%s and arrival<%s""", (current_year, next_year), as_dict=True) + return frappe.db.sql(""" + select arrival, departure, status, channel, actual_room_rate + from `tabInn Reservation` + where departure>=%s and arrival<%s""", (current_year, next_year), as_dict=True) def get_gl_entry(current_year, next_year): - return frappe.db.sql(""" + return frappe.db.sql(""" select posting_date, account, credit, debit from `tabGL Entry` where posting_date>=%s and posting_date<%s""", (current_year, next_year), as_dict=True) def get_folio_transaction(current_year, next_year): - return frappe.db.sql(""" + return frappe.db.sql(""" select audit_date, amount, mode_of_payment from `tabInn Folio Transaction` where flag='Credit' and audit_date>=%s and audit_date<%s""", (current_year, next_year), as_dict=True) def get_mode_of_payment(): - return frappe.db.sql(""" - select name from `tabMode of Payment`""", as_dict=True) + return frappe.db.sql(""" + select name from `tabMode of Payment`""", as_dict=True) + +def get_setting_value(field_name): + setting = frappe.get_doc("Inn Hotels Setting") + return setting.get(field_name) def get_data(filters): - data = [] - - if filters.date: - today = datetime.datetime.strptime(filters.date, '%Y-%m-%d').date() - current_year = datetime.datetime(year=today.year, month=1, day=1).date() - next_year = datetime.datetime(year=today.year+1, month=1, day=1).date() - current_month = datetime.datetime(year=today.year, month=today.month, day=1).date() - tmp = today.month-1 if today.month > 1 else 12 - last_month = datetime.datetime(year=today.year, month=tmp, day=1).date() - - room = {} - - keys = ['Total Room Available', 'Total Room Out of Order', 'Total Room House Use', - 'Total Room Sold', 'Studio Sold', 'Superior Sold', 'Deluxe Sold', 'Executive Sold', 'Suite Sold', - 'Total Room Reserved', 'Studio Reserved', 'Superior Reserved', 'Deluxe Reserved', 'Executive Reserved', 'Suite Reserved', - 'Total Room Available', 'Studio Available', 'Superior Available', 'Deluxe Available', 'Executive Available', 'Suite Available', - 'Total Saleable Room', - 'Total Day Use', 'Total In House', 'Total Walk In', 'Total Vacant Room'] - - for key in keys: - room[key] = {'today_actual': 0, 'mtd_actual': 0, 'mtd_last_month': 0, 'year_to_date': 0} - - room_booking = get_room_booking(current_year, next_year) - - for rb in room_booking: - start = rb['start'] - end = rb['end'] - - for i in range((end-start).days): - date = start + datetime.timedelta(days=i) - availability = rb.room_availability - - if availability == 'Out of Order' or availability == 'House Use': - key = 'Total Room ' + availability - - room[key]['year_to_date'] = room[key]['year_to_date'] + 1 - if date == today: - room[key]['today_actual'] = room[key]['today_actual'] + 1 - if date >= current_month and date <= today: - room[key]['mtd_actual'] = room[key]['mtd_actual'] + 1 - elif date >= last_month and date < current_month: - room[key]['mtd_last_month'] = room[key]['mtd_last_month'] + 1 - - elif availability == 'Room Sold' and (rb.status == 'Stayed' or rb.status == 'Finished'): - key = rb.room_type + ' Sold' - - room[key]['year_to_date'] = room[key]['year_to_date'] + 1 - if date == today: - room[key]['today_actual'] = room[key]['today_actual'] + 1 - if date >= current_month and date <= today: - room[key]['mtd_actual'] = room[key]['mtd_actual'] + 1 - elif date >= last_month and date < current_month: - room[key]['mtd_last_month'] = room[key]['mtd_last_month'] + 1 - - elif availability == 'Room Sold' and rb.status == 'Booked': - key = rb.room_type + ' Reserved' - - room[key]['year_to_date'] = room[key]['year_to_date'] + 1 - if date == today: - room[key]['today_actual'] = room[key]['today_actual'] + 1 - if date >= current_month and date <= today: - room[key]['mtd_actual'] = room[key]['mtd_actual'] + 1 - elif date >= last_month and date < current_month: - room[key]['mtd_last_month'] = room[key]['mtd_last_month'] + 1 - - room['Total Saleable Room'] = { - 'today_actual': room['Total Room Available']['today_actual'] - room['Total Room Out of Order']['today_actual'], - 'mtd_actual': room['Total Room Available']['mtd_actual'] - room['Total Room Out of Order']['mtd_actual'], - 'mtd_last_month': room['Total Room Available']['mtd_last_month'] - room['Total Room Out of Order']['mtd_last_month'], - 'year_to_date': room['Total Room Available']['year_to_date'] - room['Total Room Out of Order']['year_to_date'], - } - - total_room = get_total_room()[0]['total'] - tmp = today.month-1 if today.month > 1 else 12 - - room['Total Room Available'] = { - 'today_actual': total_room, - 'mtd_actual': total_room*today.day, - 'mtd_last_month': total_room*calendar.monthrange(today.year, tmp)[1], - 'year_to_date': total_room*((today-current_year).days+1) - } - - average_room_rate = {'today_actual': 0, 'mtd_actual': 0, 'mtd_last_month': 0, 'year_to_date': 0} - - reservation = get_reservation(current_year, next_year) - for r in reservation: - start = r['arrival'].date() - end = r['departure'].date() - - if start == end: - room['Total Day Use']['year_to_date'] = room['Total Day Use']['year_to_date'] + 1 - if start == today: - room['Total Day Use']['today_actual'] = room['Total Day Use']['today_actual'] + 1 - if start >= current_month and start <= today: - room['Total Day Use']['mtd_actual'] = room['Total Day Use']['mtd_actual'] + 1 - elif start >= last_month and start < current_month: - room['Total Day Use']['mtd_last_month'] = room['Total Day Use']['mtd_last_month'] + 1 - - for i in range((end-start).days): - date = start + datetime.timedelta(days=i) - status = r.status - - if status == 'In House': - room['Total In House']['year_to_date'] = room['Total In House']['year_to_date'] + 1 - average_room_rate['year_to_date'] = (average_room_rate['year_to_date'] + r['actual_room_rate']) / 2 - if date == today: - room['Total In House']['today_actual'] = room['Total In House']['today_actual'] + 1 - average_room_rate['today_actual'] = (average_room_rate['today_actual'] + r['actual_room_rate']) / 2 - if date >= current_month and date <= today: - room['Total In House']['mtd_actual'] = room['Total In House']['mtd_actual'] + 1 - average_room_rate['mtd_actual'] = (average_room_rate['mtd_actual'] + r['actual_room_rate']) / 2 - elif date >= last_month and date < current_month: - room['Total In House']['mtd_last_month'] = room['Total In House']['mtd_last_month'] + 1 - average_room_rate['mtd_last_month'] = (average_room_rate['mtd_last_month'] + r['actual_room_rate']) / 2 - - - channel = r.channel - if channel == 'Walk In': - room['Total Walk In']['year_to_date'] = room['Total Walk In']['year_to_date'] + 1 - if date == today: - room['Total Walk In']['today_actual'] = room['Total Walk In']['today_actual'] + 1 - if date >= current_month and date <= today: - room['Total Walk In']['mtd_actual'] = room['Total Walk In']['mtd_actual'] + 1 - elif date >= last_month and date < current_month: - room['Total Walk In']['mtd_last_month'] = room['Total Walk In']['mtd_last_month'] + 1 - - room['Total Vacant Room'] = { - 'today_actual': room['Total Room Available']['today_actual'] - room['Total In House']['today_actual'], - 'mtd_actual': room['Total Room Available']['mtd_actual'] - room['Total In House']['mtd_actual'], - 'mtd_last_month': room['Total Room Available']['mtd_last_month'] - room['Total In House']['mtd_last_month'], - 'year_to_date': room['Total Room Available']['year_to_date'] - room['Total In House']['year_to_date'] - } - - revenue = {} - - keys = ['4210.001', - '4110.001', '4120.001', '4120.002', - '4140.001', '4140.002', - '4150.001', '4150.002', '4150.003', '4150.004', '4150.006', - '2141.000', '2110.004'] - - for key in keys: - revenue[key] = {'today_actual': 0, 'mtd_actual': 0, 'mtd_last_month': 0, 'year_to_date': 0} - - gl_entry = get_gl_entry(current_year, next_year) - for ge in gl_entry: - account = ge.account[:8] - if account == '4210.001' or \ - account == '4110.001' or account == '4120.001' or account == '4120.002' or \ - account == '4140.001' or account == '4140.002' or \ - account == '4150.001' or account == '4150.002' or account == '4150.003' or account == '4150.004' or account == '4150.006' or \ - account == '2141.000' or account == '2110.004': - - revenue[account]['year_to_date'] = revenue[account]['year_to_date'] + ge.credit - ge.debit - if ge.posting_date == today: - revenue[account]['today_actual'] = revenue[account]['today_actual'] + ge.credit - ge.debit - if ge.posting_date >= current_month and ge.posting_date <= today: - revenue[account]['mtd_actual'] = revenue[account]['mtd_actual'] + ge.credit - ge.debit - elif ge.posting_date >= last_month and ge.posting_date < current_month: - revenue[account]['mtd_last_month'] = revenue[account]['mtd_last_month'] + ge.credit - ge.debit - - payment = {} - - mode_of_payment = get_mode_of_payment() - for mp in mode_of_payment: - exist = False - for key in payment: - if mp.name == key: - exist = True - if not exist: - payment[mp.name] = {} - payment[mp.name]['today_actual'] = 0 - payment[mp.name]['mtd_actual'] = 0 - payment[mp.name]['mtd_last_month'] = 0 - payment[mp.name]['year_to_date'] = 0 - - folio_transaction = get_folio_transaction(current_year, next_year) - for ft in folio_transaction: - payment[ft.mode_of_payment]['year_to_date'] = payment[ft.mode_of_payment]['year_to_date'] + ft.amount - if ft.audit_date == today: - payment[ft.mode_of_payment]['today_actual'] = payment[ft.mode_of_payment]['today_actual'] + ft.amount - if ft.audit_date >= current_month and ft.audit_date <= today: - payment[ft.mode_of_payment]['mtd_actual'] = payment[ft.mode_of_payment]['mtd_actual'] + ft.amount - elif ft.audit_date >= last_month and ft.audit_date < current_month: - payment[ft.mode_of_payment]['mtd_last_month'] = payment[ft.mode_of_payment]['mtd_last_month'] + ft.amount - - for key in room: - title = key - indent = 0.0 - - if key == 'Studio Sold' or key == 'Superior Sold' or key == 'Deluxe Sold' or key == 'Executive Sold' or key == 'Suite Sold' or key == 'Studio Reserved' or key == 'Superior Reserved' or key == 'Deluxe Reserved' or key == 'Executive Reserved' or key == 'Suite Reserved': - indent = 1.0 - - today_actual = '{:,}'.format(room[key]['today_actual']).replace(',','.') - mtd_actual = '{:,}'.format(room[key]['mtd_actual']).replace(',','.') - mtd_last_month = '{:,}'.format(room[key]['mtd_last_month']).replace(',','.') - year_to_date = '{:,}'.format(room[key]['year_to_date']).replace(',','.') - - if key == 'Total Room Sold' or key == 'Total Room Reserved': - today_actual = '' - mtd_actual = '' - mtd_last_month = '' - year_to_date = '' - - data.append({ - 'statistic': title, - 'today_actual': today_actual, - 'mtd_actual': mtd_actual, - 'mtd_last_month': mtd_last_month, - 'year_to_date': year_to_date, - 'indent': indent, - 'is_currency': False, - }) - - data.append({ - 'statistic': 'Average Room Rate', - 'today_actual': '{:,}'.format(int(round(average_room_rate['today_actual']))).replace(',','.'), - 'mtd_actual': '{:,}'.format(int(round(average_room_rate['mtd_actual']))).replace(',','.'), - 'mtd_last_month': '{:,}'.format(int(round(average_room_rate['mtd_last_month']))).replace(',','.'), - 'year_to_date': '{:,}'.format(int(round(average_room_rate['year_to_date']))).replace(',','.'), - 'indent': 0.0, - 'is_currency': True, - }) - - total_revenue = {'today_actual': 0, 'mtd_actual': 0, 'mtd_last_month': 0, 'year_to_date': 0} - - for key in revenue: - title = '' - indent = 1.0 - - if key == '4210.001': - title = 'Room Revenue' - indent = 0.0 - elif key == '4110.001': - data.append({ - 'statistic': 'Restaurant Revenue', - 'today_actual': '', - 'mtd_actual': '', - 'mtd_last_month': '', - 'year_to_date': '', - 'indent': 0.0, - 'is_currency': False, - }) - title = 'Breakfast Revenue' - elif key == '4120.001': - title = 'Resto Food' - elif key == '4120.002': - title = 'Resto Beverage' - elif key == '4140.001': - data.append({ - 'statistic': 'Room Service Revenue', - 'today_actual': '', - 'mtd_actual': '', - 'mtd_last_month': '', - 'year_to_date': '', - 'indent': 0.0, - 'is_currency': False, - }) - title = 'Service Food' - elif key == '4140.002': - title = 'Service Beverage' - elif key == '4150.001': - data.append({ - 'statistic': 'Banquet Revenue', - 'today_actual': '', - 'mtd_actual': '', - 'mtd_last_month': '', - 'year_to_date': '', - 'indent': 0.0, - 'is_currency': False, - }) - title = 'Banquet Lunch' - elif key == '4150.002': - title = 'Banquet Dinner' - elif key == '4150.003': - title = 'Banquet Coffee Break' - elif key == '4150.004': - title = 'Banquet Meeting' - elif key == '4150.006': - title = 'Banquet Wedding' - elif key == '2141.000': - data.append({ - 'statistic': 'Total Revenue', - 'today_actual': '{:,}'.format(int(round(total_revenue['today_actual']))).replace(',','.'), - 'mtd_actual': '{:,}'.format(int(round(total_revenue['mtd_actual']))).replace(',','.'), - 'mtd_last_month': '{:,}'.format(int(round(total_revenue['mtd_last_month']))).replace(',','.'), - 'year_to_date': '{:,}'.format(int(round(total_revenue['year_to_date']))).replace(',','.'), - 'indent': 0.0, - 'is_currency': True, - }) - - data.append({ - 'statistic': 'Tax and Service', - 'today_actual': '', - 'mtd_actual': '', - 'mtd_last_month': '', - 'year_to_date': '', - 'indent': 0.0, - 'is_currency': False, - }) - title = 'Tax PB 1' - elif key == '2110.004': - title = 'Service Charge' - - data.append({ - 'statistic': title, - 'today_actual': '{:,}'.format(int(round(revenue[key]['today_actual']))).replace(',','.'), - 'mtd_actual': '{:,}'.format(int(round(revenue[key]['mtd_actual']))).replace(',','.'), - 'mtd_last_month': '{:,}'.format(int(round(revenue[key]['mtd_last_month']))).replace(',','.'), - 'year_to_date': '{:,}'.format(int(round(revenue[key]['year_to_date']))).replace(',','.'), - 'indent': indent, - 'is_currency': True, - }) - - if key != '2141.000' and key != '2110.004': - total_revenue = { - 'today_actual': total_revenue['today_actual'] + revenue[key]['today_actual'], - 'mtd_actual': total_revenue['mtd_actual'] + revenue[key]['mtd_actual'], - 'mtd_last_month': total_revenue['mtd_last_month'] + revenue[key]['mtd_last_month'], - 'year_to_date': total_revenue['year_to_date'] + revenue[key]['year_to_date'] - } - - data.append({ - 'statistic': 'Payment', - 'today_actual': '', - 'mtd_actual': '', - 'mtd_last_month': '', - 'year_to_date': '', - 'indent': 0.0, - 'is_currency': False, - }) - for key in payment: - data.append({ - 'statistic': key, - 'today_actual': '{:,}'.format(int(round(payment[key]['today_actual']))).replace(',','.'), - 'mtd_actual': '{:,}'.format(int(round(payment[key]['mtd_actual']))).replace(',','.'), - 'mtd_last_month': '{:,}'.format(int(round(payment[key]['mtd_last_month']))).replace(',','.'), - 'year_to_date': '{:,}'.format(int(round(payment[key]['year_to_date']))).replace(',','.'), - 'indent': 1.0, - 'is_currency': True, - }) - - return data + data = [] + + if filters.date: + today = datetime.datetime.strptime(filters.date, '%Y-%m-%d').date() + current_year = datetime.datetime(year=today.year, month=1, day=1).date() + next_year = datetime.datetime(year=today.year+1, month=1, day=1).date() + current_month = datetime.datetime(year=today.year, month=today.month, day=1).date() + tmp = today.month-1 if today.month > 1 else 12 + last_month = datetime.datetime(year=today.year, month=tmp, day=1).date() + + room = {} + + keys = ['Total Room Available', 'Total Room Out of Order', 'Total Room House Use', + 'Total Room Sold', 'Studio Sold', 'Superior Sold', 'Deluxe Sold', 'Executive Sold', 'Suite Sold', + 'Total Room Reserved', 'Studio Reserved', 'Superior Reserved', 'Deluxe Reserved', 'Executive Reserved', 'Suite Reserved', + 'Total Room Available', 'Studio Available', 'Superior Available', 'Deluxe Available', 'Executive Available', 'Suite Available', + 'Total Saleable Room', + 'Total Day Use', 'Total In House', 'Total Walk In', 'Total Vacant Room'] + + for key in keys: + room[key] = {'today_actual': 0, 'mtd_actual': 0, 'mtd_last_month': 0, 'year_to_date': 0} + + room_booking = get_room_booking(current_year, next_year) + + for rb in room_booking: + start = rb['start'] + end = rb['end'] + + for i in range((end-start).days): + date = start + datetime.timedelta(days=i) + availability = rb.room_availability + + if availability == 'Out of Order' or availability == 'House Use': + key = 'Total Room ' + availability + + room[key]['year_to_date'] = room[key]['year_to_date'] + 1 + if date == today: + room[key]['today_actual'] = room[key]['today_actual'] + 1 + if date >= current_month and date <= today: + room[key]['mtd_actual'] = room[key]['mtd_actual'] + 1 + elif date >= last_month and date < current_month: + room[key]['mtd_last_month'] = room[key]['mtd_last_month'] + 1 + + elif availability == 'Room Sold' and (rb.status == 'Stayed' or rb.status == 'Finished'): + key = rb.room_type + ' Sold' + + room[key]['year_to_date'] = room[key]['year_to_date'] + 1 + if date == today: + room[key]['today_actual'] = room[key]['today_actual'] + 1 + if date >= current_month and date <= today: + room[key]['mtd_actual'] = room[key]['mtd_actual'] + 1 + elif date >= last_month and date < current_month: + room[key]['mtd_last_month'] = room[key]['mtd_last_month'] + 1 + + elif availability == 'Room Sold' and rb.status == 'Booked': + key = rb.room_type + ' Reserved' + + room[key]['year_to_date'] = room[key]['year_to_date'] + 1 + if date == today: + room[key]['today_actual'] = room[key]['today_actual'] + 1 + if date >= current_month and date <= today: + room[key]['mtd_actual'] = room[key]['mtd_actual'] + 1 + elif date >= last_month and date < current_month: + room[key]['mtd_last_month'] = room[key]['mtd_last_month'] + 1 + + room['Total Saleable Room'] = { + 'today_actual': room['Total Room Available']['today_actual'] - room['Total Room Out of Order']['today_actual'], + 'mtd_actual': room['Total Room Available']['mtd_actual'] - room['Total Room Out of Order']['mtd_actual'], + 'mtd_last_month': room['Total Room Available']['mtd_last_month'] - room['Total Room Out of Order']['mtd_last_month'], + 'year_to_date': room['Total Room Available']['year_to_date'] - room['Total Room Out of Order']['year_to_date'], + } + + total_room = get_total_room()[0]['total'] + tmp = today.month-1 if today.month > 1 else 12 + + room['Total Room Available'] = { + 'today_actual': total_room, + 'mtd_actual': total_room*today.day, + 'mtd_last_month': total_room*calendar.monthrange(today.year, tmp)[1], + 'year_to_date': total_room*((today-current_year).days+1) + } + + average_room_rate = {'today_actual': 0, 'mtd_actual': 0, 'mtd_last_month': 0, 'year_to_date': 0} + + reservation = get_reservation(current_year, next_year) + for r in reservation: + start = r['arrival'].date() + end = r['departure'].date() + + if start == end: + room['Total Day Use']['year_to_date'] = room['Total Day Use']['year_to_date'] + 1 + if start == today: + room['Total Day Use']['today_actual'] = room['Total Day Use']['today_actual'] + 1 + if start >= current_month and start <= today: + room['Total Day Use']['mtd_actual'] = room['Total Day Use']['mtd_actual'] + 1 + elif start >= last_month and start < current_month: + room['Total Day Use']['mtd_last_month'] = room['Total Day Use']['mtd_last_month'] + 1 + + for i in range((end-start).days): + date = start + datetime.timedelta(days=i) + status = r.status + + if status == 'In House': + room['Total In House']['year_to_date'] = room['Total In House']['year_to_date'] + 1 + average_room_rate['year_to_date'] = (average_room_rate['year_to_date'] + r['actual_room_rate']) / 2 + if date == today: + room['Total In House']['today_actual'] = room['Total In House']['today_actual'] + 1 + average_room_rate['today_actual'] = (average_room_rate['today_actual'] + r['actual_room_rate']) / 2 + if date >= current_month and date <= today: + room['Total In House']['mtd_actual'] = room['Total In House']['mtd_actual'] + 1 + average_room_rate['mtd_actual'] = (average_room_rate['mtd_actual'] + r['actual_room_rate']) / 2 + elif date >= last_month and date < current_month: + room['Total In House']['mtd_last_month'] = room['Total In House']['mtd_last_month'] + 1 + average_room_rate['mtd_last_month'] = (average_room_rate['mtd_last_month'] + r['actual_room_rate']) / 2 + + + channel = r.channel + if channel == 'Walk In': + room['Total Walk In']['year_to_date'] = room['Total Walk In']['year_to_date'] + 1 + if date == today: + room['Total Walk In']['today_actual'] = room['Total Walk In']['today_actual'] + 1 + if date >= current_month and date <= today: + room['Total Walk In']['mtd_actual'] = room['Total Walk In']['mtd_actual'] + 1 + elif date >= last_month and date < current_month: + room['Total Walk In']['mtd_last_month'] = room['Total Walk In']['mtd_last_month'] + 1 + + room['Total Vacant Room'] = { + 'today_actual': room['Total Room Available']['today_actual'] - room['Total In House']['today_actual'], + 'mtd_actual': room['Total Room Available']['mtd_actual'] - room['Total In House']['mtd_actual'], + 'mtd_last_month': room['Total Room Available']['mtd_last_month'] - room['Total In House']['mtd_last_month'], + 'year_to_date': room['Total Room Available']['year_to_date'] - room['Total In House']['year_to_date'] + } + + revenue = {} + + keys = ['4210.001', + '4110.001', '4120.001', '4120.002', + '4140.001', '4140.002', + '4150.001', '4150.002', '4150.003', '4150.004', '4150.006', + '2141.000', '2110.004'] + + for key in keys: + revenue[key] = {'today_actual': 0, 'mtd_actual': 0, 'mtd_last_month': 0, 'year_to_date': 0} + + gl_entry = get_gl_entry(current_year, next_year) + for ge in gl_entry: + account = ge.account[:8] + if account == '4210.001' or \ + account == '4110.001' or account == '4120.001' or account == '4120.002' or \ + account == '4140.001' or account == '4140.002' or \ + account == '4150.001' or account == '4150.002' or account == '4150.003' or account == '4150.004' or account == '4150.006' or \ + account == '2141.000' or account == '2110.004': + + revenue[account]['year_to_date'] = revenue[account]['year_to_date'] + ge.credit - ge.debit + if ge.posting_date == today: + revenue[account]['today_actual'] = revenue[account]['today_actual'] + ge.credit - ge.debit + if ge.posting_date >= current_month and ge.posting_date <= today: + revenue[account]['mtd_actual'] = revenue[account]['mtd_actual'] + ge.credit - ge.debit + elif ge.posting_date >= last_month and ge.posting_date < current_month: + revenue[account]['mtd_last_month'] = revenue[account]['mtd_last_month'] + ge.credit - ge.debit + + payment = {} + + mode_of_payment = get_mode_of_payment() + for mp in mode_of_payment: + exist = False + for key in payment: + if mp.name == key: + exist = True + if not exist: + payment[mp.name] = {} + payment[mp.name]['today_actual'] = 0 + payment[mp.name]['mtd_actual'] = 0 + payment[mp.name]['mtd_last_month'] = 0 + payment[mp.name]['year_to_date'] = 0 + + folio_transaction = get_folio_transaction(current_year, next_year) + for ft in folio_transaction: + payment[ft.mode_of_payment]['year_to_date'] = payment[ft.mode_of_payment]['year_to_date'] + ft.amount + if ft.audit_date == today: + payment[ft.mode_of_payment]['today_actual'] = payment[ft.mode_of_payment]['today_actual'] + ft.amount + if ft.audit_date >= current_month and ft.audit_date <= today: + payment[ft.mode_of_payment]['mtd_actual'] = payment[ft.mode_of_payment]['mtd_actual'] + ft.amount + elif ft.audit_date >= last_month and ft.audit_date < current_month: + payment[ft.mode_of_payment]['mtd_last_month'] = payment[ft.mode_of_payment]['mtd_last_month'] + ft.amount + + for key in room: + title = key + indent = 0.0 + + if key == 'Studio Sold' or key == 'Superior Sold' or key == 'Deluxe Sold' or key == 'Executive Sold' or key == 'Suite Sold' or key == 'Studio Reserved' or key == 'Superior Reserved' or key == 'Deluxe Reserved' or key == 'Executive Reserved' or key == 'Suite Reserved': + indent = 1.0 + + today_actual = '{:,}'.format(room[key]['today_actual']).replace(',','.') + mtd_actual = '{:,}'.format(room[key]['mtd_actual']).replace(',','.') + mtd_last_month = '{:,}'.format(room[key]['mtd_last_month']).replace(',','.') + year_to_date = '{:,}'.format(room[key]['year_to_date']).replace(',','.') + + if key == 'Total Room Sold' or key == 'Total Room Reserved': + today_actual = '' + mtd_actual = '' + mtd_last_month = '' + year_to_date = '' + + data.append({ + 'statistic': title, + 'today_actual': today_actual, + 'mtd_actual': mtd_actual, + 'mtd_last_month': mtd_last_month, + 'year_to_date': year_to_date, + 'indent': indent, + 'is_currency': False, + }) + + data.append({ + 'statistic': 'Average Room Rate', + 'today_actual': '{:,}'.format(int(round(average_room_rate['today_actual']))).replace(',','.'), + 'mtd_actual': '{:,}'.format(int(round(average_room_rate['mtd_actual']))).replace(',','.'), + 'mtd_last_month': '{:,}'.format(int(round(average_room_rate['mtd_last_month']))).replace(',','.'), + 'year_to_date': '{:,}'.format(int(round(average_room_rate['year_to_date']))).replace(',','.'), + 'indent': 0.0, + 'is_currency': True, + }) + + total_revenue = {'today_actual': 0, 'mtd_actual': 0, 'mtd_last_month': 0, 'year_to_date': 0} + + for key in revenue: + title = '' + indent = 1.0 + + if key == '4210.001': + title = 'Room Revenue' + indent = 0.0 + elif key == '4110.001': + data.append({ + 'statistic': 'Restaurant Revenue', + 'today_actual': '', + 'mtd_actual': '', + 'mtd_last_month': '', + 'year_to_date': '', + 'indent': 0.0, + 'is_currency': False, + }) + title = 'Breakfast Revenue' + elif key == '4120.001': + title = 'Resto Food' + elif key == '4120.002': + title = 'Resto Beverage' + elif key == '4140.001': + data.append({ + 'statistic': 'Room Service Revenue', + 'today_actual': '', + 'mtd_actual': '', + 'mtd_last_month': '', + 'year_to_date': '', + 'indent': 0.0, + 'is_currency': False, + }) + title = 'Service Food' + elif key == '4140.002': + title = 'Service Beverage' + elif key == '4150.001': + data.append({ + 'statistic': 'Banquet Revenue', + 'today_actual': '', + 'mtd_actual': '', + 'mtd_last_month': '', + 'year_to_date': '', + 'indent': 0.0, + 'is_currency': False, + }) + title = 'Banquet Lunch' + elif key == '4150.002': + title = 'Banquet Dinner' + elif key == '4150.003': + title = 'Banquet Coffee Break' + elif key == '4150.004': + title = 'Banquet Meeting' + elif key == '4150.006': + title = 'Banquet Wedding' + elif key == '2141.000': + data.append({ + 'statistic': 'Total Revenue', + 'today_actual': '{:,}'.format(int(round(total_revenue['today_actual']))).replace(',','.'), + 'mtd_actual': '{:,}'.format(int(round(total_revenue['mtd_actual']))).replace(',','.'), + 'mtd_last_month': '{:,}'.format(int(round(total_revenue['mtd_last_month']))).replace(',','.'), + 'year_to_date': '{:,}'.format(int(round(total_revenue['year_to_date']))).replace(',','.'), + 'indent': 0.0, + 'is_currency': True, + }) + + data.append({ + 'statistic': 'Tax and Service', + 'today_actual': '', + 'mtd_actual': '', + 'mtd_last_month': '', + 'year_to_date': '', + 'indent': 0.0, + 'is_currency': False, + }) + title = 'Tax PB 1' + elif key == '2110.004': + title = 'Service Charge' + + data.append({ + 'statistic': title, + 'today_actual': '{:,}'.format(int(round(revenue[key]['today_actual']))).replace(',','.'), + 'mtd_actual': '{:,}'.format(int(round(revenue[key]['mtd_actual']))).replace(',','.'), + 'mtd_last_month': '{:,}'.format(int(round(revenue[key]['mtd_last_month']))).replace(',','.'), + 'year_to_date': '{:,}'.format(int(round(revenue[key]['year_to_date']))).replace(',','.'), + 'indent': indent, + 'is_currency': True, + }) + + if key != '2141.000' and key != '2110.004': + total_revenue = { + 'today_actual': total_revenue['today_actual'] + revenue[key]['today_actual'], + 'mtd_actual': total_revenue['mtd_actual'] + revenue[key]['mtd_actual'], + 'mtd_last_month': total_revenue['mtd_last_month'] + revenue[key]['mtd_last_month'], + 'year_to_date': total_revenue['year_to_date'] + revenue[key]['year_to_date'] + } + + data.append({ + 'statistic': 'Payment', + 'today_actual': '', + 'mtd_actual': '', + 'mtd_last_month': '', + 'year_to_date': '', + 'indent': 0.0, + 'is_currency': False, + }) + for key in payment: + data.append({ + 'statistic': key, + 'today_actual': '{:,}'.format(int(round(payment[key]['today_actual']))).replace(',','.'), + 'mtd_actual': '{:,}'.format(int(round(payment[key]['mtd_actual']))).replace(',','.'), + 'mtd_last_month': '{:,}'.format(int(round(payment[key]['mtd_last_month']))).replace(',','.'), + 'year_to_date': '{:,}'.format(int(round(payment[key]['year_to_date']))).replace(',','.'), + 'indent': 1.0, + 'is_currency': True, + }) + + return data \ No newline at end of file From fe7aa3035bba8dcb3e5f122382a1e74b4daf7378 Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Sun, 26 Jan 2025 10:36:12 +0200 Subject: [PATCH 07/22] [Fix]: Tax in Folio and Room Charge Posting --- inn/__init__.py | 2 +- .../inn_hotels_setting.json | 128 +- .../inn_room_card_owner_webcard.py | 143 +- .../inn_room_charge_posting.py | 1667 ++++++++++------- 4 files changed, 1069 insertions(+), 871 deletions(-) diff --git a/inn/__init__.py b/inn/__init__.py index 87ede6f1..8820232a 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = '1.1.2' +__version__ = "1.1.3" diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index 242bd24c..f7334597 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -47,6 +47,8 @@ "inn_channel_exclude_tax", "maximum_payment_exclude", "inn_tax_exclude_option", + "column_break_mssu", + "include_tax", "profit_sharing_reservation_section", "guest_account_receiveable", "profit_sharing_account", @@ -74,46 +76,35 @@ "folio_transaction_type", "supervisor_passcode", "folio_default_tab", - "bed_type_section", - "studio", - "superior", - "deluxe", - "executive", - "suite", - "column_break_pekg", - "housekeeping", - "housekeeping_assistant", - "restaurant_user", - "restaurant_supervisor", - "housekeeping_supervisor", - "booking_approver", "folio_transaction_type_section", "package_tax", - "room_charge_tax_service", - "breakfast_charge_tax_service", - "credit_card_administration_fee", "package", + "down_payment", + "additional_charge", + "round_off", + "cancellation_fee", + "late_checkout", + "early_checkin", + "column_break_mtit", + "room_charge_tax_service", "room_charge", - "breakfast_charge", - "refund", - "dp_kamar", "room_payment", + "credit_card_administration_fee", "deposit", - "down_payment", "payment", - "additional_charge", + "laundry", + "fbs_tax_11", + "fbs_service_10", + "column_break_vbod", + "breakfast_charge_tax_service", + "breakfast_charge", + "dp_kamar", + "refund", "restaurant_food", - "restaurant_beverages", - "restaurant_other", "room_service_food", "room_service_beverage", - "fbs_service_10", - "fbs_tax_11", - "round_off", - "laundry", - "cancellation_fee", - "late_checkout", - "early_checkin" + "restaurant_other", + "restaurant_beverages" ], "fields": [ { @@ -683,84 +674,27 @@ "label": "Folio Transaction Type" }, { - "fieldname": "bed_type_section", - "fieldtype": "Section Break", - "label": "Room Type & Role" - }, - { - "fieldname": "studio", - "fieldtype": "Link", - "label": "Studio", - "options": "Inn Room Type" - }, - { - "fieldname": "superior", - "fieldtype": "Link", - "label": "Superior", - "options": "Inn Room Type" - }, - { - "fieldname": "deluxe", - "fieldtype": "Link", - "label": "Deluxe", - "options": "Inn Room Type" - }, - { - "fieldname": "executive", - "fieldtype": "Link", - "label": "Executive", - "options": "Inn Room Type" - }, - { - "fieldname": "suite", - "fieldtype": "Link", - "label": "Suite", - "options": "Inn Room Type" - }, - { - "fieldname": "column_break_pekg", + "fieldname": "column_break_mtit", "fieldtype": "Column Break" }, { - "fieldname": "housekeeping", - "fieldtype": "Link", - "label": "Housekeeping", - "options": "Role" - }, - { - "fieldname": "housekeeping_assistant", - "fieldtype": "Link", - "label": "Housekeeping Assistant", - "options": "Role" - }, - { - "fieldname": "restaurant_user", - "fieldtype": "Link", - "label": "Restaurant User", - "options": "Role" - }, - { - "fieldname": "restaurant_supervisor", - "fieldtype": "Link", - "label": "Restaurant Supervisor", - "options": "Role" + "fieldname": "column_break_vbod", + "fieldtype": "Column Break" }, { - "fieldname": "housekeeping_supervisor", - "fieldtype": "Link", - "label": "Housekeeping Supervisor", - "options": "Role" + "fieldname": "column_break_mssu", + "fieldtype": "Column Break" }, { - "fieldname": "booking_approver", - "fieldtype": "Link", - "label": "Booking Approver", - "options": "Role" + "default": "0", + "fieldname": "include_tax", + "fieldtype": "Check", + "label": "Include Tax" } ], "issingle": 1, "links": [], - "modified": "2025-01-24 21:07:55.122096", + "modified": "2025-01-26 10:35:16.814025", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py b/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py index f4c61040..c1847e06 100644 --- a/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py +++ b/inn/inn_hotels/doctype/inn_room_booking/inn_room_card_owner_webcard.py @@ -65,7 +65,11 @@ def count_sold_room(start_date=None, end_date=None): # Calculate reservations that start before start_date and end after start_date current_sold = frappe.db.get_values( doctype="Inn Room Booking", - filters={"start": ["<", start_date], "end": [">", start_date], "room_availability": "Room Sold"}, + filters={ + "start": ["<", start_date], + "end": [">", start_date], + "room_availability": "Room Sold", + }, fieldname=["start", "end"], as_dict=True, ) @@ -77,11 +81,13 @@ def count_sold_room(start_date=None, end_date=None): days_sold = (room_end_date - start_date).days total_sold += days_sold - # Calculate reservations that start after start_date and before end_date current_sold = frappe.db.get_values( doctype="Inn Room Booking", - filters=[["start", "between", [start_date, end_date]], ["room_availability", "=", "Room Sold"]], + filters=[ + ["start", "between", [start_date, end_date]], + ["room_availability", "=", "Room Sold"], + ], fieldname=["start", "end"], as_dict=True, ) @@ -94,10 +100,7 @@ def count_sold_room(start_date=None, end_date=None): days_sold = (room_end_date - room_start_date).days total_sold += days_sold - return { - "value": total_sold, - "fieldtype": "Int" - } + return {"value": total_sold, "fieldtype": "Int"} @frappe.whitelist() @@ -127,7 +130,11 @@ def count_available_room(start_date=None, end_date=None): # Calculate reservations that start before start_date and end after start_date current_used = frappe.db.get_values( doctype="Inn Room Booking", - filters={"start": ["<", start_date], "end": [">", start_date], "status": ["!=", "Finished"]}, + filters={ + "start": ["<", start_date], + "end": [">", start_date], + "status": ["!=", "Finished"], + }, fieldname=["start", "end"], as_dict=True, ) @@ -139,7 +146,10 @@ def count_available_room(start_date=None, end_date=None): # Calculate reservations that start after start_date and before end_date current_used = frappe.db.get_values( doctype="Inn Room Booking", - filters=[["start", "between", [start_date, end_date]], ["status", "!=", "Finished"]], + filters=[ + ["start", "between", [start_date, end_date]], + ["status", "!=", "Finished"], + ], fieldname=["start", "end"], as_dict=True, ) @@ -176,7 +186,12 @@ def count_ooo_room(start_date=None, end_date=None): # Calculate reservations that start before start_date and end after start_date current_ooo = frappe.db.get_values( doctype="Inn Room Booking", - filters={"start": ["<", start_date], "end": [">", start_date], "room_availability": "Out of Order", "status": ["!=", "Finished"]}, + filters={ + "start": ["<", start_date], + "end": [">", start_date], + "room_availability": "Out of Order", + "status": ["!=", "Finished"], + }, fieldname=["start", "end"], as_dict=True, ) @@ -188,7 +203,11 @@ def count_ooo_room(start_date=None, end_date=None): # Calculate reservations that start after start_date and before end_date current_ooo = frappe.db.get_values( doctype="Inn Room Booking", - filters=[["start", "between", [start_date, end_date]], ["room_availability", "=", "Out of Order"], ["status", "!=", "Finished"]], + filters=[ + ["start", "between", [start_date, end_date]], + ["room_availability", "=", "Out of Order"], + ["status", "!=", "Finished"], + ], fieldname=["start", "end"], as_dict=True, ) @@ -220,12 +239,17 @@ def calculate_total_rate_and_sold(start_date, end_date): # Fetch transaction types dynamically transaction_types = get_transaction_types() - transaction_type_list = tuple(filter(None, [ - transaction_types["room_charge_tax_service"], - transaction_types["breakfast_charge_tax_service"], - transaction_types["room_charge"], - transaction_types["breakfast_charge"], - ])) + transaction_type_list = tuple( + filter( + None, + [ + transaction_types["room_charge_tax_service"], + transaction_types["breakfast_charge_tax_service"], + transaction_types["room_charge"], + transaction_types["breakfast_charge"], + ], + ) + ) if not transaction_type_list: return 0, 0 @@ -248,13 +272,18 @@ def calculate_total_rate_and_sold(start_date, end_date): if not folio_ids: return 0, 0 + folio_ids = ( + f"AND parent = {frappe.db.escape(folio_ids[0])}" + if len(folio_ids) == 1 + else f"AND parent IN {folio_ids}" + ) # Query to calculate total revenue from transactions transaction_query = f""" SELECT SUM(amount) AS total FROM `tabInn Folio Transaction` WHERE audit_date < '{end_date}' AND audit_date >= '{start_date}' - AND parent IN {folio_ids} + {folio_ids} AND transaction_type IN {transaction_type_list} """ total = frappe.db.sql(transaction_query, as_dict=True)[0] @@ -265,7 +294,7 @@ def calculate_total_rate_and_sold(start_date, end_date): SELECT COUNT(*) AS count FROM `tabInn Folio Transaction` WHERE audit_date < '{end_date}' AND audit_date >= '{start_date}' - AND parent IN {folio_ids} + {folio_ids} AND transaction_type = '{transaction_types["room_charge"]}' """ count = frappe.db.sql(count_query, as_dict=True)[0] @@ -283,46 +312,45 @@ def calculate_total_rate_and_sold(start_date, end_date): return total_revenue, count.count - # # calculate reservation start before start_date and reservation end after start date - # current_sold = frappe.db.get_values(doctype="Inn Reservation", filters={"arrival": ["<", start_date], "expected_departure": [ - # ">", start_date]}, fieldname=["name", "arrival", "expected_departure", "room_rate"], as_dict=True) - # reservation_id = [x.name for x in current_sold] - # for ii in current_sold: - # room_end_date = ii.expected_departure - # if room_end_date > end_date: - # room_end_date = end_date - # days_sold = (room_end_date - start_date).days - # total_sold += days_sold +# # calculate reservation start before start_date and reservation end after start date +# current_sold = frappe.db.get_values(doctype="Inn Reservation", filters={"arrival": ["<", start_date], "expected_departure": [ +# ">", start_date]}, fieldname=["name", "arrival", "expected_departure", "room_rate"], as_dict=True) +# reservation_id = [x.name for x in current_sold] +# for ii in current_sold: +# room_end_date = ii.expected_departure +# if room_end_date > end_date: +# room_end_date = end_date - # if ii.room_rate not in cached_rate: - # room_rate = frappe.db.get_value(doctype="Inn Room Rate", filters={ - # "name": ii.room_rate}, fieldname="final_total_rate_amount") - # cached_rate[ii.room_rate] = room_rate +# days_sold = (room_end_date - start_date).days +# total_sold += days_sold - # total_rate += cached_rate[ii.room_rate] * days_sold +# if ii.room_rate not in cached_rate: +# room_rate = frappe.db.get_value(doctype="Inn Room Rate", filters={ +# "name": ii.room_rate}, fieldname="final_total_rate_amount") +# cached_rate[ii.room_rate] = room_rate - # # calculate reservation start after start_date and reservations start before before_date - # current_sold = frappe.db.get_values(doctype="Inn Reservation", filters=[["expected_arrival", "between", [ - # start_date, end_date]]], fieldname=["expected_arrival", "expected_departure", "room_rate"], as_dict=True) - # for ii in current_sold: - # room_start_date = ii.expected_arrival - # room_end_date = ii.expected_departure - # if room_end_date > end_date: - # room_end_date = end_date +# total_rate += cached_rate[ii.room_rate] * days_sold - # days_sold = (room_end_date - room_start_date).days - # total_sold += days_sold +# # calculate reservation start after start_date and reservations start before before_date +# current_sold = frappe.db.get_values(doctype="Inn Reservation", filters=[["expected_arrival", "between", [ +# start_date, end_date]]], fieldname=["expected_arrival", "expected_departure", "room_rate"], as_dict=True) +# for ii in current_sold: +# room_start_date = ii.expected_arrival +# room_end_date = ii.expected_departure +# if room_end_date > end_date: +# room_end_date = end_date - # if ii.room_rate not in cached_rate: - # room_rate = frappe.db.get_value(doctype="Inn Room Rate", filters={ - # "name": ii.room_rate}, fieldname="final_total_rate_amount") - # cached_rate[ii.room_rate] = room_rate - # total_rate += cached_rate[ii.room_rate] * days_sold - - # return total_rate, total_sold +# days_sold = (room_end_date - room_start_date).days +# total_sold += days_sold +# if ii.room_rate not in cached_rate: +# room_rate = frappe.db.get_value(doctype="Inn Room Rate", filters={ +# "name": ii.room_rate}, fieldname="final_total_rate_amount") +# cached_rate[ii.room_rate] = room_rate +# total_rate += cached_rate[ii.room_rate] * days_sold +# return total_rate, total_sold @frappe.whitelist() @@ -331,17 +359,13 @@ def calculate_average_rate(start_date=None, end_date=None): start_date = date.today().isoformat() end_date = date.today() + timedelta(days=1) end_date = end_date.isoformat() - total_rate, total_sold = calculate_total_rate_and_sold( - start_date, end_date) + total_rate, total_sold = calculate_total_rate_and_sold(start_date, end_date) if total_sold == 0: value = 0 else: value = total_rate / total_sold - return { - "value": value, - "fieldtype": "Currency" - } + return {"value": value, "fieldtype": "Currency"} @frappe.whitelist() @@ -353,7 +377,4 @@ def calculate_total_rate(start_date=None, end_date=None): total_rate, _ = calculate_total_rate_and_sold(start_date, end_date) if total_rate is None: total_rate = 0 - return { - "value": total_rate, - "fieldtype": "Currency" - } + return {"value": total_rate, "fieldtype": "Currency"} diff --git a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py index 9b73c648..6e1aeac3 100644 --- a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py +++ b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py @@ -5,747 +5,990 @@ import math import datetime from frappe.model.document import Document -from inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type import get_accounts_from_id +from inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type import ( + get_accounts_from_id, +) from inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction import get_idx from inn.inn_hotels.doctype.inn_audit_log.inn_audit_log import get_last_audit_date -from inn.inn_hotels.doctype.inn_tax.inn_tax import calculate_inn_tax_and_charges, calculate_inn_tax_and_charges_exclude_commision +from inn.inn_hotels.doctype.inn_tax.inn_tax import ( + calculate_inn_tax_and_charges, + calculate_inn_tax_and_charges_exclude_commision, +) from inn.inn_hotels.doctype.inn_channel.inn_channel import check_channel_commission from frappe.utils import flt + class InnRoomChargePosting(Document): - pass + pass + @frappe.whitelist() def is_there_open_room_charge_posting(): - if frappe.get_all('Inn Room Charge Posting', {'status': 'Open'}): - return 1 - else: - return 2 + if frappe.get_all("Inn Room Charge Posting", {"status": "Open"}): + return 1 + else: + return 2 + @frappe.whitelist() def is_there_closed_room_charge_posting_at(): - date = get_last_audit_date().strftime('%Y-%m-%d') + date = get_last_audit_date().strftime("%Y-%m-%d") + + if frappe.db.exists( + "Inn Room Charge Posting", {"audit_date": date, "status": "Closed"} + ): + return 1 + else: + return 2 - if frappe.db.exists('Inn Room Charge Posting', {'audit_date': date, 'status': 'Closed'}): - return 1 - else: - return 2 @frappe.whitelist() def populate_tobe_posted(): - tobe_posted_list = [] - folio_list = frappe.get_all('Inn Folio', filters={'status': 'Open', 'type': 'Guest'}, fields=['*']) - for item in folio_list: - reservation = frappe.get_doc('Inn Reservation', item.reservation_id) - if reservation.status == 'In House' or reservation.status == 'Finish': - room_charge_remark = 'Room Charge: Room Rate (Nett): ' + reservation.actual_room_id + " - " + \ - get_last_audit_date().strftime("%d-%m-%Y") - if not frappe.db.exists('Inn Folio Transaction', - {'parent': item.name, 'transaction_type': 'Room Charge', 'remark': room_charge_remark, 'is_void': 0}): - tobe_posted = frappe.new_doc('Inn Room Charge To Be Posted') - tobe_posted.reservation_id = item.reservation_id - tobe_posted.folio_id = item.name - tobe_posted.room_id = reservation.actual_room_id - tobe_posted.customer_id = reservation.customer_id - tobe_posted.room_rate_id = reservation.room_rate - tobe_posted.actual_room_rate = reservation.actual_room_rate - tobe_posted_list.append(tobe_posted) - return tobe_posted_list + tobe_posted_list = [] + folio_list = frappe.get_all( + "Inn Folio", filters={"status": "Open", "type": "Guest"}, fields=["*"] + ) + for item in folio_list: + reservation = frappe.get_doc("Inn Reservation", item.reservation_id) + if reservation.status == "In House" or reservation.status == "Finish": + room_charge_remark = ( + "Room Charge: Room Rate (Nett): " + + reservation.actual_room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + if not frappe.db.exists( + "Inn Folio Transaction", + { + "parent": item.name, + "transaction_type": "Room Charge", + "remark": room_charge_remark, + "is_void": 0, + }, + ): + tobe_posted = frappe.new_doc("Inn Room Charge To Be Posted") + tobe_posted.reservation_id = item.reservation_id + tobe_posted.folio_id = item.name + tobe_posted.room_id = reservation.actual_room_id + tobe_posted.customer_id = reservation.customer_id + tobe_posted.room_rate_id = reservation.room_rate + tobe_posted.actual_room_rate = reservation.actual_room_rate + tobe_posted_list.append(tobe_posted) + return tobe_posted_list + @frappe.whitelist() def post_individual_room_charges(parent_id, tobe_posted_list): - # Fetch all transaction types from Inn Hotels Setting - hotel_settings = frappe.get_doc("Inn Hotels Setting") - transaction_types = { - "room_charge_tax_service": hotel_settings.room_charge_tax_service, - "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, - "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, - "package": hotel_settings.package, - "room_charge": hotel_settings.room_charge, - "breakfast_charge": hotel_settings.breakfast_charge, - "refund": hotel_settings.refund, - "dp_kamar": hotel_settings.dp_kamar, - "room_payment": hotel_settings.room_payment, - "deposit": hotel_settings.deposit, - "down_payment": hotel_settings.down_payment, - "payment": hotel_settings.payment, - "additional_charge": hotel_settings.additional_charge, - "restaurant_food": hotel_settings.restaurant_food, - "restaurant_beverages": hotel_settings.restaurant_beverages, - "restaurant_other": hotel_settings.restaurant_other, - "room_service_food": hotel_settings.room_service_food, - "room_service_beverage": hotel_settings.room_service_beverage, - "fbs_service_10": hotel_settings.fbs_service_10, - "fbs_tax_11": hotel_settings.fbs_tax_11, - "round_off": hotel_settings.round_off, - "laundry": hotel_settings.laundry, - "cancellation_fee": hotel_settings.cancellation_fee, - "late_checkout": hotel_settings.late_checkout, - "early_checkin": hotel_settings.early_checkin, - } - - # to exclude service charge from reduced because of commision / cashback - room_post_settings = frappe.db.get_values_from_single(doctype="Inn Hotels Setting", filters="", fields=["profit_sharing_account", "profit_sharing_transaction_type"], as_dict=True)[0] - PROFIT_SHARING_ACCOUNT = room_post_settings.profit_sharing_account - COMMISION_TRANSACTION_TYPE = room_post_settings.profit_sharing_transaction_type - - channel_exclude_tax = frappe.get_list("Inn Channel Tax Exclude", - parent_doctype='Inn Hotels Setting', - filters = { - "parenttype": "Inn Hotels Setting", - "parent": "Inn Hotels Setting", - "parentfield": "inn_channel_exclude_tax" - }, pluck="channel") - inn_settings = frappe.get_value("Inn Hotels Setting", None, ["maximum_payment_exclude", "inn_tax_exclude_option"], as_dict=1) - maximum_price_exclude_tax = inn_settings.maximum_payment_exclude - inn_tax_exclude = inn_settings.inn_tax_exclude_option - return_value = '' - room_charge_posting_doc = frappe.get_doc('Inn Room Charge Posting', parent_id) - list_json = json.loads(tobe_posted_list) - # for difference calculations - fdc_reservation = '' - fdc_folio_trx_tax_name = '' - for item in list_json: - # Create Inn Folio Transaction Bundle - ftb_doc = frappe.new_doc('Inn Folio Transaction Bundle') - ftb_doc.transaction_type = transaction_types["room_charge"] # Use dynamic value - ftb_doc.insert() - - # Posting Room Charge - item_doc = frappe.get_doc('Inn Room Charge To Be Posted', item) - accumulated_amount = 0.00 - room_charge_debit_account, room_charge_credit_account = get_accounts_from_id(transaction_types["room_charge"]) # Use dynamic value - reservation = frappe.get_doc('Inn Reservation', item_doc.reservation_id) - is_exclude_tax = False - if (reservation.channel in channel_exclude_tax) or (reservation.actual_room_rate <= flt(maximum_price_exclude_tax)): - reservation.actual_room_rate_tax = inn_tax_exclude - reservation.actual_breakfast_rate_tax = inn_tax_exclude - is_exclude_tax = True - recalculate_nett_charge(reservation) - - fdc_reservation = reservation - - # check if channel is commission - channel = check_channel_commission(reservation) - is_channel_commision = True - if channel.profit_sharing == 0: - is_channel_commision = False - - room_charge_folio_trx = frappe.new_doc('Inn Folio Transaction') - room_charge_folio_trx.flag = 'Debit' - room_charge_folio_trx.is_void = 0 - room_charge_folio_trx.idx = get_idx(item_doc.folio_id) - room_charge_folio_trx.transaction_type = transaction_types["room_charge"] # Use dynamic value - room_charge_folio_trx.amount = float(int(reservation.nett_actual_room_rate)) - accumulated_amount += float(int(reservation.nett_actual_room_rate)) - room_charge_folio_trx.debit_account = room_charge_debit_account - room_charge_folio_trx.credit_account = room_charge_credit_account - room_charge_folio_trx.remark = 'Room Charge: Room Rate (Nett): ' + item_doc.room_id + " - " + get_last_audit_date().strftime("%d-%m-%Y") - room_charge_folio_trx.actual_room_rate = reservation.actual_room_rate - room_charge_folio_trx.parent = item_doc.folio_id - room_charge_folio_trx.parenttype = 'Inn Folio' - room_charge_folio_trx.parentfield = 'folio_transaction' - room_charge_folio_trx.ftb_id = ftb_doc.name - room_charge_folio_trx.insert() - - return_value = return_value + '
  • ' + room_charge_folio_trx.remark + '
  • ' - - # Create Inn Folio Transaction Bundle Detail Item Room Charge - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = room_charge_folio_trx.transaction_type - ftbd_doc.transaction_id = room_charge_folio_trx.name - ftb_doc.append('transaction_detail', ftbd_doc) - - fdc_room_rate = frappe.get_doc('Inn Room Rate', fdc_reservation.room_rate) - fdc_room_rate_tax = frappe.get_doc('Inn Tax', fdc_room_rate.room_rate_tax) - fdc_room_rate_tax_breakdown = fdc_room_rate_tax.inn_tax_breakdown - if fdc_room_rate_tax_breakdown[-1].breakdown_rate != 0.0: - fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[-1].breakdown_account - else: - fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[-2].breakdown_account - - # get tax breakdown account from reservation - if is_exclude_tax: - fdc_room_rate_tax = frappe.get_doc("Inn Tax", reservation.actual_room_rate_tax) - fdc_room_rate_tax_account = fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_account if fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_rate != 0 else fdc_room_rate_tax.inn_tax_breakdown[-2].breakdown_account - - if is_channel_commision: - # add commission first - room_commision_doc = frappe.new_doc('Inn Folio Transaction') - room_commision_doc.flag = 'Debit' - room_commision_doc.is_void = 0 - room_commision_doc.idx = get_idx(item_doc.folio_id) - - room_commision_doc.transaction_type = COMMISION_TRANSACTION_TYPE - room_commision_doc.amount = float(int(channel.room_cashback)) - accumulated_amount += float(int(channel.room_cashback)) - room_commision_doc.credit_account = PROFIT_SHARING_ACCOUNT - room_commision_doc.debit_account = room_charge_debit_account - room_commision_doc.remark = 'Commission ' + channel.name + ' : ' + item_doc.room_id + " - " + get_last_audit_date().strftime("%d-%m-%Y") - room_commision_doc.parent = item_doc.folio_id - room_commision_doc.parenttype = 'Inn Folio' - room_commision_doc.parentfield = 'folio_transaction' - room_commision_doc.ftb_id = ftb_doc.name - room_commision_doc.insert() - - # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = room_commision_doc.transaction_type - ftbd_doc.transaction_id = room_commision_doc.name - ftb_doc.append('transaction_detail', ftbd_doc) - - # Posting Room Charge Tax/Service - room_tb_id, room_tb_amount, _ = calculate_inn_tax_and_charges(reservation.nett_actual_room_rate, - reservation.actual_room_rate_tax) - - # Posting Room Charge Tax/Service - for index, room_tax_item_name in enumerate(room_tb_id): - room_tax_doc = frappe.new_doc('Inn Folio Transaction') - room_tax_doc.flag = 'Debit' - room_tax_doc.is_void = 0 - room_tax_doc.idx = get_idx(item_doc.folio_id) - room_tax_doc.transaction_type = transaction_types["room_charge_tax_service"] - room_tax_doc.amount = room_tb_amount[index] - accumulated_amount += room_tb_amount[index] - room_tax_doc.credit_account = frappe.get_doc('Inn Tax Breakdown', room_tax_item_name).breakdown_account - room_tax_doc.debit_account = room_charge_debit_account - room_tax_doc.remark = 'Room Charge Tax Room Rate ' + room_tax_item_name + ' : ' + item_doc.room_id + " - " + get_last_audit_date().strftime("%d-%m-%Y") - room_tax_doc.parent = item_doc.folio_id - room_tax_doc.parenttype = 'Inn Folio' - room_tax_doc.parentfield = 'folio_transaction' - room_tax_doc.ftb_id = ftb_doc.name - room_tax_doc.insert() - - if room_tax_doc.credit_account == fdc_room_rate_tax_account: - fdc_folio_trx_tax_name = room_tax_doc.name - - # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = room_tax_doc.transaction_type - ftbd_doc.transaction_id = room_tax_doc.name - ftb_doc.append('transaction_detail', ftbd_doc) - - - ## corner case: if breakfast charge is 0 then don't post any breakfast related to Folio - breakfast_price = float(int(reservation.nett_actual_breakfast_rate)) - if breakfast_price > 0: - # Posting Breakfast Charge - breakfast_charge_debit_account, breakfast_charge_credit_account = get_accounts_from_id(transaction_types["breakfast_charge"]) - breakfast_charge_folio_trx = frappe.new_doc('Inn Folio Transaction') - breakfast_charge_folio_trx.flag = 'Debit' - breakfast_charge_folio_trx.is_void = 0 - breakfast_charge_folio_trx.idx = get_idx(item_doc.folio_id) - breakfast_charge_folio_trx.transaction_type = transaction_types["breakfast_charge"] - breakfast_charge_folio_trx.amount = float(int(reservation.nett_actual_breakfast_rate)) - accumulated_amount += float(int(reservation.nett_actual_breakfast_rate)) - breakfast_charge_folio_trx.debit_account = breakfast_charge_debit_account - breakfast_charge_folio_trx.credit_account = breakfast_charge_credit_account - breakfast_charge_folio_trx.remark = 'Room Charge: Breakfast (Nett): ' + item_doc.room_id + " - " + get_last_audit_date().strftime("%d-%m-%Y") - breakfast_charge_folio_trx.parent = item_doc.folio_id - breakfast_charge_folio_trx.parenttype = 'Inn Folio' - breakfast_charge_folio_trx.parentfield = 'folio_transaction' - breakfast_charge_folio_trx.ftb_id = ftb_doc.name - breakfast_charge_folio_trx.insert() - - # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = breakfast_charge_folio_trx.transaction_type - ftbd_doc.transaction_id = breakfast_charge_folio_trx.name - ftb_doc.append('transaction_detail', ftbd_doc) - - - if is_channel_commision: - # add commission first - breakfast_commission = frappe.new_doc('Inn Folio Transaction') - breakfast_commission.flag = 'Debit' - breakfast_commission.is_void = 0 - breakfast_commission.idx = get_idx(item_doc.folio_id) - - breakfast_commission.transaction_type = COMMISION_TRANSACTION_TYPE - breakfast_commission.amount = float(int(channel.breakfast_cashback)) - accumulated_amount += float(int(channel.breakfast_cashback)) - breakfast_commission.credit_account = PROFIT_SHARING_ACCOUNT - breakfast_commission.debit_account = breakfast_charge_debit_account - breakfast_commission.remark = 'Commission ' + channel.name + ' : ' + item_doc.room_id + " - " + get_last_audit_date().strftime("%d-%m-%Y") - breakfast_commission.parent = item_doc.folio_id - breakfast_commission.parenttype = 'Inn Folio' - breakfast_commission.parentfield = 'folio_transaction' - breakfast_commission.ftb_id = ftb_doc.name - breakfast_commission.insert() - - # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = breakfast_commission.transaction_type - ftbd_doc.transaction_id = breakfast_commission.name - ftb_doc.append('transaction_detail', ftbd_doc) - - # Posting Breakfast Tax/Service - breakfast_tb_id, breakfast_tb_amount, _ = calculate_inn_tax_and_charges(reservation.nett_actual_breakfast_rate, - reservation.actual_breakfast_rate_tax) - - # Posting Breakfast Tax/Service - for index, breakfast_tax_item_name in enumerate(breakfast_tb_id): - breakfast_tax_doc = frappe.new_doc('Inn Folio Transaction') - breakfast_tax_doc.flag = 'Debit' - breakfast_tax_doc.is_void = 0 - breakfast_tax_doc.idx = get_idx(item_doc.folio_id) - breakfast_tax_doc.transaction_type = transaction_types["breakfast_charge_tax_service"] - breakfast_tax_doc.amount = breakfast_tb_amount[index] - accumulated_amount += breakfast_tb_amount[index] - breakfast_tax_doc.credit_account = frappe.get_doc('Inn Tax Breakdown', - breakfast_tax_item_name).breakdown_account - breakfast_tax_doc.debit_account = breakfast_charge_debit_account - breakfast_tax_doc.remark = 'Breakfast Charge Tax Room Rate ' + breakfast_tax_item_name + ' : ' + item_doc.room_id + " - " + get_last_audit_date().strftime("%d-%m-%Y") - breakfast_tax_doc.parent = item_doc.folio_id - breakfast_tax_doc.parenttype = 'Inn Folio' - breakfast_tax_doc.parentfield = 'folio_transaction' - breakfast_tax_doc.ftb_id = ftb_doc.name - breakfast_tax_doc.insert() - - # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge Tax/Service - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = breakfast_tax_doc.transaction_type - ftbd_doc.transaction_id = breakfast_tax_doc.name - ftb_doc.append('transaction_detail', ftbd_doc) - - print("accumulated amount = " + str(accumulated_amount)) - print("math_ceil(accumulated amount) = " + str(math.ceil(accumulated_amount))) - print("actual room rate = " + str(reservation.actual_room_rate)) - print ("abs = " + str(abs(math.ceil(accumulated_amount) - int(reservation.actual_room_rate)))) - if abs(math.ceil(accumulated_amount) - int(reservation.actual_room_rate)) != 0: - difference = math.ceil(accumulated_amount) - int(reservation.actual_room_rate) - - if breakfast_price > 0: - # hasil perhitungan lebih besar daripada room rate yang tersimpan di db - if difference > 0: - adjusted_room_charge_amount = room_charge_folio_trx.amount - adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount - for i in range(0, abs(difference)): - adjusted_room_charge_amount = adjusted_room_charge_amount - 1.0 - # hasil perhitungan lebih kecil daripada room rate yang tersimpan di db - elif difference < 0: - adjusted_room_charge_amount = room_charge_folio_trx.amount - adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount - fdc_folio_trx_tax = frappe.get_doc('Inn Folio Transaction', fdc_folio_trx_tax_name) - adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount - for i in range(0, abs(difference)): - adjusted_room_rate_tax_amount = adjusted_room_rate_tax_amount + 1.0 - fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount - fdc_folio_trx_tax.save() - - room_charge_folio_trx.amount = adjusted_room_charge_amount - room_charge_folio_trx.save() - breakfast_charge_folio_trx.amount = adjusted_breakfast_charge_amount - breakfast_charge_folio_trx.save() - - else: - if difference > 0: - adjusted_room_charge_amount = room_charge_folio_trx.amount - for i in range(0, abs(difference)): - adjusted_room_charge_amount = adjusted_room_charge_amount - 1.0 - elif difference < 0: - adjusted_room_charge_amount = room_charge_folio_trx.amount - fdc_folio_trx_tax = frappe.get_doc('Inn Folio Transaction', fdc_folio_trx_tax_name) - adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount - for i in range(0, abs(difference)): - adjusted_room_rate_tax_amount = adjusted_room_rate_tax_amount + 1.0 - fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount - fdc_folio_trx_tax.save() - - room_charge_folio_trx.amount = adjusted_room_charge_amount - room_charge_folio_trx.save() - - - # Resave Bundle to save Detail - ftb_doc.save() - - posted = frappe.new_doc('Inn Room Charge Posted') - posted.reservation_id = item_doc.reservation_id - posted.folio_id = item_doc.folio_id - posted.room_id = item_doc.room_id - posted.customer_id = item_doc.customer_id - posted.room_rate_id = item_doc.room_rate_id - posted.actual_room_rate = item_doc.actual_room_rate - posted.folio_transaction_id = room_charge_folio_trx.name - posted.parent = parent_id - posted.parentfield = 'already_posted' - posted.parenttype = 'Inn Room Charge Posting' - room_charge_posting_doc.append('already_posted', posted) - - frappe.delete_doc('Inn Room Charge To Be Posted', item_doc.name) - - room_charge_posting_doc.save() - calculate_already_posted_total(room_charge_posting_doc.name) - - return return_value + # Fetch all transaction types from Inn Hotels Setting + hotel_settings = frappe.get_doc("Inn Hotels Setting") + transaction_types = { + "room_charge_tax_service": hotel_settings.room_charge_tax_service, + "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, + "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, + "package": hotel_settings.package, + "room_charge": hotel_settings.room_charge, + "breakfast_charge": hotel_settings.breakfast_charge, + "refund": hotel_settings.refund, + "dp_kamar": hotel_settings.dp_kamar, + "room_payment": hotel_settings.room_payment, + "deposit": hotel_settings.deposit, + "down_payment": hotel_settings.down_payment, + "payment": hotel_settings.payment, + "additional_charge": hotel_settings.additional_charge, + "restaurant_food": hotel_settings.restaurant_food, + "restaurant_beverages": hotel_settings.restaurant_beverages, + "restaurant_other": hotel_settings.restaurant_other, + "room_service_food": hotel_settings.room_service_food, + "room_service_beverage": hotel_settings.room_service_beverage, + "fbs_service_10": hotel_settings.fbs_service_10, + "fbs_tax_11": hotel_settings.fbs_tax_11, + "round_off": hotel_settings.round_off, + "laundry": hotel_settings.laundry, + "cancellation_fee": hotel_settings.cancellation_fee, + "late_checkout": hotel_settings.late_checkout, + "early_checkin": hotel_settings.early_checkin, + } + + # to exclude service charge from reduced because of commision / cashback + room_post_settings = frappe.db.get_values_from_single( + doctype="Inn Hotels Setting", + filters="", + fields=["profit_sharing_account", "profit_sharing_transaction_type"], + as_dict=True, + )[0] + PROFIT_SHARING_ACCOUNT = room_post_settings.profit_sharing_account + COMMISION_TRANSACTION_TYPE = room_post_settings.profit_sharing_transaction_type + + channel_exclude_tax = frappe.get_list( + "Inn Channel Tax Exclude", + parent_doctype="Inn Hotels Setting", + filters={ + "parenttype": "Inn Hotels Setting", + "parent": "Inn Hotels Setting", + "parentfield": "inn_channel_exclude_tax", + }, + pluck="channel", + ) + inn_settings = frappe.get_value( + "Inn Hotels Setting", + None, + ["maximum_payment_exclude", "inn_tax_exclude_option"], + as_dict=1, + ) + maximum_price_exclude_tax = inn_settings.maximum_payment_exclude + inn_tax_exclude = inn_settings.inn_tax_exclude_option + return_value = "" + room_charge_posting_doc = frappe.get_doc("Inn Room Charge Posting", parent_id) + list_json = json.loads(tobe_posted_list) + # for difference calculations + fdc_reservation = "" + fdc_folio_trx_tax_name = "" + for item in list_json: + # Create Inn Folio Transaction Bundle + ftb_doc = frappe.new_doc("Inn Folio Transaction Bundle") + ftb_doc.transaction_type = transaction_types["room_charge"] # Use dynamic value + ftb_doc.insert() + + # Posting Room Charge + item_doc = frappe.get_doc("Inn Room Charge To Be Posted", item) + accumulated_amount = 0.00 + room_charge_debit_account, room_charge_credit_account = get_accounts_from_id( + transaction_types["room_charge"] + ) # Use dynamic value + reservation = frappe.get_doc("Inn Reservation", item_doc.reservation_id) + is_exclude_tax = False + if (reservation.channel in channel_exclude_tax) or ( + reservation.actual_room_rate <= flt(maximum_price_exclude_tax) + ): + reservation.actual_room_rate_tax = inn_tax_exclude + reservation.actual_breakfast_rate_tax = inn_tax_exclude + is_exclude_tax = True + recalculate_nett_charge(reservation) + + fdc_reservation = reservation + + # check if channel is commission + channel = check_channel_commission(reservation) + is_channel_commision = True + if channel.profit_sharing == 0: + is_channel_commision = False + + room_charge_folio_trx = frappe.new_doc("Inn Folio Transaction") + room_charge_folio_trx.flag = "Debit" + room_charge_folio_trx.is_void = 0 + room_charge_folio_trx.idx = get_idx(item_doc.folio_id) + room_charge_folio_trx.transaction_type = transaction_types[ + "room_charge" + ] # Use dynamic value + room_charge_folio_trx.amount = float(int(reservation.nett_actual_room_rate)) + accumulated_amount += float(int(reservation.nett_actual_room_rate)) + room_charge_folio_trx.debit_account = room_charge_debit_account + room_charge_folio_trx.credit_account = room_charge_credit_account + room_charge_folio_trx.remark = ( + "Room Charge: Room Rate (Nett): " + + item_doc.room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + room_charge_folio_trx.actual_room_rate = reservation.actual_room_rate + room_charge_folio_trx.parent = item_doc.folio_id + room_charge_folio_trx.parenttype = "Inn Folio" + room_charge_folio_trx.parentfield = "folio_transaction" + room_charge_folio_trx.ftb_id = ftb_doc.name + room_charge_folio_trx.insert() + + return_value = return_value + "
  • " + room_charge_folio_trx.remark + "
  • " + + # Create Inn Folio Transaction Bundle Detail Item Room Charge + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = room_charge_folio_trx.transaction_type + ftbd_doc.transaction_id = room_charge_folio_trx.name + ftb_doc.append("transaction_detail", ftbd_doc) + + fdc_room_rate = frappe.get_doc("Inn Room Rate", fdc_reservation.room_rate) + fdc_room_rate_tax = frappe.get_doc("Inn Tax", fdc_room_rate.room_rate_tax) + fdc_room_rate_tax_breakdown = fdc_room_rate_tax.inn_tax_breakdown + if fdc_room_rate_tax_breakdown[-1].breakdown_rate != 0.0: + fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ + -1 + ].breakdown_account + else: + fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ + -2 + ].breakdown_account + + # get tax breakdown account from reservation + if is_exclude_tax: + fdc_room_rate_tax = frappe.get_doc( + "Inn Tax", reservation.actual_room_rate_tax + ) + fdc_room_rate_tax_account = ( + fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_account + if fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_rate != 0 + else fdc_room_rate_tax.inn_tax_breakdown[-2].breakdown_account + ) + + if is_channel_commision: + # add commission first + room_commision_doc = frappe.new_doc("Inn Folio Transaction") + room_commision_doc.flag = "Debit" + room_commision_doc.is_void = 0 + room_commision_doc.idx = get_idx(item_doc.folio_id) + + room_commision_doc.transaction_type = COMMISION_TRANSACTION_TYPE + room_commision_doc.amount = float(int(channel.room_cashback)) + accumulated_amount += float(int(channel.room_cashback)) + room_commision_doc.credit_account = PROFIT_SHARING_ACCOUNT + room_commision_doc.debit_account = room_charge_debit_account + room_commision_doc.remark = ( + "Commission " + + channel.name + + " : " + + item_doc.room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + room_commision_doc.parent = item_doc.folio_id + room_commision_doc.parenttype = "Inn Folio" + room_commision_doc.parentfield = "folio_transaction" + room_commision_doc.ftb_id = ftb_doc.name + room_commision_doc.insert() + + # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = room_commision_doc.transaction_type + ftbd_doc.transaction_id = room_commision_doc.name + ftb_doc.append("transaction_detail", ftbd_doc) + + # Posting Room Charge Tax/Service + room_tb_id, room_tb_amount, _ = calculate_inn_tax_and_charges( + reservation.nett_actual_room_rate, reservation.actual_room_rate_tax + ) + + # Posting Room Charge Tax/Service + for index, room_tax_item_name in enumerate(room_tb_id): + room_tax_doc = frappe.new_doc("Inn Folio Transaction") + room_tax_doc.flag = "Debit" + room_tax_doc.is_void = 0 + room_tax_doc.idx = get_idx(item_doc.folio_id) + room_tax_doc.transaction_type = transaction_types["room_charge_tax_service"] + room_tax_doc.amount = room_tb_amount[index] + accumulated_amount += room_tb_amount[index] + room_tax_doc.credit_account = frappe.get_doc( + "Inn Tax Breakdown", room_tax_item_name + ).breakdown_account + room_tax_doc.debit_account = room_charge_debit_account + room_tax_doc.remark = ( + "Room Charge Tax Room Rate " + + room_tax_item_name + + " : " + + item_doc.room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + room_tax_doc.parent = item_doc.folio_id + room_tax_doc.parenttype = "Inn Folio" + room_tax_doc.parentfield = "folio_transaction" + room_tax_doc.ftb_id = ftb_doc.name + room_tax_doc.insert() + + if room_tax_doc.credit_account == fdc_room_rate_tax_account: + fdc_folio_trx_tax_name = room_tax_doc.name + + # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = room_tax_doc.transaction_type + ftbd_doc.transaction_id = room_tax_doc.name + ftb_doc.append("transaction_detail", ftbd_doc) + + ## corner case: if breakfast charge is 0 then don't post any breakfast related to Folio + breakfast_price = float(int(reservation.nett_actual_breakfast_rate)) + if breakfast_price > 0: + # Posting Breakfast Charge + breakfast_charge_debit_account, breakfast_charge_credit_account = ( + get_accounts_from_id(transaction_types["breakfast_charge"]) + ) + breakfast_charge_folio_trx = frappe.new_doc("Inn Folio Transaction") + breakfast_charge_folio_trx.flag = "Debit" + breakfast_charge_folio_trx.is_void = 0 + breakfast_charge_folio_trx.idx = get_idx(item_doc.folio_id) + breakfast_charge_folio_trx.transaction_type = transaction_types[ + "breakfast_charge" + ] + breakfast_charge_folio_trx.amount = float( + int(reservation.nett_actual_breakfast_rate) + ) + accumulated_amount += float(int(reservation.nett_actual_breakfast_rate)) + breakfast_charge_folio_trx.debit_account = breakfast_charge_debit_account + breakfast_charge_folio_trx.credit_account = breakfast_charge_credit_account + breakfast_charge_folio_trx.remark = ( + "Room Charge: Breakfast (Nett): " + + item_doc.room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + breakfast_charge_folio_trx.parent = item_doc.folio_id + breakfast_charge_folio_trx.parenttype = "Inn Folio" + breakfast_charge_folio_trx.parentfield = "folio_transaction" + breakfast_charge_folio_trx.ftb_id = ftb_doc.name + breakfast_charge_folio_trx.insert() + + # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = breakfast_charge_folio_trx.transaction_type + ftbd_doc.transaction_id = breakfast_charge_folio_trx.name + ftb_doc.append("transaction_detail", ftbd_doc) + + if is_channel_commision: + # add commission first + breakfast_commission = frappe.new_doc("Inn Folio Transaction") + breakfast_commission.flag = "Debit" + breakfast_commission.is_void = 0 + breakfast_commission.idx = get_idx(item_doc.folio_id) + + breakfast_commission.transaction_type = COMMISION_TRANSACTION_TYPE + breakfast_commission.amount = float(int(channel.breakfast_cashback)) + accumulated_amount += float(int(channel.breakfast_cashback)) + breakfast_commission.credit_account = PROFIT_SHARING_ACCOUNT + breakfast_commission.debit_account = breakfast_charge_debit_account + breakfast_commission.remark = ( + "Commission " + + channel.name + + " : " + + item_doc.room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + breakfast_commission.parent = item_doc.folio_id + breakfast_commission.parenttype = "Inn Folio" + breakfast_commission.parentfield = "folio_transaction" + breakfast_commission.ftb_id = ftb_doc.name + breakfast_commission.insert() + + # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = breakfast_commission.transaction_type + ftbd_doc.transaction_id = breakfast_commission.name + ftb_doc.append("transaction_detail", ftbd_doc) + + # Posting Breakfast Tax/Service + breakfast_tb_id, breakfast_tb_amount, _ = calculate_inn_tax_and_charges( + reservation.nett_actual_breakfast_rate, + reservation.actual_breakfast_rate_tax, + ) + + # Posting Breakfast Tax/Service + for index, breakfast_tax_item_name in enumerate(breakfast_tb_id): + breakfast_tax_doc = frappe.new_doc("Inn Folio Transaction") + breakfast_tax_doc.flag = "Debit" + breakfast_tax_doc.is_void = 0 + breakfast_tax_doc.idx = get_idx(item_doc.folio_id) + breakfast_tax_doc.transaction_type = transaction_types[ + "breakfast_charge_tax_service" + ] + breakfast_tax_doc.amount = breakfast_tb_amount[index] + accumulated_amount += breakfast_tb_amount[index] + breakfast_tax_doc.credit_account = frappe.get_doc( + "Inn Tax Breakdown", breakfast_tax_item_name + ).breakdown_account + breakfast_tax_doc.debit_account = breakfast_charge_debit_account + breakfast_tax_doc.remark = ( + "Breakfast Charge Tax Room Rate " + + breakfast_tax_item_name + + " : " + + item_doc.room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + breakfast_tax_doc.parent = item_doc.folio_id + breakfast_tax_doc.parenttype = "Inn Folio" + breakfast_tax_doc.parentfield = "folio_transaction" + breakfast_tax_doc.ftb_id = ftb_doc.name + breakfast_tax_doc.insert() + + # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = breakfast_tax_doc.transaction_type + ftbd_doc.transaction_id = breakfast_tax_doc.name + ftb_doc.append("transaction_detail", ftbd_doc) + + print("accumulated amount = " + str(accumulated_amount)) + print("math_ceil(accumulated amount) = " + str(math.ceil(accumulated_amount))) + print("actual room rate = " + str(reservation.actual_room_rate)) + print( + "abs = " + + str( + abs(math.ceil(accumulated_amount) - int(reservation.actual_room_rate)) + ) + ) + if abs(math.ceil(accumulated_amount) - int(reservation.actual_room_rate)) != 0: + difference = math.ceil(accumulated_amount) - int( + reservation.actual_room_rate + ) + + if breakfast_price > 0: + # hasil perhitungan lebih besar daripada room rate yang tersimpan di db + if difference > 0: + adjusted_room_charge_amount = room_charge_folio_trx.amount + adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount + for i in range(0, abs(difference)): + adjusted_room_charge_amount = adjusted_room_charge_amount - 1.0 + # hasil perhitungan lebih kecil daripada room rate yang tersimpan di db + elif difference < 0: + adjusted_room_charge_amount = room_charge_folio_trx.amount + adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount + fdc_folio_trx_tax = frappe.get_doc( + "Inn Folio Transaction", fdc_folio_trx_tax_name + ) + adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount + for i in range(0, abs(difference)): + adjusted_room_rate_tax_amount = ( + adjusted_room_rate_tax_amount + 1.0 + ) + fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount + fdc_folio_trx_tax.save() + + room_charge_folio_trx.amount = adjusted_room_charge_amount + room_charge_folio_trx.save() + breakfast_charge_folio_trx.amount = adjusted_breakfast_charge_amount + breakfast_charge_folio_trx.save() + + else: + if difference > 0: + adjusted_room_charge_amount = room_charge_folio_trx.amount + for i in range(0, abs(difference)): + adjusted_room_charge_amount = adjusted_room_charge_amount - 1.0 + elif difference < 0: + adjusted_room_charge_amount = room_charge_folio_trx.amount + fdc_folio_trx_tax = frappe.get_doc( + "Inn Folio Transaction", fdc_folio_trx_tax_name + ) + adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount + for i in range(0, abs(difference)): + adjusted_room_rate_tax_amount = ( + adjusted_room_rate_tax_amount + 1.0 + ) + fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount + fdc_folio_trx_tax.save() + + room_charge_folio_trx.amount = adjusted_room_charge_amount + room_charge_folio_trx.save() + + # Resave Bundle to save Detail + ftb_doc.save() + + posted = frappe.new_doc("Inn Room Charge Posted") + posted.reservation_id = item_doc.reservation_id + posted.folio_id = item_doc.folio_id + posted.room_id = item_doc.room_id + posted.customer_id = item_doc.customer_id + posted.room_rate_id = item_doc.room_rate_id + posted.actual_room_rate = item_doc.actual_room_rate + posted.folio_transaction_id = room_charge_folio_trx.name + posted.parent = parent_id + posted.parentfield = "already_posted" + posted.parenttype = "Inn Room Charge Posting" + room_charge_posting_doc.append("already_posted", posted) + + frappe.delete_doc("Inn Room Charge To Be Posted", item_doc.name) + + room_charge_posting_doc.save() + calculate_already_posted_total(room_charge_posting_doc.name) + + return return_value + @frappe.whitelist() def post_room_charges(parent_id, tobe_posted_list): - # Fetch all transaction types from Inn Hotels Setting - hotel_settings = frappe.get_doc("Inn Hotels Setting") - transaction_types = { - "room_charge_tax_service": hotel_settings.room_charge_tax_service, - "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, - "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, - "package": hotel_settings.package, - "room_charge": hotel_settings.room_charge, - "breakfast_charge": hotel_settings.breakfast_charge, - "refund": hotel_settings.refund, - "dp_kamar": hotel_settings.dp_kamar, - "room_payment": hotel_settings.room_payment, - "deposit": hotel_settings.deposit, - "down_payment": hotel_settings.down_payment, - "payment": hotel_settings.payment, - "additional_charge": hotel_settings.additional_charge, - "restaurant_food": hotel_settings.restaurant_food, - "restaurant_beverages": hotel_settings.restaurant_beverages, - "restaurant_other": hotel_settings.restaurant_other, - "room_service_food": hotel_settings.room_service_food, - "room_service_beverage": hotel_settings.room_service_beverage, - "fbs_service_10": hotel_settings.fbs_service_10, - "fbs_tax_11": hotel_settings.fbs_tax_11, - "round_off": hotel_settings.round_off, - "laundry": hotel_settings.laundry, - "cancellation_fee": hotel_settings.cancellation_fee, - "late_checkout": hotel_settings.late_checkout, - "early_checkin": hotel_settings.early_checkin, - } - - # to exclude service charge from reduced because of commision / cashback - room_post_settings = frappe.db.get_values_from_single(doctype="Inn Hotels Setting", filters="", fields=["room_revenue_account", "breakfast_revenue_account", "profit_sharing_account", "profit_sharing_transaction_type"], as_dict=True)[0] - PROFIT_SHARING_ACCOUNT = room_post_settings.profit_sharing_account - COMMISION_TRANSACTION_TYPE = room_post_settings.profit_sharing_transaction_type - - channel_exclude_tax = frappe.get_list("Inn Channel Tax Exclude", - { - "parenttype": "Inn Hotels Setting", - "parent": "Inn Hotels Setting", - "parentfield": "inn_channel_exclude_tax" - }, - parent_doctype='Inn Hotels Setting', - pluck="channel" - ) - inn_settings = frappe.get_value("Inn Hotels Setting", None, ["maximum_payment_exclude", "inn_tax_exclude_option"], as_dict=1) - maximum_price_exclude_tax = inn_settings.maximum_payment_exclude - inn_tax_exclude = inn_settings.inn_tax_exclude_option - - return_value = '' - room_charge_posting_doc = frappe.get_doc('Inn Room Charge Posting', parent_id) - list_json = json.loads(tobe_posted_list) - # for difference calculations - fdc_reservation = '' - fdc_folio_trx_tax_name = '' - for item in list_json: - # Create Inn Folio Transaction Bundle - ftb_doc = frappe.new_doc('Inn Folio Transaction Bundle') - ftb_doc.transaction_type = transaction_types["room_charge"] - ftb_doc.insert() - - # Posting Room Charge - accumulated_amount = 0.00 - room_charge_debit_account, room_charge_credit_account = get_accounts_from_id(transaction_types["room_charge"]) - reservation = frappe.get_doc('Inn Reservation', item['reservation_id']) - fdc_reservation = reservation - is_exclude_tax = False - if (reservation.channel in channel_exclude_tax) or (reservation.actual_room_rate <= flt(maximum_price_exclude_tax)): - reservation.actual_room_rate_tax = inn_tax_exclude - reservation.actual_breakfast_rate_tax = inn_tax_exclude - is_exclude_tax = True - recalculate_nett_charge(reservation) - - # check if channel is commission - channel = check_channel_commission(reservation) - is_channel_commision = True - if channel.profit_sharing == 0: - is_channel_commision = False - - room_charge_folio_trx = frappe.new_doc('Inn Folio Transaction') - room_charge_folio_trx.flag = 'Debit' - room_charge_folio_trx.is_void = 0 - room_charge_folio_trx.idx = get_idx(item['folio_id']) - room_charge_folio_trx.transaction_type = transaction_types["room_charge"] - room_charge_folio_trx.amount = float(int(reservation.nett_actual_room_rate)) - accumulated_amount += float(int(reservation.nett_actual_room_rate)) - room_charge_folio_trx.debit_account = room_charge_debit_account - room_charge_folio_trx.credit_account = room_charge_credit_account - room_charge_folio_trx.remark = 'Room Charge: Room Rate (Nett): ' + item[ - 'room_id'] + " - " + get_last_audit_date().strftime("%d-%m-%Y") - room_charge_folio_trx.actual_room_rate = reservation.actual_room_rate - room_charge_folio_trx.parent = item['folio_id'] - room_charge_folio_trx.parenttype = 'Inn Folio' - room_charge_folio_trx.parentfield = 'folio_transaction' - room_charge_folio_trx.ftb_id = ftb_doc.name - room_charge_folio_trx.insert() - - return_value = return_value + '
  • ' + room_charge_folio_trx.remark + '
  • ' - - # Create Inn Folio Transaction Bundle Detail Item Room Charge - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = room_charge_folio_trx.transaction_type - ftbd_doc.transaction_id = room_charge_folio_trx.name - ftb_doc.append('transaction_detail', ftbd_doc) - - fdc_room_rate = frappe.get_doc('Inn Room Rate', fdc_reservation.room_rate) - fdc_room_rate_tax = frappe.get_doc('Inn Tax', fdc_room_rate.room_rate_tax) - fdc_room_rate_tax_breakdown = fdc_room_rate_tax.inn_tax_breakdown - if fdc_room_rate_tax_breakdown[-1].breakdown_rate != 0.0: - fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[-1].breakdown_account - else: - fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[-2].breakdown_account - # get tax breakdown account from reservation - if is_exclude_tax: - fdc_room_rate_tax = frappe.get_doc("Inn Tax", reservation.actual_room_rate_tax) - fdc_room_rate_tax_account = fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_account if fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_rate != 0 else fdc_room_rate_tax[-2].breakdown_account - - - if is_channel_commision: - # add commission first - room_commision_doc = frappe.new_doc('Inn Folio Transaction') - room_commision_doc.flag = 'Debit' - room_commision_doc.is_void = 0 - room_commision_doc.idx = get_idx(item["folio_id"]) - - room_commision_doc.transaction_type = COMMISION_TRANSACTION_TYPE - room_commision_doc.amount = float(int(channel.room_cashback)) - accumulated_amount += float(int(channel.room_cashback)) - room_commision_doc.credit_account = PROFIT_SHARING_ACCOUNT - room_commision_doc.debit_account = room_charge_debit_account - room_commision_doc.remark = 'Commission ' + channel.name + ' : ' + item["room_id"] + " - " + get_last_audit_date().strftime("%d-%m-%Y") - room_commision_doc.parent = item["folio_id"] - room_commision_doc.parenttype = 'Inn Folio' - room_commision_doc.parentfield = 'folio_transaction' - room_commision_doc.ftb_id = ftb_doc.name - room_commision_doc.insert() - - # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = room_commision_doc.transaction_type - ftbd_doc.transaction_id = room_commision_doc.name - ftb_doc.append('transaction_detail', ftbd_doc) - - # Posting Room Charge Tax/Service - room_tb_id, room_tb_amount, _ = calculate_inn_tax_and_charges(reservation.nett_actual_room_rate, - reservation.actual_room_rate_tax) - - for index, room_tax_item_name in enumerate(room_tb_id): - room_tax_doc = frappe.new_doc('Inn Folio Transaction') - room_tax_doc.flag = 'Debit' - room_tax_doc.is_void = 0 - room_tax_doc.idx = get_idx(item['folio_id']) - room_tax_doc.transaction_type = transaction_types["room_charge_tax_service"] - room_tax_doc.amount = room_tb_amount[index] - accumulated_amount += room_tb_amount[index] - room_tax_doc.credit_account = frappe.get_doc('Inn Tax Breakdown', room_tax_item_name).breakdown_account - room_tax_doc.debit_account = room_charge_debit_account - room_tax_doc.remark = 'Room Charge Tax Room Rate ' + room_tax_item_name + ' : ' + item[ - 'room_id'] + " - " + get_last_audit_date().strftime("%d-%m-%Y") - room_tax_doc.parent = item['folio_id'] - room_tax_doc.parenttype = 'Inn Folio' - room_tax_doc.parentfield = 'folio_transaction' - room_tax_doc.ftb_id = ftb_doc.name - room_tax_doc.insert() - - if room_tax_doc.credit_account == fdc_room_rate_tax_account: - fdc_folio_trx_tax_name = room_tax_doc.name - - ## corner case: if breakfast charge is 0 then don't post any breakfast related transaction - breakfast_price = float(int(reservation.nett_actual_breakfast_rate)) - if breakfast_price > 0: - - # Posting Breakfast Charge - breakfast_charge_debit_account, breakfast_charge_credit_account = get_accounts_from_id(transaction_types["breakfast_charge"]) - breakfast_charge_folio_trx.flag = 'Debit' - breakfast_charge_folio_trx.is_void = 0 - breakfast_charge_folio_trx.idx = get_idx(item['folio_id']) - breakfast_charge_folio_trx.transaction_type = transaction_types["breakfast_charge"] - breakfast_charge_folio_trx.amount = float(int(reservation.nett_actual_breakfast_rate)) - accumulated_amount += float(int(reservation.nett_actual_breakfast_rate)) - breakfast_charge_folio_trx.debit_account = breakfast_charge_debit_account - breakfast_charge_folio_trx.credit_account = breakfast_charge_credit_account - breakfast_charge_folio_trx.remark = 'Room Charge: Breakfast (Nett): ' + item[ - 'room_id'] + " - " + get_last_audit_date().strftime("%d-%m-%Y") - breakfast_charge_folio_trx.parent = item['folio_id'] - breakfast_charge_folio_trx.parenttype = 'Inn Folio' - breakfast_charge_folio_trx.parentfield = 'folio_transaction' - breakfast_charge_folio_trx.ftb_id = ftb_doc.name - breakfast_charge_folio_trx.insert() - - # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = breakfast_charge_folio_trx.transaction_type - ftbd_doc.transaction_id = breakfast_charge_folio_trx.name - ftb_doc.append('transaction_detail', ftbd_doc) - - if is_channel_commision: - # add commission first - breakfast_commission = frappe.new_doc('Inn Folio Transaction') - breakfast_commission.flag = 'Debit' - breakfast_commission.is_void = 0 - breakfast_commission.idx = get_idx(item["folio_id"]) - - breakfast_commission.transaction_type = COMMISION_TRANSACTION_TYPE - breakfast_commission.amount = float(int(channel.breakfast_cashback)) - accumulated_amount += float(int(channel.breakfast_cashback)) - breakfast_commission.credit_account = PROFIT_SHARING_ACCOUNT - breakfast_commission.debit_account = breakfast_charge_debit_account - breakfast_commission.remark = 'Commission ' + channel.name + ' : ' + item["room_id"] + " - " + get_last_audit_date().strftime("%d-%m-%Y") - breakfast_commission.parent = item["folio_id"] - breakfast_commission.parenttype = 'Inn Folio' - breakfast_commission.parentfield = 'folio_transaction' - breakfast_commission.ftb_id = ftb_doc.name - breakfast_commission.insert() - - # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = breakfast_commission.transaction_type - ftbd_doc.transaction_id = breakfast_commission.name - ftb_doc.append('transaction_detail', ftbd_doc) - - # Posting Breakfast Tax/Service - breakfast_tb_id, breakfast_tb_amount, _ = calculate_inn_tax_and_charges(reservation.nett_actual_breakfast_rate, - reservation.actual_breakfast_rate_tax) - for index, breakfast_tax_item_name in enumerate(breakfast_tb_id): - breakfast_tax_doc = frappe.new_doc('Inn Folio Transaction') - breakfast_tax_doc.flag = 'Debit' - breakfast_tax_doc.is_void = 0 - breakfast_tax_doc.idx = get_idx(item['folio_id']) - breakfast_tax_doc.transaction_type = transaction_types["breakfast_charge_tax_service"] - breakfast_tax_doc.amount = breakfast_tb_amount[index] - accumulated_amount += breakfast_tb_amount[index] - breakfast_tax_doc.credit_account = frappe.get_doc('Inn Tax Breakdown', - breakfast_tax_item_name).breakdown_account - breakfast_tax_doc.debit_account = breakfast_charge_debit_account - breakfast_tax_doc.remark = 'Breakfast Charge Tax Room Rate ' + breakfast_tax_item_name + ' : ' + item[ - 'room_id'] + " - " + get_last_audit_date().strftime("%d-%m-%Y") - breakfast_tax_doc.parent = item['folio_id'] - breakfast_tax_doc.parenttype = 'Inn Folio' - breakfast_tax_doc.parentfield = 'folio_transaction' - breakfast_tax_doc.ftb_id = ftb_doc.name - breakfast_tax_doc.insert() - - # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge Tax/Service - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') - ftbd_doc.transaction_type = breakfast_tax_doc.transaction_type - ftbd_doc.transaction_id = breakfast_tax_doc.name - ftb_doc.append('transaction_detail', ftbd_doc) - - print("accumulated amount = " + str(accumulated_amount)) - print("math_ceil(accumulated amount) = " + str(math.ceil(accumulated_amount))) - print("actual room rate = " + str(reservation.actual_room_rate)) - print("abs = " + str(abs(math.ceil(accumulated_amount) - int(reservation.actual_room_rate)))) - if abs(math.ceil(accumulated_amount) - int(reservation.actual_room_rate)) != 0: - difference = math.ceil(accumulated_amount) - int(reservation.actual_room_rate) - if breakfast_price > 0: - if difference > 0: - adjusted_room_charge_amount = room_charge_folio_trx.amount - adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount - for i in range(0, abs(difference)): - adjusted_room_charge_amount = adjusted_room_charge_amount - 1.0 - - elif difference < 0: - adjusted_room_charge_amount = room_charge_folio_trx.amount - adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount - fdc_folio_trx_tax = frappe.get_doc('Inn Folio Transaction', fdc_folio_trx_tax_name) - adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount - # TODO: ganti tambah difference ke pajak, bukan ke room rate & breakfast - for i in range(0, abs(difference)): - adjusted_room_rate_tax_amount = adjusted_room_rate_tax_amount + 1.0 - fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount - fdc_folio_trx_tax.save() - - room_charge_folio_trx.amount = adjusted_room_charge_amount - room_charge_folio_trx.save() - breakfast_charge_folio_trx.amount = adjusted_breakfast_charge_amount - breakfast_charge_folio_trx.save() - - else: - if difference > 0: - adjusted_room_charge_amount = room_charge_folio_trx.amount - for i in range(0, abs(difference)): - adjusted_room_charge_amount = adjusted_room_charge_amount - 1.0 - elif difference < 0: - adjusted_room_charge_amount = room_charge_folio_trx.amount - fdc_folio_trx_tax = frappe.get_doc('Inn Folio Transaction', fdc_folio_trx_tax_name) - adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount - for i in range(0, abs(difference)): - adjusted_room_rate_tax_amount = adjusted_room_rate_tax_amount + 1.0 - fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount - fdc_folio_trx_tax.save() - room_charge_folio_trx.amount = adjusted_room_charge_amount - room_charge_folio_trx.save() - - # Resave Bundle to save Detail - ftb_doc.save() - - posted = frappe.new_doc('Inn Room Charge Posted') - posted.reservation_id = item['reservation_id'] - posted.folio_id = item['folio_id'] - posted.room_id = item['room_id'] - posted.customer_id = item['customer_id'] - posted.room_rate_id = item['room_rate_id'] - posted.actual_room_rate = item['actual_room_rate'] - posted.folio_transaction_id = room_charge_folio_trx.name - posted.parent = parent_id - posted.parentfield = 'already_posted' - posted.parenttype = 'Inn Room Charge Posting' - room_charge_posting_doc.append('already_posted', posted) - - frappe.delete_doc('Inn Room Charge To Be Posted', item['name']) - - room_charge_posting_doc.save() - calculate_already_posted_total(room_charge_posting_doc.name) - - return return_value + # Fetch all transaction types from Inn Hotels Setting + hotel_settings = frappe.get_doc("Inn Hotels Setting") + transaction_types = { + "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, + "package": hotel_settings.package, + "room_charge": hotel_settings.room_charge, + "breakfast_charge": hotel_settings.breakfast_charge, + "refund": hotel_settings.refund, + "dp_kamar": hotel_settings.dp_kamar, + "room_payment": hotel_settings.room_payment, + "deposit": hotel_settings.deposit, + "down_payment": hotel_settings.down_payment, + "payment": hotel_settings.payment, + "additional_charge": hotel_settings.additional_charge, + "restaurant_food": hotel_settings.restaurant_food, + "restaurant_beverages": hotel_settings.restaurant_beverages, + "restaurant_other": hotel_settings.restaurant_other, + "room_service_food": hotel_settings.room_service_food, + "room_service_beverage": hotel_settings.room_service_beverage, + "fbs_service_10": hotel_settings.fbs_service_10, + "round_off": hotel_settings.round_off, + "laundry": hotel_settings.laundry, + "cancellation_fee": hotel_settings.cancellation_fee, + "late_checkout": hotel_settings.late_checkout, + "early_checkin": hotel_settings.early_checkin, + } + if hotel_settings.include_tax: + transaction_types["room_charge_tax_service"] = ( + hotel_settings.room_charge_tax_service, + ) + transaction_types["breakfast_charge_tax_service"] = ( + hotel_settings.breakfast_charge_tax_service, + ) + transaction_types["fbs_tax_11"] = (hotel_settings.fbs_tax_11,) + + # to exclude service charge from reduced because of commision / cashback + room_post_settings = frappe.db.get_values_from_single( + doctype="Inn Hotels Setting", + filters="", + fields=[ + "room_revenue_account", + "breakfast_revenue_account", + "profit_sharing_account", + "profit_sharing_transaction_type", + ], + as_dict=True, + )[0] + PROFIT_SHARING_ACCOUNT = room_post_settings.profit_sharing_account + COMMISION_TRANSACTION_TYPE = room_post_settings.profit_sharing_transaction_type + + channel_exclude_tax = frappe.get_list( + "Inn Channel Tax Exclude", + { + "parenttype": "Inn Hotels Setting", + "parent": "Inn Hotels Setting", + "parentfield": "inn_channel_exclude_tax", + }, + parent_doctype="Inn Hotels Setting", + pluck="channel", + ) + inn_settings = frappe.get_value( + "Inn Hotels Setting", + None, + ["maximum_payment_exclude", "inn_tax_exclude_option"], + as_dict=1, + ) + maximum_price_exclude_tax = inn_settings.maximum_payment_exclude + inn_tax_exclude = inn_settings.inn_tax_exclude_option + + return_value = "" + room_charge_posting_doc = frappe.get_doc("Inn Room Charge Posting", parent_id) + list_json = json.loads(tobe_posted_list) + # for difference calculations + fdc_reservation = "" + fdc_folio_trx_tax_name = "" + for item in list_json: + # Create Inn Folio Transaction Bundle + ftb_doc = frappe.new_doc("Inn Folio Transaction Bundle") + ftb_doc.transaction_type = transaction_types["room_charge"] + ftb_doc.insert() + + # Posting Room Charge + accumulated_amount = 0.00 + room_charge_debit_account, room_charge_credit_account = get_accounts_from_id( + transaction_types["room_charge"] + ) + reservation = frappe.get_doc("Inn Reservation", item["reservation_id"]) + fdc_reservation = reservation + is_exclude_tax = False + if (reservation.channel in channel_exclude_tax) or ( + reservation.actual_room_rate <= flt(maximum_price_exclude_tax) + ): + reservation.actual_room_rate_tax = inn_tax_exclude + reservation.actual_breakfast_rate_tax = inn_tax_exclude + is_exclude_tax = True + recalculate_nett_charge(reservation) + + # check if channel is commission + channel = check_channel_commission(reservation) + is_channel_commision = True + if channel.profit_sharing == 0: + is_channel_commision = False + + room_charge_folio_trx = frappe.new_doc("Inn Folio Transaction") + room_charge_folio_trx.flag = "Debit" + room_charge_folio_trx.is_void = 0 + room_charge_folio_trx.idx = get_idx(item["folio_id"]) + room_charge_folio_trx.transaction_type = transaction_types["room_charge"] + room_charge_folio_trx.amount = float(int(reservation.nett_actual_room_rate)) + accumulated_amount += float(int(reservation.nett_actual_room_rate)) + room_charge_folio_trx.debit_account = room_charge_debit_account + room_charge_folio_trx.credit_account = room_charge_credit_account + room_charge_folio_trx.remark = ( + "Room Charge: Room Rate (Nett): " + + item["room_id"] + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + room_charge_folio_trx.actual_room_rate = reservation.actual_room_rate + room_charge_folio_trx.parent = item["folio_id"] + room_charge_folio_trx.parenttype = "Inn Folio" + room_charge_folio_trx.parentfield = "folio_transaction" + room_charge_folio_trx.ftb_id = ftb_doc.name + room_charge_folio_trx.insert() + + return_value = return_value + "
  • " + room_charge_folio_trx.remark + "
  • " + + # Create Inn Folio Transaction Bundle Detail Item Room Charge + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = room_charge_folio_trx.transaction_type + ftbd_doc.transaction_id = room_charge_folio_trx.name + ftb_doc.append("transaction_detail", ftbd_doc) + + fdc_room_rate = frappe.get_doc("Inn Room Rate", fdc_reservation.room_rate) + fdc_room_rate_tax = frappe.get_doc("Inn Tax", fdc_room_rate.room_rate_tax) + fdc_room_rate_tax_breakdown = fdc_room_rate_tax.inn_tax_breakdown + if fdc_room_rate_tax_breakdown[-1].breakdown_rate != 0.0: + fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ + -1 + ].breakdown_account + # else: + # fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ + # -2 + # ].breakdown_account + # get tax breakdown account from reservation + if is_exclude_tax: + fdc_room_rate_tax = frappe.get_doc( + "Inn Tax", reservation.actual_room_rate_tax + ) + fdc_room_rate_tax_account = ( + fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_account + if fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_rate != 0 + else fdc_room_rate_tax[-2].breakdown_account + ) + + if is_channel_commision: + # add commission first + room_commision_doc = frappe.new_doc("Inn Folio Transaction") + room_commision_doc.flag = "Debit" + room_commision_doc.is_void = 0 + room_commision_doc.idx = get_idx(item["folio_id"]) + + room_commision_doc.transaction_type = COMMISION_TRANSACTION_TYPE + room_commision_doc.amount = float(int(channel.room_cashback)) + accumulated_amount += float(int(channel.room_cashback)) + room_commision_doc.credit_account = PROFIT_SHARING_ACCOUNT + room_commision_doc.debit_account = room_charge_debit_account + room_commision_doc.remark = ( + "Commission " + + channel.name + + " : " + + item["room_id"] + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + room_commision_doc.parent = item["folio_id"] + room_commision_doc.parenttype = "Inn Folio" + room_commision_doc.parentfield = "folio_transaction" + room_commision_doc.ftb_id = ftb_doc.name + room_commision_doc.insert() + + # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = room_commision_doc.transaction_type + ftbd_doc.transaction_id = room_commision_doc.name + ftb_doc.append("transaction_detail", ftbd_doc) + + # Posting Room Charge Tax/Service + room_tb_id, room_tb_amount, _ = calculate_inn_tax_and_charges( + reservation.nett_actual_room_rate, reservation.actual_room_rate_tax + ) + + if hotel_settings.include_tax: + + for index, room_tax_item_name in enumerate(room_tb_id): + room_tax_doc = frappe.new_doc("Inn Folio Transaction") + room_tax_doc.flag = "Debit" + room_tax_doc.is_void = 0 + room_tax_doc.idx = get_idx(item["folio_id"]) + room_tax_doc.transaction_type = transaction_types[ + "room_charge_tax_service" + ] + room_tax_doc.amount = room_tb_amount[index] + accumulated_amount += room_tb_amount[index] + room_tax_doc.credit_account = frappe.get_doc( + "Inn Tax Breakdown", room_tax_item_name + ).breakdown_account + room_tax_doc.debit_account = room_charge_debit_account + room_tax_doc.remark = ( + "Room Charge Tax Room Rate " + + room_tax_item_name + + " : " + + item["room_id"] + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + room_tax_doc.parent = item["folio_id"] + room_tax_doc.parenttype = "Inn Folio" + room_tax_doc.parentfield = "folio_transaction" + room_tax_doc.ftb_id = ftb_doc.name + room_tax_doc.insert() + + if room_tax_doc.credit_account == fdc_room_rate_tax_account: + fdc_folio_trx_tax_name = room_tax_doc.name + + ## corner case: if breakfast charge is 0 then don't post any breakfast related transaction + breakfast_price = float(int(reservation.nett_actual_breakfast_rate)) + if breakfast_price > 0: + + # Posting Breakfast Charge + breakfast_charge_debit_account, breakfast_charge_credit_account = ( + get_accounts_from_id(transaction_types["breakfast_charge"]) + ) + breakfast_charge_folio_trx = frappe.new_doc("Inn Folio Transaction") + breakfast_charge_folio_trx.flag = "Debit" + breakfast_charge_folio_trx.is_void = 0 + breakfast_charge_folio_trx.idx = get_idx(item["folio_id"]) + breakfast_charge_folio_trx.transaction_type = transaction_types[ + "breakfast_charge" + ] + breakfast_charge_folio_trx.amount = float( + int(reservation.nett_actual_breakfast_rate) + ) + accumulated_amount += float(int(reservation.nett_actual_breakfast_rate)) + breakfast_charge_folio_trx.debit_account = breakfast_charge_debit_account + breakfast_charge_folio_trx.credit_account = breakfast_charge_credit_account + breakfast_charge_folio_trx.remark = ( + "Room Charge: Breakfast (Nett): " + + item["room_id"] + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + breakfast_charge_folio_trx.parent = item["folio_id"] + breakfast_charge_folio_trx.parenttype = "Inn Folio" + breakfast_charge_folio_trx.parentfield = "folio_transaction" + breakfast_charge_folio_trx.ftb_id = ftb_doc.name + breakfast_charge_folio_trx.insert() + + # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = breakfast_charge_folio_trx.transaction_type + ftbd_doc.transaction_id = breakfast_charge_folio_trx.name + ftb_doc.append("transaction_detail", ftbd_doc) + + if is_channel_commision: + # add commission first + breakfast_commission = frappe.new_doc("Inn Folio Transaction") + breakfast_commission.flag = "Debit" + breakfast_commission.is_void = 0 + breakfast_commission.idx = get_idx(item["folio_id"]) + + breakfast_commission.transaction_type = COMMISION_TRANSACTION_TYPE + breakfast_commission.amount = float(int(channel.breakfast_cashback)) + accumulated_amount += float(int(channel.breakfast_cashback)) + breakfast_commission.credit_account = PROFIT_SHARING_ACCOUNT + breakfast_commission.debit_account = breakfast_charge_debit_account + breakfast_commission.remark = ( + "Commission " + + channel.name + + " : " + + item["room_id"] + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + breakfast_commission.parent = item["folio_id"] + breakfast_commission.parenttype = "Inn Folio" + breakfast_commission.parentfield = "folio_transaction" + breakfast_commission.ftb_id = ftb_doc.name + breakfast_commission.insert() + + # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = breakfast_commission.transaction_type + ftbd_doc.transaction_id = breakfast_commission.name + ftb_doc.append("transaction_detail", ftbd_doc) + if hotel_settings.include_tax: + # Posting Breakfast Tax/Service + breakfast_tb_id, breakfast_tb_amount, _ = calculate_inn_tax_and_charges( + reservation.nett_actual_breakfast_rate, + reservation.actual_breakfast_rate_tax, + ) + for index, breakfast_tax_item_name in enumerate(breakfast_tb_id): + breakfast_tax_doc = frappe.new_doc("Inn Folio Transaction") + breakfast_tax_doc.flag = "Debit" + breakfast_tax_doc.is_void = 0 + breakfast_tax_doc.idx = get_idx(item["folio_id"]) + breakfast_tax_doc.transaction_type = transaction_types[ + "breakfast_charge_tax_service" + ] + breakfast_tax_doc.amount = breakfast_tb_amount[index] + accumulated_amount += breakfast_tb_amount[index] + breakfast_tax_doc.credit_account = frappe.get_doc( + "Inn Tax Breakdown", breakfast_tax_item_name + ).breakdown_account + breakfast_tax_doc.debit_account = breakfast_charge_debit_account + breakfast_tax_doc.remark = ( + "Breakfast Charge Tax Room Rate " + + breakfast_tax_item_name + + " : " + + item["room_id"] + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + breakfast_tax_doc.parent = item["folio_id"] + breakfast_tax_doc.parenttype = "Inn Folio" + breakfast_tax_doc.parentfield = "folio_transaction" + breakfast_tax_doc.ftb_id = ftb_doc.name + breakfast_tax_doc.insert() + + # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = breakfast_tax_doc.transaction_type + ftbd_doc.transaction_id = breakfast_tax_doc.name + ftb_doc.append("transaction_detail", ftbd_doc) + + print("accumulated amount = " + str(accumulated_amount)) + print("math_ceil(accumulated amount) = " + str(math.ceil(accumulated_amount))) + print("actual room rate = " + str(reservation.actual_room_rate)) + print( + "abs = " + + str( + abs(math.ceil(accumulated_amount) - int(reservation.actual_room_rate)) + ) + ) + if abs(math.ceil(accumulated_amount) - int(reservation.actual_room_rate)) != 0: + difference = math.ceil(accumulated_amount) - int( + reservation.actual_room_rate + ) + if breakfast_price > 0: + if difference > 0: + adjusted_room_charge_amount = room_charge_folio_trx.amount + adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount + for i in range(0, abs(difference)): + adjusted_room_charge_amount = adjusted_room_charge_amount - 1.0 + + elif difference < 0: + adjusted_room_charge_amount = room_charge_folio_trx.amount + adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount + fdc_folio_trx_tax = frappe.get_doc( + "Inn Folio Transaction", fdc_folio_trx_tax_name + ) + adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount + # TODO: ganti tambah difference ke pajak, bukan ke room rate & breakfast + for i in range(0, abs(difference)): + adjusted_room_rate_tax_amount = ( + adjusted_room_rate_tax_amount + 1.0 + ) + fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount + fdc_folio_trx_tax.save() + + room_charge_folio_trx.amount = adjusted_room_charge_amount + room_charge_folio_trx.save() + breakfast_charge_folio_trx.amount = adjusted_breakfast_charge_amount + breakfast_charge_folio_trx.save() + + else: + if difference > 0: + adjusted_room_charge_amount = room_charge_folio_trx.amount + for i in range(0, abs(difference)): + adjusted_room_charge_amount = adjusted_room_charge_amount - 1.0 + elif difference < 0: + adjusted_room_charge_amount = room_charge_folio_trx.amount + fdc_folio_trx_tax = frappe.get_doc( + "Inn Folio Transaction", fdc_folio_trx_tax_name + ) + adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount + for i in range(0, abs(difference)): + adjusted_room_rate_tax_amount = ( + adjusted_room_rate_tax_amount + 1.0 + ) + fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount + fdc_folio_trx_tax.save() + room_charge_folio_trx.amount = adjusted_room_charge_amount + room_charge_folio_trx.save() + + # Resave Bundle to save Detail + ftb_doc.save() + + posted = frappe.new_doc("Inn Room Charge Posted") + posted.reservation_id = item["reservation_id"] + posted.folio_id = item["folio_id"] + posted.room_id = item["room_id"] + posted.customer_id = item["customer_id"] + posted.room_rate_id = item["room_rate_id"] + posted.actual_room_rate = item["actual_room_rate"] + posted.folio_transaction_id = room_charge_folio_trx.name + posted.parent = parent_id + posted.parentfield = "already_posted" + posted.parenttype = "Inn Room Charge Posting" + room_charge_posting_doc.append("already_posted", posted) + + frappe.delete_doc("Inn Room Charge To Be Posted", item["name"]) + + room_charge_posting_doc.save() + calculate_already_posted_total(room_charge_posting_doc.name) + + return return_value + def calculate_already_posted_total(room_charge_posting_id): - total = 0.0 - doc = frappe.get_doc('Inn Room Charge Posting', room_charge_posting_id) - posted = doc.get('already_posted') - if len(posted) > 0: - for item in posted: - total += item.actual_room_rate + total = 0.0 + doc = frappe.get_doc("Inn Room Charge Posting", room_charge_posting_id) + posted = doc.get("already_posted") + if len(posted) > 0: + for item in posted: + total += item.actual_room_rate + + frappe.db.set_value( + "Inn Room Charge Posting", doc.name, "already_posted_total", total + ) - frappe.db.set_value('Inn Room Charge Posting', doc.name, 'already_posted_total', total) def recalculate_nett_charge(reservation_doc): - room_tax_name, new_room_charge, breakfast_tax_name, new_breakfast_charge = recalculate_tax_by_exclude_tax(reservation_doc) - reservation_doc.nett_actual_room_rate = new_room_charge - reservation_doc.nett_actual_breakfast_rate = new_breakfast_charge - return reservation_doc + room_tax_name, new_room_charge, breakfast_tax_name, new_breakfast_charge = ( + recalculate_tax_by_exclude_tax(reservation_doc) + ) + reservation_doc.nett_actual_room_rate = new_room_charge + reservation_doc.nett_actual_breakfast_rate = new_breakfast_charge + return reservation_doc def recalculate_tax_by_exclude_tax(reservation_doc): - '''wrapper to ease naming''' - return __get_actual_room_rate_breakdown_check_commission(reservation_doc) + """wrapper to ease naming""" + return __get_actual_room_rate_breakdown_check_commission(reservation_doc) + def __get_actual_room_rate_breakdown_check_commission(reservation_doc): - ''' - creating new function because old function is calculating tax breakdown based on room rate tax. - dont want to risk it to change to reservation tax. - - calculating nett based on tax in inn hotels setting. - ''' - from inn.inn_hotels.doctype.inn_channel.inn_channel import check_channel_commission, PROFIT_SHARING_ENABLED, PROFIT_SHARING_TYPE_PERCENTAGE - - - channel = check_channel_commission(reservation_doc, reservation_price=reservation_doc.actual_room_rate) - if channel.profit_sharing == PROFIT_SHARING_ENABLED: - if channel.sharing_type != PROFIT_SHARING_TYPE_PERCENTAGE: - raise NotImplementedError("comission type other than percentage is not supported yet") - # if channel is profit sharing enabled it will autofill room_cashback and breakfast_cashback - else: - channel.room_cashback = 0 - channel.breakfast_cashback = 0 - - room_rate_doc = frappe.get_doc('Inn Room Rate', reservation_doc.room_rate) - - # diff in here: using reservation tax as a base and when channel is not in commission also call this function will filled cashback as 0 - _, _, room_price = calculate_inn_tax_and_charges_exclude_commision(reservation_doc.actual_room_rate - room_rate_doc.final_breakfast_rate_amount, reservation_doc.actual_room_rate_tax, channel.room_cashback) - _, _, breakfast_price = calculate_inn_tax_and_charges_exclude_commision(room_rate_doc.final_breakfast_rate_amount, reservation_doc.actual_breakfast_rate_tax, channel.breakfast_cashback) - # diff on top - room_rate_tax = reservation_doc.actual_room_rate_tax - room_rate = room_price[0] - breakfast_tax = reservation_doc.actual_breakfast_rate_tax - breakfast_rate = breakfast_price[0] - - return room_rate_tax, room_rate, breakfast_tax, breakfast_rate \ No newline at end of file + """ + creating new function because old function is calculating tax breakdown based on room rate tax. + dont want to risk it to change to reservation tax. + + calculating nett based on tax in inn hotels setting. + """ + from inn.inn_hotels.doctype.inn_channel.inn_channel import ( + check_channel_commission, + PROFIT_SHARING_ENABLED, + PROFIT_SHARING_TYPE_PERCENTAGE, + ) + + channel = check_channel_commission( + reservation_doc, reservation_price=reservation_doc.actual_room_rate + ) + if channel.profit_sharing == PROFIT_SHARING_ENABLED: + if channel.sharing_type != PROFIT_SHARING_TYPE_PERCENTAGE: + raise NotImplementedError( + "comission type other than percentage is not supported yet" + ) + # if channel is profit sharing enabled it will autofill room_cashback and breakfast_cashback + else: + channel.room_cashback = 0 + channel.breakfast_cashback = 0 + + room_rate_doc = frappe.get_doc("Inn Room Rate", reservation_doc.room_rate) + + # diff in here: using reservation tax as a base and when channel is not in commission also call this function will filled cashback as 0 + _, _, room_price = calculate_inn_tax_and_charges_exclude_commision( + reservation_doc.actual_room_rate - room_rate_doc.final_breakfast_rate_amount, + reservation_doc.actual_room_rate_tax, + channel.room_cashback, + ) + _, _, breakfast_price = calculate_inn_tax_and_charges_exclude_commision( + room_rate_doc.final_breakfast_rate_amount, + reservation_doc.actual_breakfast_rate_tax, + channel.breakfast_cashback, + ) + # diff on top + room_rate_tax = reservation_doc.actual_room_rate_tax + room_rate = room_price[0] + breakfast_tax = reservation_doc.actual_breakfast_rate_tax + breakfast_rate = breakfast_price[0] + + return room_rate_tax, room_rate, breakfast_tax, breakfast_rate From eafb5543e39adfb2b2df1b28f52026ed432e50b9 Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Sun, 26 Jan 2025 13:10:43 +0200 Subject: [PATCH 08/22] [Fix]: Added account default and made adjustments to taxes --- inn/__init__.py | 2 +- .../ar_city_ledger_invoice.js | 423 ++--- .../ar_city_ledger_invoice.py | 128 +- .../inn_dayend_close/inn_dayend_close.py | 902 ++++++---- inn/inn_hotels/doctype/inn_folio/inn_folio.js | 1540 +++++++++-------- .../inn_hotels_setting.json | 24 +- .../inn_room_charge_posting.py | 8 +- 7 files changed, 1693 insertions(+), 1334 deletions(-) diff --git a/inn/__init__.py b/inn/__init__.py index 8820232a..a20ee89b 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = "1.1.3" +__version__ = "1.1.4" diff --git a/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js b/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js index 4952d16a..24936dc8 100644 --- a/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js +++ b/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js @@ -1,228 +1,255 @@ // Copyright (c) 2020, Core Initiative and contributors // For license information, please see license.txt -frappe.ui.form.on('AR City Ledger Invoice', { - onload: function(frm) { - make_payment_visibility(frm); - }, - refresh: function(frm) { - filter_folio(frm); - make_payment_visibility(frm); - }, - inn_channel: function (frm) { - filter_folio(frm); - }, - inn_group: function (frm) { - filter_folio(frm); - }, - customer_id: function (frm) { - filter_folio(frm); - }, - make_payment: function (frm) { - frappe.confirm(__("Please make sure that the payment details (Payment Date, Amount and Mode of Payment) are correct, and Outstanding Amount is zero. Are you want to continue?"), function() { - if (frm.doc.outstanding != 0.0) { - frappe.msgprint('Outstanding amount must be zero in order to Make Payment. Please correct the payment details before Making Payment.'); - } - else { - frappe.call({ - method: "inn.inn_hotels.doctype.ar_city_ledger_invoice.ar_city_ledger_invoice.make_payment", - args: { - id: frm.doc.name, - }, - callback: (r) => { - if (r.message === 1) { - frappe.show_alert(__("This AR City Ledger Invoice are successfully paid.")); - frm.reload_doc(); - } - } - }); - } - }); - - } +frappe.ui.form.on("AR City Ledger Invoice", { + onload: function (frm) { + make_payment_visibility(frm); + }, + refresh: function (frm) { + filter_folio(frm); + make_payment_visibility(frm); + }, + inn_channel: function (frm) { + filter_folio(frm); + }, + inn_group: function (frm) { + filter_folio(frm); + }, + customer_id: function (frm) { + filter_folio(frm); + }, + make_payment: function (frm) { + frappe.confirm( + __( + "Please make sure that the payment details (Payment Date, Amount and Mode of Payment) are correct, and Outstanding Amount is zero. Are you want to continue?" + ), + function () { + if (frm.doc.outstanding != 0.0) { + frappe.msgprint( + "Outstanding amount must be zero in order to Make Payment. Please correct the payment details before Making Payment." + ); + } else { + frappe.call({ + method: + "inn.inn_hotels.doctype.ar_city_ledger_invoice.ar_city_ledger_invoice.make_payment", + args: { + id: frm.doc.name, + }, + callback: (r) => { + if (r.message === 1) { + frappe.show_alert( + __("This AR City Ledger Invoice are successfully paid.") + ); + frm.reload_doc(); + } + }, + }); + } + } + ); + }, }); -frappe.ui.form.on('AR City Ledger Invoice Folio', { - folio_id: function (frm, cdt, cdn) { - let child = locals[cdt][cdn]; - autofill_by_folio(child); - }, - folio_remove: function (frm) { - calculate_payments(frm); - }, +frappe.ui.form.on("AR City Ledger Invoice Folio", { + folio_id: function (frm, cdt, cdn) { + let child = locals[cdt][cdn]; + autofill_by_folio(child); + }, + folio_remove: function (frm) { + calculate_payments(frm); + }, }); -frappe.ui.form.on('AR City Ledger Invoice Payments', { - payments_add: function (frm) { - console.log("masuk sini"); - if (!frm.doc.folio || frm.doc.folio.length === 0) { - frappe.msgprint("Please add Folio to be Collected first"); - frm.doc.payments = []; - frm.refresh_field('payments'); - } - }, - payments_remove: function (frm) { - calculate_payments(frm); - }, - payment_amount: function (frm, cdt, cdn) { - let child = locals[cdt][cdn]; - if (child.payment_amount) { - calculate_payments(frm); - } - }, - mode_of_payment: function (frm, cdt, cdn) { - let child = locals[cdt][cdn]; - if (child.mode_of_payment) { - autofill_payments_account(child); - } - } +frappe.ui.form.on("AR City Ledger Invoice Payments", { + payments_add: function (frm) { + console.log("masuk sini"); + if (!frm.doc.folio || frm.doc.folio.length === 0) { + frappe.msgprint("Please add Folio to be Collected first"); + frm.doc.payments = []; + frm.refresh_field("payments"); + } + }, + payments_remove: function (frm) { + calculate_payments(frm); + }, + payment_amount: function (frm, cdt, cdn) { + let child = locals[cdt][cdn]; + if (child.payment_amount) { + calculate_payments(frm); + } + }, + mode_of_payment: function (frm, cdt, cdn) { + let child = locals[cdt][cdn]; + if (child.mode_of_payment) { + autofill_payments_account(child); + } + }, }); function filter_folio(frm) { - let field = frm.fields_dict['folio'].grid.fields_map['folio_id']; - let channel = frm.doc.inn_channel; - let group = frm.doc.inn_group; - let customer_id = frm.doc.customer_id; - frappe.call({ - method: 'inn.inn_hotels.doctype.ar_city_ledger.ar_city_ledger.get_folio_from_ar_city_ledger', - args: { - selector: 'Folio', - channel: channel, - group: group, - customer_id: customer_id - }, - callback: (r) => { - if (r.message) { - field.get_query = function () { - return { - filters: [ - ['Inn Folio', 'name', 'in', r.message] - ] - } - } - } - } - }); + let field = frm.fields_dict["folio"].grid.fields_map["folio_id"]; + let channel = frm.doc.inn_channel; + let group = frm.doc.inn_group; + let customer_id = frm.doc.customer_id; + frappe.call({ + method: + "inn.inn_hotels.doctype.ar_city_ledger.ar_city_ledger.get_folio_from_ar_city_ledger", + args: { + selector: "Folio", + channel: channel, + group: group, + customer_id: customer_id, + }, + callback: (r) => { + if (r.message) { + console.log(r); + field.get_query = function () { + return { + filters: [["Inn Folio", "name", "in", r.message]], + }; + }; + } + }, + }); } function autofill_by_folio(child) { - if (child.folio_id !== undefined) { - frappe.call({ - method: 'inn.inn_hotels.doctype.ar_city_ledger.ar_city_ledger.get_ar_city_ledger_by_folio', - args: { - folio_id: child.folio_id - }, - callback: (r) => { - child.customer_id = r.message.customer_id; - child.amount = r.message.total_amount; - child.open = r.message.folio_open; - child.close = r.message.folio_close; - child.ar_city_ledger_id = r.message.name; - cur_frm.refresh_field('folio'); + if (child.folio_id !== undefined) { + frappe.call({ + method: + "inn.inn_hotels.doctype.ar_city_ledger.ar_city_ledger.get_ar_city_ledger_by_folio", + args: { + folio_id: child.folio_id, + }, + callback: (r) => { + child.customer_id = r.message.customer_id; + child.amount = r.message.total_amount; + child.open = r.message.folio_open; + child.close = r.message.folio_close; + child.ar_city_ledger_id = r.message.name; + cur_frm.refresh_field("folio"); - if (child.amount != 0) { - calculate_payments(cur_frm); - } - } - }); - } + if (child.amount != 0) { + calculate_payments(cur_frm); + } + }, + }); + } } -cur_frm.set_query("mode_of_payment", "payments", function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; - return{ - filters: [ - ['Mode of Payment', 'mode_of_payment', '!=', 'City Ledger'], - ] - } +cur_frm.set_query("mode_of_payment", "payments", function (doc, cdt, cdn) { + var d = locals[cdt][cdn]; + return { + filters: [["Mode of Payment", "mode_of_payment", "!=", "City Ledger"]], + }; }); function calculate_payments(frm) { - let total_amount = 0.0; - let total_paid = 0.0; - let outstanding = 0.0; - let folios = []; - let payments = []; - if (frm.doc.folio) { - folios = frm.doc.folio; - } - if (frm.doc.payments) { - payments = frm.doc.payments; - } + let total_amount = 0.0; + let total_paid = 0.0; + let outstanding = 0.0; + let folios = []; + let payments = []; + if (frm.doc.folio) { + folios = frm.doc.folio; + } + if (frm.doc.payments) { + payments = frm.doc.payments; + } - if (folios.length > 0) { - for (let i = 0; i < folios.length; i++) { - if (folios[i].amount !== undefined) { - total_amount += folios[i].amount; - } - } - } - else { - total_amount = 0.0; - } + if (folios.length > 0) { + for (let i = 0; i < folios.length; i++) { + if (folios[i].amount !== undefined) { + total_amount += folios[i].amount; + } + } + } else { + total_amount = 0.0; + } - if (payments.length > 0) { - for (let i = 0; i < payments.length; i++) { - if (payments[i].payment_amount !== undefined) { - total_paid += payments[i].payment_amount - } - } - } - else { - total_paid = 0.0; - } + if (payments.length > 0) { + for (let i = 0; i < payments.length; i++) { + if (payments[i].payment_amount !== undefined) { + total_paid += payments[i].payment_amount; + } + } + } else { + total_paid = 0.0; + } - outstanding = total_amount - total_paid; + outstanding = total_amount - total_paid; - frm.set_value('total_amount', total_amount); - frm.set_value('total_paid', total_paid); - frm.set_value('outstanding', outstanding); + frm.set_value("total_amount", total_amount); + frm.set_value("total_paid", total_paid); + frm.set_value("outstanding", outstanding); } function autofill_payments_account(child) { - frappe.call({ - method: 'inn.inn_hotels.doctype.ar_city_ledger_invoice.ar_city_ledger_invoice.get_payments_accounts', - args: { - mode_of_payment: child.mode_of_payment - }, - callback: (r) => { - if (r.message) { - child.account = r.message[0]; - child.account_against = r.message[1]; - cur_frm.refresh_field('payments'); - } - } - }); + frappe.call({ + method: + "inn.inn_hotels.doctype.ar_city_ledger_invoice.ar_city_ledger_invoice.get_payments_accounts", + args: { + mode_of_payment: child.mode_of_payment, + }, + callback: (r) => { + if (r.message) { + child.account = r.message[0]; + child.account_against = r.message[1]; + cur_frm.refresh_field("payments"); + } + }, + }); } function make_payment_visibility(frm) { - if (frm.doc.__islocal === 1) { - frm.set_df_property('sb5', 'hidden', 1); - } - else if (frm.doc.payments && frm.doc.payments.length === 0) { - frm.set_df_property('sb5', 'hidden', 1); - } - else if (frm.doc.status == 'Paid') { - frm.set_df_property('sb5', 'hidden', 1); - disable_form(frm); - } - else { - frm.set_df_property('sb5', 'hidden', 0); - } + if (frm.doc.__islocal === 1) { + frm.set_df_property("sb5", "hidden", 1); + } else if (frm.doc.payments && frm.doc.payments.length === 0) { + frm.set_df_property("sb5", "hidden", 1); + } else if (frm.doc.status == "Paid") { + frm.set_df_property("sb5", "hidden", 1); + disable_form(frm); + } else { + frm.set_df_property("sb5", "hidden", 0); + } } function disable_form(frm) { - frm.disable_save(); - frm.set_df_property('issued_date', 'read_only', 1); - frm.set_df_property('due_date', 'read_only', 1); - frm.set_df_property('inn_channel', 'read_only', 1); - frm.set_df_property('inn_group', 'read_only', 1); - frm.set_df_property('customer_id', 'read_only', 1); - frm.get_field("folio").grid.only_sortable(); - frappe.meta.get_docfield('AR City Ledger Invoice Folio', 'folio_id', frm.doc.name).read_only = 1; - frm.get_field("payments").grid.only_sortable(); - frappe.meta.get_docfield('AR City Ledger Invoice Payments', 'payment_reference_date', frm.doc.name).read_only = 1; - frappe.meta.get_docfield('AR City Ledger Invoice Payments', 'mode_of_payment', frm.doc.name).read_only = 1; - frappe.meta.get_docfield('AR City Ledger Invoice Payments', 'payment_amount', frm.doc.name).read_only = 1; - frappe.meta.get_docfield('AR City Ledger Invoice Payments', 'payment_reference_no', frm.doc.name).read_only = 1; - frappe.meta.get_docfield('AR City Ledger Invoice Payments', 'payment_clearance_date', frm.doc.name).read_only = 1; - frm.set_intro('This AR City Ledger Invoice has been Paid.'); -} \ No newline at end of file + frm.disable_save(); + frm.set_df_property("issued_date", "read_only", 1); + frm.set_df_property("due_date", "read_only", 1); + frm.set_df_property("inn_channel", "read_only", 1); + frm.set_df_property("inn_group", "read_only", 1); + frm.set_df_property("customer_id", "read_only", 1); + frm.get_field("folio").grid.only_sortable(); + frappe.meta.get_docfield( + "AR City Ledger Invoice Folio", + "folio_id", + frm.doc.name + ).read_only = 1; + frm.get_field("payments").grid.only_sortable(); + frappe.meta.get_docfield( + "AR City Ledger Invoice Payments", + "payment_reference_date", + frm.doc.name + ).read_only = 1; + frappe.meta.get_docfield( + "AR City Ledger Invoice Payments", + "mode_of_payment", + frm.doc.name + ).read_only = 1; + frappe.meta.get_docfield( + "AR City Ledger Invoice Payments", + "payment_amount", + frm.doc.name + ).read_only = 1; + frappe.meta.get_docfield( + "AR City Ledger Invoice Payments", + "payment_reference_no", + frm.doc.name + ).read_only = 1; + frappe.meta.get_docfield( + "AR City Ledger Invoice Payments", + "payment_clearance_date", + frm.doc.name + ).read_only = 1; + frm.set_intro("This AR City Ledger Invoice has been Paid."); +} diff --git a/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.py b/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.py index 0f5202b6..92fdb55e 100644 --- a/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.py +++ b/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.py @@ -6,72 +6,92 @@ import frappe from frappe.model.document import Document + class ARCityLedgerInvoice(Document): - pass + pass + @frappe.whitelist() def get_payments_accounts(mode_of_payment): - account = frappe.db.get_value('Mode of Payment Account', {'parent': mode_of_payment, 'company': frappe.get_doc( - "Global Defaults").default_company}, "default_account") - against = frappe.db.get_list('Account', filters={'account_number': '1133.001'})[0].name - return account, against + hotel_settings = frappe.get_single("Inn Hotels Setting") + account = frappe.db.get_value( + "Mode of Payment Account", + { + "parent": mode_of_payment, + "company": frappe.get_doc("Global Defaults").default_company, + }, + "default_account", + ) + against = frappe.db.get_list( + "Account", + filters={"name": hotel_settings.ar_city_ledger_invoice_payment_account}, + )[0].name + return account, against + @frappe.whitelist() def make_payment(id): - doc = frappe.get_doc('AR City Ledger Invoice', id) - arc_id = [] - folio_list = doc.folio - if len(folio_list) == 0: - frappe.msgprint("Please add the Folio to be Collected first before making payment") - else: - for folio in folio_list: - arc_id.append(folio.ar_city_ledger_id) - payments = doc.get('payments') - return_status = 1 + doc = frappe.get_doc("AR City Ledger Invoice", id) + arc_id = [] + folio_list = doc.folio + if len(folio_list) == 0: + frappe.msgprint( + "Please add the Folio to be Collected first before making payment" + ) + else: + for folio in folio_list: + arc_id.append(folio.ar_city_ledger_id) + payments = doc.get("payments") + return_status = 1 - for payment in payments: - remark = 'AR City Ledger Invoice Payments: ' + payment.name - doc_je = frappe.new_doc('Journal Entry') - doc_je.title = payment.name - doc_je.voucher_type = 'Journal Entry' - doc_je.naming_series = 'ACC-JV-.YYYY.-' - doc_je.posting_date = payment.payment_reference_date - doc_je.company = frappe.get_doc('Global Defaults').default_company - doc_je.total_amount_currency = frappe.get_doc('Global Defaults').default_currency - doc_je.remark = remark - doc_je.user_remark = remark + for payment in payments: + remark = "AR City Ledger Invoice Payments: " + payment.name + doc_je = frappe.new_doc("Journal Entry") + doc_je.title = payment.name + doc_je.voucher_type = "Journal Entry" + doc_je.naming_series = "ACC-JV-.YYYY.-" + doc_je.posting_date = payment.payment_reference_date + doc_je.company = frappe.get_doc("Global Defaults").default_company + doc_je.total_amount_currency = frappe.get_doc( + "Global Defaults" + ).default_currency + doc_je.remark = remark + doc_je.user_remark = remark - doc_jea_debit = frappe.new_doc('Journal Entry Account') - doc_jea_debit.account = payment.account - doc_jea_debit.debit = payment.payment_amount - doc_jea_debit.debit_in_account_currency = payment.payment_amount - doc_jea_debit.party_type = 'Customer' - doc_jea_debit.party = doc.customer_id - doc_jea_debit.user_remark = remark + doc_jea_debit = frappe.new_doc("Journal Entry Account") + doc_jea_debit.account = payment.account + doc_jea_debit.debit = payment.payment_amount + doc_jea_debit.debit_in_account_currency = payment.payment_amount + doc_jea_debit.party_type = "Customer" + doc_jea_debit.party = doc.customer_id + doc_jea_debit.user_remark = remark - doc_jea_credit = frappe.new_doc('Journal Entry Account') - doc_jea_credit.account = payment.account_against - doc_jea_credit.credit = payment.payment_amount - doc_jea_credit.credit_in_account_currency = payment.payment_amount - doc_jea_credit.party_type = 'Customer' - doc_jea_credit.party = doc.customer_id - doc_jea_credit.user_remark = remark + doc_jea_credit = frappe.new_doc("Journal Entry Account") + doc_jea_credit.account = payment.account_against + doc_jea_credit.credit = payment.payment_amount + doc_jea_credit.credit_in_account_currency = payment.payment_amount + doc_jea_credit.party_type = "Customer" + doc_jea_credit.party = doc.customer_id + doc_jea_credit.user_remark = remark - doc_je.append('accounts', doc_jea_debit) - doc_je.append('accounts', doc_jea_credit) + doc_je.append("accounts", doc_jea_debit) + doc_je.append("accounts", doc_jea_credit) - doc_je.save() - doc_je.submit() + doc_je.save() + doc_je.submit() - if frappe.db.get_value('Journal Entry', {'title': payment.name}, 'remark') == remark: - return_status = 2 + if ( + frappe.db.get_value("Journal Entry", {"title": payment.name}, "remark") + == remark + ): + return_status = 2 - if return_status == 1: - doc.status = 'Paid' - doc.save() - for arc in arc_id: - doc_arc_ledger = frappe.get_doc('AR City Ledger', arc) - doc_arc_ledger.is_paid = 1 - doc_arc_ledger.save() + if return_status == 1: + doc.status = "Paid" + doc.save() + for arc in arc_id: + doc_arc_ledger = frappe.get_doc("AR City Ledger", arc) + doc_arc_ledger.is_paid = 1 + doc_arc_ledger.save() - return return_status \ No newline at end of file + return return_status diff --git a/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.py b/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.py index 784bf5b6..3d069be6 100644 --- a/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.py +++ b/inn/inn_hotels/doctype/inn_dayend_close/inn_dayend_close.py @@ -9,380 +9,574 @@ from frappe.model.document import Document from inn.inn_hotels.doctype.inn_audit_log.inn_audit_log import get_last_audit_date from inn.inn_hotels.doctype.inn_folio.inn_folio import check_void_request -from inn.inn_hotels.doctype.inn_dayend_close.inn_dayend_close_helper import _fill_party_account +from inn.inn_hotels.doctype.inn_dayend_close.inn_dayend_close_helper import ( + _fill_party_account, +) + class InnDayendClose(Document): - pass + pass + @frappe.whitelist() def is_there_open_dayend_close(): - if frappe.get_all('Inn Dayend Close', {'status': 'Open'}): - return 1 - else: - return 2 + if frappe.get_all("Inn Dayend Close", {"status": "Open"}): + return 1 + else: + return 2 + @frappe.whitelist() def process_dayend_close(doc_id): - need_resolve_flag = False - - # Fetch transaction types from Inn Hotels Setting - hotel_settings = frappe.get_doc("Inn Hotels Setting") - transaction_types = { - "room_charge_tax_service": hotel_settings.room_charge_tax_service, - "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, - "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, - "package": hotel_settings.package, - "room_charge": hotel_settings.room_charge, - "breakfast_charge": hotel_settings.breakfast_charge, - "refund": hotel_settings.refund, - "dp_kamar": hotel_settings.dp_kamar, - "room_payment": hotel_settings.room_payment, - "deposit": hotel_settings.deposit, - "down_payment": hotel_settings.down_payment, - "payment": hotel_settings.payment, - "additional_charge": hotel_settings.additional_charge, - "restaurant_food": hotel_settings.restaurant_food, - "restaurant_beverages": hotel_settings.restaurant_beverages, - "restaurant_other": hotel_settings.restaurant_other, - "room_service_food": hotel_settings.room_service_food, - "room_service_beverage": hotel_settings.room_service_beverage, - "fbs_service_10": hotel_settings.fbs_service_10, - "fbs_tax_11": hotel_settings.fbs_tax_11, - "round_off": hotel_settings.round_off, - "laundry": hotel_settings.laundry, - "cancellation_fee": hotel_settings.cancellation_fee, - "late_checkout": hotel_settings.late_checkout, - "early_checkin": hotel_settings.early_checkin, - } - - COMMISSION_TRANSACTION_TYPE = hotel_settings.profit_sharing_transaction_type - - # Create Journal Entry Pairing for Every Eligible Inn Folio Transactions - folio_list = frappe.get_all('Inn Folio', filters={'status': ['in', ['Open', 'Closed']], 'journal_entry_id_closed': ['=', '']}, fields=["name", "reservation_id"]) - for item in folio_list: - need_resolve_list = check_void_request(item.name) - if len(need_resolve_list) > 0: - need_resolve_flag = True - break - - if need_resolve_flag: - return "There are transaction requested to be voided not yet responded. Please resolve the request first." - else: - print('Folio List Size: ',len(folio_list)) - for item in folio_list: - print(datetime.datetime.now(),': Folio ', item.name) - doc_folio = frappe.get_doc('Inn Folio', item.name) - if doc_folio.reservation_id: - reservation = frappe.get_doc('Inn Reservation', doc_folio.reservation_id) - - if reservation.status == 'In House': - actual_room = frappe.get_doc('Inn Room', reservation.actual_room_id) - actual_room.room_status = 'Occupied Dirty' - actual_room.save() - - trx_list : list[Document] = doc_folio.get('folio_transaction') - for trx in trx_list: - if trx.is_void == 0 and trx.journal_entry_id is None: - if trx.remark is None: - remark = trx.transaction_type + ' ' + trx.parent - elif trx.remark == '': - remark = trx.transaction_type + ' ' + trx.parent - else: - remark = trx.remark - customer_name = frappe.db.get_value('Inn Folio', trx.parent, 'customer_id') - doc_je = frappe.new_doc('Journal Entry') - doc_je.title = doc_folio.name - doc_je.voucher_type = 'Journal Entry' - doc_je.naming_series = 'ACC-JV-.YYYY.-' - doc_je.posting_date = get_last_audit_date() - doc_je.company = frappe.get_doc('Global Defaults').default_company - doc_je.total_amount_currency = frappe.get_doc('Global Defaults').default_currency - doc_je.remark = remark - doc_je.user_remark = remark - - doc_jea_debit = frappe.new_doc('Journal Entry Account') - doc_jea_debit.account = trx.debit_account - doc_jea_debit.debit = trx.amount - doc_jea_debit.debit_in_account_currency = trx.amount - doc_jea_debit.party_type, doc_jea_debit.party = _fill_party_account(doc_jea_debit.account, customer_name) - doc_jea_debit.user_remark = remark - - if trx.transaction_type == COMMISSION_TRANSACTION_TYPE and doc_jea_debit.party_type == "Supplier": - channel_id = frappe.db.get_value("Inn Reservation", item.reservation_id, fieldname="channel") - channel_vendor = frappe.db.get_value("Inn Channel", channel_id, channel_id) - doc_jea_debit.party = channel_vendor - - doc_jea_credit = frappe.new_doc('Journal Entry Account') - doc_jea_credit.account = trx.credit_account - doc_jea_credit.credit = trx.amount - doc_jea_credit.credit_in_account_currency = trx.amount - doc_jea_credit.party_type, doc_jea_credit.party = _fill_party_account(doc_jea_credit.account, customer_name) - doc_jea_credit.user_remark = remark - - if trx.transaction_type == COMMISSION_TRANSACTION_TYPE and doc_jea_credit.party_type == "Supplier": - channel_id = frappe.db.get_value("Inn Reservation", item.reservation_id, fieldname="channel") - channel_vendor = frappe.db.get_value(doctype="Inn Channel", filters={"name": channel_id}, fieldname="supplier") - doc_jea_credit.party = channel_vendor - - doc_je.append('accounts', doc_jea_debit) - doc_je.append('accounts', doc_jea_credit) - - doc_je.save() - doc_je.submit() - - trx.journal_entry_id = doc_je.name - trx.save() - - # Create Journal Entry Pairing for Every Eligible Inn Folio - closed_folio_list = frappe.get_all('Inn Folio', filters={ - 'status': 'Closed', - 'total_credit': ['!=', 0], - 'total_debit': ['!=', 0], - 'journal_entry_id_closed': ['=', ''] - }) - for item in closed_folio_list: - doc_folio = frappe.get_doc('Inn Folio', item.name) - cust_name = doc_folio.customer_id - # Get all Closed folio with close date == last audit date - if doc_folio.journal_entry_id_closed is None and doc_folio.close == get_last_audit_date(): - closed_folio_remark = 'Closed Folio Transaction' - # Get all transactions that not void - closed_trx_list = frappe.get_all('Inn Folio Transaction', - filters={'parent': item.name,'is_void': 0}, - fields=['*']) - # Folio must not be empty, Because Journal Entry Table Account not allowed to be empty - if len(closed_trx_list) > 0: - doc_je = frappe.new_doc('Journal Entry') - doc_je.title = doc_folio.name - doc_je.voucher_type = 'Journal Entry' - doc_je.naming_series = 'ACC-JV-.YYYY.-' - doc_je.posting_date = get_last_audit_date() - doc_je.company = frappe.get_doc('Global Defaults').default_company - doc_je.total_amount_currency = frappe.get_doc('Global Defaults').default_currency - doc_je.remark = closed_folio_remark - doc_je.user_remark = closed_folio_remark - - for trx in closed_trx_list: - if trx.flag == 'Debit': - doc_jea_debit = frappe.new_doc('Journal Entry Account') - doc_jea_debit.account = trx.debit_account - doc_jea_debit.debit = trx.amount - doc_jea_debit.credit_in_account_currency = trx.amount #amount flipped to credit - doc_jea_debit.party_type, doc_jea_debit.party = _fill_party_account(doc_jea_debit.account, cust_name) - doc_jea_debit.user_remark = closed_folio_remark - doc_je.append('accounts', doc_jea_debit) - print(f"DEBIT {doc_jea_debit.debit} - {doc_jea_debit.credit_in_account_currency} {trx.remark}") - elif trx.flag == 'Credit': - doc_jea_credit = frappe.new_doc('Journal Entry Account') - doc_jea_credit.account = trx.credit_account - doc_jea_credit.credit = trx.amount - doc_jea_credit.debit_in_account_currency = trx.amount #amount flipped to debit - doc_jea_credit.party_type, doc_jea_credit.party = _fill_party_account(doc_jea_credit.account, cust_name) - doc_jea_credit.user_remark = closed_folio_remark - doc_je.append('accounts', doc_jea_credit) - print(f"CREDIT {doc_jea_credit.credit} - {doc_jea_credit.debit_in_account_currency} {trx.remark}") - - doc_je.save() - doc_je.submit() - doc_folio.journal_entry_id_closed = doc_je.name - doc_folio.save() - - # Create Journal Entry for Inn Restaurant Finished Order - # Get all finished order that not transfered to folio and not paired with journal entry yet - create_je_for_inn_restaurant_finished_order(transaction_types) - - doc_audit_log = frappe.new_doc('Inn Audit Log') - doc_audit_log.naming_series = 'AL.DD.-.MM.-.YYYY.-' - doc_audit_log.audit_date = get_last_audit_date() + datetime.timedelta(days = 1) - doc_audit_log.posting_date = datetime.datetime.now() - doc_audit_log.posted_by =frappe.session.user - doc_audit_log.insert() - - doc = frappe.get_doc('Inn Dayend Close', doc_id) - doc.status = 'Closed' - doc.save() - - return doc.status + need_resolve_flag = False + + # Fetch transaction types from Inn Hotels Setting + hotel_settings = frappe.get_doc("Inn Hotels Setting") + transaction_types = { + "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, + "package": hotel_settings.package, + "room_charge": hotel_settings.room_charge, + "breakfast_charge": hotel_settings.breakfast_charge, + "refund": hotel_settings.refund, + "dp_kamar": hotel_settings.dp_kamar, + "room_payment": hotel_settings.room_payment, + "deposit": hotel_settings.deposit, + "down_payment": hotel_settings.down_payment, + "payment": hotel_settings.payment, + "additional_charge": hotel_settings.additional_charge, + "restaurant_food": hotel_settings.restaurant_food, + "restaurant_beverages": hotel_settings.restaurant_beverages, + "restaurant_other": hotel_settings.restaurant_other, + "room_service_food": hotel_settings.room_service_food, + "room_service_beverage": hotel_settings.room_service_beverage, + "fbs_service_10": hotel_settings.fbs_service_10, + "round_off": hotel_settings.round_off, + "laundry": hotel_settings.laundry, + "cancellation_fee": hotel_settings.cancellation_fee, + "late_checkout": hotel_settings.late_checkout, + "early_checkin": hotel_settings.early_checkin, + } + if hotel_settings.include_tax: + transaction_types["room_charge_tax_service"] = ( + hotel_settings.room_charge_tax_service + ) + + transaction_types["breakfast_charge_tax_service"] = ( + hotel_settings.breakfast_charge_tax_service + ) + + transaction_types["fbs_tax_11"] = hotel_settings.fbs_tax_11 + + COMMISSION_TRANSACTION_TYPE = hotel_settings.profit_sharing_transaction_type + + # Create Journal Entry Pairing for Every Eligible Inn Folio Transactions + folio_list = frappe.get_all( + "Inn Folio", + filters={ + "status": ["in", ["Open", "Closed"]], + "journal_entry_id_closed": ["=", ""], + }, + fields=["name", "reservation_id"], + ) + for item in folio_list: + need_resolve_list = check_void_request(item.name) + if len(need_resolve_list) > 0: + need_resolve_flag = True + break + + if need_resolve_flag: + return "There are transaction requested to be voided not yet responded. Please resolve the request first." + else: + print("Folio List Size: ", len(folio_list)) + for item in folio_list: + print(datetime.datetime.now(), ": Folio ", item.name) + doc_folio = frappe.get_doc("Inn Folio", item.name) + if doc_folio.reservation_id: + reservation = frappe.get_doc( + "Inn Reservation", doc_folio.reservation_id + ) + + if reservation.status == "In House": + actual_room = frappe.get_doc("Inn Room", reservation.actual_room_id) + actual_room.room_status = "Occupied Dirty" + actual_room.save() + + trx_list: list[Document] = doc_folio.get("folio_transaction") + for trx in trx_list: + if trx.is_void == 0 and trx.journal_entry_id is None: + if trx.remark is None: + remark = trx.transaction_type + " " + trx.parent + elif trx.remark == "": + remark = trx.transaction_type + " " + trx.parent + else: + remark = trx.remark + customer_name = frappe.db.get_value( + "Inn Folio", trx.parent, "customer_id" + ) + doc_je = frappe.new_doc("Journal Entry") + doc_je.title = doc_folio.name + doc_je.voucher_type = "Journal Entry" + doc_je.naming_series = "ACC-JV-.YYYY.-" + doc_je.posting_date = get_last_audit_date() + doc_je.company = frappe.get_doc("Global Defaults").default_company + doc_je.total_amount_currency = frappe.get_doc( + "Global Defaults" + ).default_currency + doc_je.remark = remark + doc_je.user_remark = remark + + doc_jea_debit = frappe.new_doc("Journal Entry Account") + doc_jea_debit.account = trx.debit_account + doc_jea_debit.debit = trx.amount + doc_jea_debit.debit_in_account_currency = trx.amount + doc_jea_debit.party_type, doc_jea_debit.party = _fill_party_account( + doc_jea_debit.account, customer_name + ) + doc_jea_debit.user_remark = remark + + if ( + trx.transaction_type == COMMISSION_TRANSACTION_TYPE + and doc_jea_debit.party_type == "Supplier" + ): + channel_id = frappe.db.get_value( + "Inn Reservation", item.reservation_id, fieldname="channel" + ) + channel_vendor = frappe.db.get_value( + "Inn Channel", channel_id, channel_id + ) + doc_jea_debit.party = channel_vendor + + doc_jea_credit = frappe.new_doc("Journal Entry Account") + doc_jea_credit.account = trx.credit_account + doc_jea_credit.credit = trx.amount + doc_jea_credit.credit_in_account_currency = trx.amount + doc_jea_credit.party_type, doc_jea_credit.party = ( + _fill_party_account(doc_jea_credit.account, customer_name) + ) + doc_jea_credit.user_remark = remark + + if ( + trx.transaction_type == COMMISSION_TRANSACTION_TYPE + and doc_jea_credit.party_type == "Supplier" + ): + channel_id = frappe.db.get_value( + "Inn Reservation", item.reservation_id, fieldname="channel" + ) + channel_vendor = frappe.db.get_value( + doctype="Inn Channel", + filters={"name": channel_id}, + fieldname="supplier", + ) + doc_jea_credit.party = channel_vendor + + doc_je.append("accounts", doc_jea_debit) + doc_je.append("accounts", doc_jea_credit) + + doc_je.save() + doc_je.submit() + + trx.journal_entry_id = doc_je.name + trx.save() + + # Create Journal Entry Pairing for Every Eligible Inn Folio + closed_folio_list = frappe.get_all( + "Inn Folio", + filters={ + "status": "Closed", + "total_credit": ["!=", 0], + "total_debit": ["!=", 0], + "journal_entry_id_closed": ["=", ""], + }, + ) + for item in closed_folio_list: + doc_folio = frappe.get_doc("Inn Folio", item.name) + cust_name = doc_folio.customer_id + # Get all Closed folio with close date == last audit date + if ( + doc_folio.journal_entry_id_closed is None + and doc_folio.close == get_last_audit_date() + ): + closed_folio_remark = "Closed Folio Transaction" + # Get all transactions that not void + closed_trx_list = frappe.get_all( + "Inn Folio Transaction", + filters={"parent": item.name, "is_void": 0}, + fields=["*"], + ) + # Folio must not be empty, Because Journal Entry Table Account not allowed to be empty + if len(closed_trx_list) > 0: + doc_je = frappe.new_doc("Journal Entry") + doc_je.title = doc_folio.name + doc_je.voucher_type = "Journal Entry" + doc_je.naming_series = "ACC-JV-.YYYY.-" + doc_je.posting_date = get_last_audit_date() + doc_je.company = frappe.get_doc("Global Defaults").default_company + doc_je.total_amount_currency = frappe.get_doc( + "Global Defaults" + ).default_currency + doc_je.remark = closed_folio_remark + doc_je.user_remark = closed_folio_remark + + for trx in closed_trx_list: + if trx.flag == "Debit": + doc_jea_debit = frappe.new_doc("Journal Entry Account") + doc_jea_debit.account = trx.debit_account + doc_jea_debit.debit = trx.amount + doc_jea_debit.credit_in_account_currency = ( + trx.amount + ) # amount flipped to credit + doc_jea_debit.party_type, doc_jea_debit.party = ( + _fill_party_account(doc_jea_debit.account, cust_name) + ) + doc_jea_debit.user_remark = closed_folio_remark + doc_je.append("accounts", doc_jea_debit) + print( + f"DEBIT {doc_jea_debit.debit} - {doc_jea_debit.credit_in_account_currency} {trx.remark}" + ) + elif trx.flag == "Credit": + doc_jea_credit = frappe.new_doc("Journal Entry Account") + doc_jea_credit.account = trx.credit_account + doc_jea_credit.credit = trx.amount + doc_jea_credit.debit_in_account_currency = ( + trx.amount + ) # amount flipped to debit + doc_jea_credit.party_type, doc_jea_credit.party = ( + _fill_party_account(doc_jea_credit.account, cust_name) + ) + doc_jea_credit.user_remark = closed_folio_remark + doc_je.append("accounts", doc_jea_credit) + print( + f"CREDIT {doc_jea_credit.credit} - {doc_jea_credit.debit_in_account_currency} {trx.remark}" + ) + + doc_je.save() + doc_je.submit() + doc_folio.journal_entry_id_closed = doc_je.name + doc_folio.save() + + # Create Journal Entry for Inn Restaurant Finished Order + # Get all finished order that not transfered to folio and not paired with journal entry yet + # create_je_for_inn_restaurant_finished_order(transaction_types) + + doc_audit_log = frappe.new_doc("Inn Audit Log") + doc_audit_log.naming_series = "AL.DD.-.MM.-.YYYY.-" + doc_audit_log.audit_date = get_last_audit_date() + datetime.timedelta(days=1) + doc_audit_log.posting_date = datetime.datetime.now() + doc_audit_log.posted_by = frappe.session.user + doc_audit_log.insert() + + doc = frappe.get_doc("Inn Dayend Close", doc_id) + doc.status = "Closed" + doc.save() + + return doc.status + @frappe.whitelist() def load_child(date): - audit_date = datetime.datetime.strptime(date, '%Y-%m-%d').date() - # return get_arrived_today(audit_date), get_departed_today(audit_date), get_closed_today(audit_date), get_ongoing_order_need_to_be_finished() - return get_arrived_today(audit_date), get_departed_today(audit_date), get_closed_today(audit_date) + audit_date = datetime.datetime.strptime(date, "%Y-%m-%d").date() + # return get_arrived_today(audit_date), get_departed_today(audit_date), get_closed_today(audit_date), get_ongoing_order_need_to_be_finished() + return ( + get_arrived_today(audit_date), + get_departed_today(audit_date), + get_closed_today(audit_date), + ) + def get_arrived_today(date): - return_list = [] - list = frappe.get_all('Inn Reservation', filters={'status': 'Reserved'}, fields=['*']) - for item in list: - if item.expected_arrival == date: - new_arrived = frappe.new_doc('Inn Expected Arrived Today') - new_arrived.reservation_id = item.name - new_arrived.folio_id = frappe.get_doc('Inn Folio', {'reservation_id': item.name}).name - new_arrived.customer_id = item.customer_id - new_arrived.description = 'Must Check In Today' - return_list.append(new_arrived) - return return_list + return_list = [] + list = frappe.get_all( + "Inn Reservation", filters={"status": "Reserved"}, fields=["*"] + ) + for item in list: + if item.expected_arrival == date: + new_arrived = frappe.new_doc("Inn Expected Arrived Today") + new_arrived.reservation_id = item.name + new_arrived.folio_id = frappe.get_doc( + "Inn Folio", {"reservation_id": item.name} + ).name + new_arrived.customer_id = item.customer_id + new_arrived.description = "Must Check In Today" + return_list.append(new_arrived) + return return_list + def get_departed_today(date): - return_list = [] - list = frappe.get_all('Inn Reservation', filters={'status': 'In House'}, fields=['*']) - for item in list: - if item.departure.date() == date: - new_departed = frappe.new_doc('Inn Expected Departed Today') - new_departed.reservation_id = item.name - new_departed.folio_id = frappe.get_doc('Inn Folio', {'reservation_id': item.name}).name - new_departed.customer_id = item.customer_id - new_departed.description = 'Must Check Out Today' - return_list.append(new_departed) - return return_list + return_list = [] + list = frappe.get_all( + "Inn Reservation", filters={"status": "In House"}, fields=["*"] + ) + for item in list: + if item.departure.date() == date: + new_departed = frappe.new_doc("Inn Expected Departed Today") + new_departed.reservation_id = item.name + new_departed.folio_id = frappe.get_doc( + "Inn Folio", {"reservation_id": item.name} + ).name + new_departed.customer_id = item.customer_id + new_departed.description = "Must Check Out Today" + return_list.append(new_departed) + return return_list + def get_closed_today(date): - return_list = [] - list = frappe.get_all('Inn Folio', filters={'status': 'Open', 'type': ['in', ['Master', 'Desk']]}, fields=['*']) - for item in list: - if item.close == date: - new_closed = frappe.new_doc('Inn Expected Closed Today') - new_closed.type = item.type - new_closed.folio_id = item.name - new_closed.customer_id = item.customer_id - new_closed.description = 'Must Close Today' - return_list.append(new_closed) - return return_list + return_list = [] + list = frappe.get_all( + "Inn Folio", + filters={"status": "Open", "type": ["in", ["Master", "Desk"]]}, + fields=["*"], + ) + for item in list: + if item.close == date: + new_closed = frappe.new_doc("Inn Expected Closed Today") + new_closed.type = item.type + new_closed.folio_id = item.name + new_closed.customer_id = item.customer_id + new_closed.description = "Must Close Today" + return_list.append(new_closed) + return return_list + def get_ongoing_order_need_to_be_finished(): - return_list = [] - list = frappe.get_all('Inn Restaurant Ongoing Order', fields=['*']) - for item in list: - new_order_need_to_finish = frappe.new_doc('Inn Restaurant Order Expected to be Finished') - new_order_need_to_finish.ongoing_order_id = item.name - new_order_need_to_finish.restaurant = item.restaurant - new_order_need_to_finish.customer = item.customer - new_order_need_to_finish.description = 'Restaurant Order need to be finished today' - return_list.append(new_order_need_to_finish) - return return_list + return_list = [] + list = frappe.get_all("Inn Restaurant Ongoing Order", fields=["*"]) + for item in list: + new_order_need_to_finish = frappe.new_doc( + "Inn Restaurant Order Expected to be Finished" + ) + new_order_need_to_finish.ongoing_order_id = item.name + new_order_need_to_finish.restaurant = item.restaurant + new_order_need_to_finish.customer = item.customer + new_order_need_to_finish.description = ( + "Restaurant Order need to be finished today" + ) + return_list.append(new_order_need_to_finish) + return return_list + def create_journal_entry(title, remark, debit_account, credit_account, amount): - print("Journal Entry Title: " + title) - customer_name = 'Customer Restaurant' - doc_je = frappe.new_doc('Journal Entry') - doc_je.title = title - doc_je.voucher_type = 'Journal Entry' - doc_je.naming_series = 'ACC-JV-.YYYY.-' - doc_je.posting_date = get_last_audit_date() - doc_je.company = frappe.get_doc('Global Defaults').default_company - doc_je.total_amount_currency = frappe.get_doc('Global Defaults').default_currency - doc_je.remark = remark - doc_je.user_remark = remark - - doc_jea_debit = frappe.new_doc('Journal Entry Account') - doc_jea_debit.account = debit_account - doc_jea_debit.debit = amount - doc_jea_debit.debit_in_account_currency = amount - doc_jea_debit.party_type, doc_jea_debit.party = _fill_party_account(doc_jea_debit.account, customer_name) - doc_jea_debit.user_remark = remark - - doc_jea_credit = frappe.new_doc('Journal Entry Account') - doc_jea_credit.account = credit_account - doc_jea_credit.credit = amount - doc_jea_credit.credit_in_account_currency = amount - doc_jea_credit.party_type, doc_jea_credit.party = _fill_party_account(doc_jea_credit.account, customer_name) - doc_jea_credit.user_remark = remark - - doc_je.append('accounts', doc_jea_debit) - doc_je.append('accounts', doc_jea_credit) - - doc_je.save() - doc_je.submit() + print("Journal Entry Title: " + title) + customer_name = "Customer Restaurant" + doc_je = frappe.new_doc("Journal Entry") + doc_je.title = title + doc_je.voucher_type = "Journal Entry" + doc_je.naming_series = "ACC-JV-.YYYY.-" + doc_je.posting_date = get_last_audit_date() + doc_je.company = frappe.get_doc("Global Defaults").default_company + doc_je.total_amount_currency = frappe.get_doc("Global Defaults").default_currency + doc_je.remark = remark + doc_je.user_remark = remark + + doc_jea_debit = frappe.new_doc("Journal Entry Account") + doc_jea_debit.account = debit_account + doc_jea_debit.debit = amount + doc_jea_debit.debit_in_account_currency = amount + doc_jea_debit.party_type, doc_jea_debit.party = _fill_party_account( + doc_jea_debit.account, customer_name + ) + doc_jea_debit.user_remark = remark + + doc_jea_credit = frappe.new_doc("Journal Entry Account") + doc_jea_credit.account = credit_account + doc_jea_credit.credit = amount + doc_jea_credit.credit_in_account_currency = amount + doc_jea_credit.party_type, doc_jea_credit.party = _fill_party_account( + doc_jea_credit.account, customer_name + ) + doc_jea_credit.user_remark = remark + + doc_je.append("accounts", doc_jea_debit) + doc_je.append("accounts", doc_jea_credit) + + doc_je.save() + doc_je.submit() + def create_je_for_inn_restaurant_finished_order(transaction_types): - order_list = frappe.get_all('Inn Restaurant Finished Order', - filters={ - 'transfer_charges_folio': ('=', ''), - 'is_journaled': 0, - }, fields=['*']) - for order in order_list: - restaurant_food = 0 - restaurant_beverage = 0 - restaurant_other = 0 - - # 1. ORDER ITEM IN RESTAURANT FINISHED ORDER - order_item_list = frappe.get_all('Inn Restaurant Order Item', filters={'parent': order.name}, fields=['*']) - - print("order item list of " + order.name + " is " + str(len(order_item_list))) - if order_item_list is not None and len(order_item_list) > 0: - print("masuk if order list exist") - # Calculate Total Amount of Food, Beverages and Other Charges in Restaurant Order - for item in order_item_list: - print('item now = ' + item.name) - menu_type = frappe.db.get_value('Inn Restaurant Menu Item', item.item, 'item_type') - print('menu type = ' + menu_type) - if menu_type == 'Food': - restaurant_food += float(item.rate) - print('restaurant_food now = ' + str(restaurant_food)) - elif menu_type == 'Beverage': - restaurant_beverage += float(item.rate) - print('restaurant_beverage now = ' + str(restaurant_beverage)) - elif menu_type == 'Other': - restaurant_other += float(item.rate) - print('restaurant_other now = ' + str(restaurant_other)) - else: - print("order list not exist") - # Create Journal Entry for Total Amount of Orders for Food, Beverages, and Other Restaurant charges - if restaurant_food > 0: - print("entry restaurant food") - food_title = 'Restaurant Food of ' + order.name - food_remark = 'Restaurant Food Charges from Restaurant Order: ' + order.name - food_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_food"]).debit_account - food_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_food"]).credit_account - create_journal_entry(food_title, food_remark, food_debit_account, food_credit_account, restaurant_food) - - if restaurant_beverage > 0: - print("entry restaurant beverage") - bev_title = 'Restaurant Beverages of ' + order.name - bev_remark = 'Restaurant Beverage Charges from Restaurant Order: ' + order.name - bev_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_beverages"]).debit_account - bev_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_beverages"]).credit_account - create_journal_entry(bev_title, bev_remark, bev_debit_account, bev_credit_account, restaurant_beverage) - if restaurant_other > 0: - print("entry Other Restaurant") - other_title = 'Other Restaurant of ' + order.name - other_remark = 'Other Restaurant Charges from Restaurant Order: ' + order.name - other_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_other"]).debit_account - other_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["restaurant_other"]).credit_account - create_journal_entry(other_title, other_remark, other_debit_account, other_credit_account, restaurant_other) - - # Create Journal Entry for Round Off Charges - if float(order.rounding_amount) > 0: - ro_title = 'Round Off of ' + order.name - ro_remark = 'Rounding off Amount of Restaurant Charges from Restaurant Order: ' + order.name - ro_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["round_off"]).debit_account - ro_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["round_off"]).credit_account - create_journal_entry(ro_title, ro_remark, ro_debit_account, ro_credit_account, order.rounding_amount) - - # Create Journal Entry for Service - service_title = 'FBS -- Service 10 % of ' + order.name - service_remark = 'Service of Restaurant Charges from Restaurant Order: ' + order.name - srv_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["fbs_service_10"]).debit_account - srv_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["fbs_service_10"]).credit_account - create_journal_entry(service_title, service_remark, srv_debit_account, srv_credit_account, order.service_amount) - # Create Journal Entry for Tax - tax_title = 'FBS -- Tax 11 %' + order.name - tax_remark = 'Tax of Restaurant Charges from Restaurant Order: ' + order.name - tax_debit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["fbs_tax_11"]).debit_account - tax_credit_account = frappe.get_doc('Inn Folio Transaction Type', transaction_types["fbs_tax_11"]).credit_account - create_journal_entry(tax_title, tax_remark, tax_debit_account, tax_credit_account, order.tax_amount) - - # 2. ORDER PAYMENT IN RESTAURANT FINISHED ORDER - order_payment_list = order.get('order_payment') - if order_payment_list is not None and len(order_payment_list) > 0: - for payment in order_payment_list: - payment_title = payment.mode_of_payment + ' Payment for ' + order.name - payment_remark = 'Payment with ' + payment.mode_of_payment + 'from Restaurant Order: ' + order.name - payment_debit_account = frappe.db.get_value('Mode of Payment Account', - {'parent': payment.mode_of_payment, 'company': frappe.get_doc( - "Global Defaults").default_company}, "default_account") - payment_credit_account = frappe.db.get_list('Account', filters={'account_number': '2110.005'})[0].name - create_journal_entry(payment_title, payment_remark, payment_debit_account, payment_credit_account, payment.amount) - - # 3. SET VALUE IS_JOURNALED IN FINISHED ORDER TO TRUE, MARKING THAT THE ORDER ALREADY PAIRED WITH JOURNAL ENTRIES - frappe.db.set_value('Inn Restaurant Finished Order', order.name, 'is_journaled', 1) \ No newline at end of file + order_list = frappe.get_all( + "Inn Restaurant Finished Order", + filters={ + "transfer_charges_folio": ("=", ""), + "is_journaled": 0, + }, + fields=["*"], + ) + for order in order_list: + restaurant_food = 0 + restaurant_beverage = 0 + restaurant_other = 0 + + # 1. ORDER ITEM IN RESTAURANT FINISHED ORDER + order_item_list = frappe.get_all( + "Inn Restaurant Order Item", filters={"parent": order.name}, fields=["*"] + ) + + print("order item list of " + order.name + " is " + str(len(order_item_list))) + if order_item_list is not None and len(order_item_list) > 0: + print("masuk if order list exist") + # Calculate Total Amount of Food, Beverages and Other Charges in Restaurant Order + for item in order_item_list: + print("item now = " + item.name) + menu_type = frappe.db.get_value( + "Inn Restaurant Menu Item", item.item, "item_type" + ) + print("menu type = " + menu_type) + if menu_type == "Food": + restaurant_food += float(item.rate) + print("restaurant_food now = " + str(restaurant_food)) + elif menu_type == "Beverage": + restaurant_beverage += float(item.rate) + print("restaurant_beverage now = " + str(restaurant_beverage)) + elif menu_type == "Other": + restaurant_other += float(item.rate) + print("restaurant_other now = " + str(restaurant_other)) + else: + print("order list not exist") + # Create Journal Entry for Total Amount of Orders for Food, Beverages, and Other Restaurant charges + if restaurant_food > 0: + print("entry restaurant food") + food_title = "Restaurant Food of " + order.name + food_remark = "Restaurant Food Charges from Restaurant Order: " + order.name + food_debit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["restaurant_food"] + ).debit_account + food_credit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["restaurant_food"] + ).credit_account + create_journal_entry( + food_title, + food_remark, + food_debit_account, + food_credit_account, + restaurant_food, + ) + + if restaurant_beverage > 0: + print("entry restaurant beverage") + bev_title = "Restaurant Beverages of " + order.name + bev_remark = ( + "Restaurant Beverage Charges from Restaurant Order: " + order.name + ) + bev_debit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["restaurant_beverages"] + ).debit_account + bev_credit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["restaurant_beverages"] + ).credit_account + create_journal_entry( + bev_title, + bev_remark, + bev_debit_account, + bev_credit_account, + restaurant_beverage, + ) + if restaurant_other > 0: + print("entry Other Restaurant") + other_title = "Other Restaurant of " + order.name + other_remark = ( + "Other Restaurant Charges from Restaurant Order: " + order.name + ) + other_debit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["restaurant_other"] + ).debit_account + other_credit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["restaurant_other"] + ).credit_account + create_journal_entry( + other_title, + other_remark, + other_debit_account, + other_credit_account, + restaurant_other, + ) + + # Create Journal Entry for Round Off Charges + if float(order.rounding_amount) > 0: + ro_title = "Round Off of " + order.name + ro_remark = ( + "Rounding off Amount of Restaurant Charges from Restaurant Order: " + + order.name + ) + ro_debit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["round_off"] + ).debit_account + ro_credit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["round_off"] + ).credit_account + create_journal_entry( + ro_title, + ro_remark, + ro_debit_account, + ro_credit_account, + order.rounding_amount, + ) + + # Create Journal Entry for Service + service_title = "FBS -- Service 10 % of " + order.name + service_remark = ( + "Service of Restaurant Charges from Restaurant Order: " + order.name + ) + srv_debit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["fbs_service_10"] + ).debit_account + srv_credit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["fbs_service_10"] + ).credit_account + create_journal_entry( + service_title, + service_remark, + srv_debit_account, + srv_credit_account, + order.service_amount, + ) + # Create Journal Entry for Tax + tax_title = "FBS -- Tax 11 %" + order.name + tax_remark = "Tax of Restaurant Charges from Restaurant Order: " + order.name + tax_debit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["fbs_tax_11"] + ).debit_account + tax_credit_account = frappe.get_doc( + "Inn Folio Transaction Type", transaction_types["fbs_tax_11"] + ).credit_account + create_journal_entry( + tax_title, + tax_remark, + tax_debit_account, + tax_credit_account, + order.tax_amount, + ) + + # 2. ORDER PAYMENT IN RESTAURANT FINISHED ORDER + order_payment_list = order.get("order_payment") + if order_payment_list is not None and len(order_payment_list) > 0: + for payment in order_payment_list: + payment_title = payment.mode_of_payment + " Payment for " + order.name + payment_remark = ( + "Payment with " + + payment.mode_of_payment + + "from Restaurant Order: " + + order.name + ) + payment_debit_account = frappe.db.get_value( + "Mode of Payment Account", + { + "parent": payment.mode_of_payment, + "company": frappe.get_doc("Global Defaults").default_company, + }, + "default_account", + ) + payment_credit_account = frappe.db.get_list( + "Account", filters={"account_number": "2110.005"} + )[0].name + create_journal_entry( + payment_title, + payment_remark, + payment_debit_account, + payment_credit_account, + payment.amount, + ) + + # 3. SET VALUE IS_JOURNALED IN FINISHED ORDER TO TRUE, MARKING THAT THE ORDER ALREADY PAIRED WITH JOURNAL ENTRIES + frappe.db.set_value( + "Inn Restaurant Finished Order", order.name, "is_journaled", 1 + ) diff --git a/inn/inn_hotels/doctype/inn_folio/inn_folio.js b/inn/inn_hotels/doctype/inn_folio/inn_folio.js index 4f33bf27..84c8bab3 100644 --- a/inn/inn_hotels/doctype/inn_folio/inn_folio.js +++ b/inn/inn_hotels/doctype/inn_folio/inn_folio.js @@ -1,793 +1,891 @@ // Copyright (c) 2020, Core Initiative and contributors // For license information, please see license.txt -var is_check_in = getUrlVars()['is_check_in']; +var is_check_in = getUrlVars()["is_check_in"]; var void_shown = false; var folio_transaction = null; -frappe.ui.form.on('Inn Folio', { - before_save: function(frm) { - make_mandatory(frm); - }, - onload: function(frm) { - frm.get_field("folio_transaction").grid.only_sortable(); - make_read_only(frm); - }, - transfer_to_another_folio: function(frm) { - if (frm.doc.__islocal !== 1) { - let trx_selected = frm.get_field("folio_transaction").grid.get_selected(); - if (trx_selected.length === 0) { - frappe.msgprint('Please select at least one transaction to be transfered'); - } - else { - transfer_to_another_folio(frm, trx_selected); - } - } - }, - add_package: function(frm) { - add_package(frm); - }, - add_charge: function (frm) { - add_charge(frm); - }, - add_payment: function (frm) { - add_payment(frm); - }, - add_refund: function (frm) { - add_refund(frm); - }, - toggle_void_transaction: function(frm, cdt, cdn) { - folio_transaction = frm.get_doc(cdt, cdn).folio_transaction; - if (void_shown == false) { - folio_transaction.forEach(show_void); - void_shown = true; - frm.fields_dict['toggle_void_transaction'].label = 'Hide Void Transaction'; - frm.refresh_field('toggle_void_transaction'); - } - else { - folio_transaction.forEach(hide_void); - void_shown = false; - frm.fields_dict['toggle_void_transaction'].label = 'Show Void Transaction'; - frm.refresh_field('toggle_void_transaction'); - } - }, - refresh: function (frm, cdt, cdn) { - make_read_only(frm); - if (frm.doc.__islocal !== 1) { - var x = frappe.get_doc(cdt, cdn).folio_transaction; - if (x) { - x.forEach(hide_void); - } - if (frm.doc.status === 'Open') { - toggle_visibility_buttons(frm, 0); - // Auto update balance if needed - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio.inn_folio.need_to_update_balance', - args: { - folio_id: frm.doc.name - }, - callback: (r) => { - if (r.message === 1) { - // update needed - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio.inn_folio.update_balance', - args: { - folio_id: frm.doc.name - }, - callback: (r) => { - if (r.message) { - frm.doc.total_debit = r.message[0]; - frm.doc.total_credit = r.message[1]; - frm.doc.balance = r.message[2]; - frm.refresh_field('total_debit'); - frm.refresh_field('total_credit'); - frm.refresh_field('balance'); - } - } - }); - } - } - }); - // Close folio manually for Folio type master or desk - if (frm.doc.type !== 'Guest') { - frm.page.add_menu_item(__('Close Folio'), function () { - if (frm.doc.balance !== 0) { - frappe.msgprint("Balance is not 0. There are still transactions needed to be resolved."); - } - else { - close_folio(frm); - } - }); - } - } - toggle_guest_in_type(frm, 0); - // Show Reservation Button - if (frm.doc.reservation_id !== undefined) { - frm.add_custom_button(__('Show Reservation'), function () { - let url = frappe.urllib.get_full_url('/app/inn-reservation/' + frm.doc.reservation_id); - if (is_check_in === 'true') { - url = url + '?is_check_in=true' - } - var w = window.open(url, "_self"); - }); - } - // Update Balance Button - if (frm.doc.status !== 'Cancel') { - frm.add_custom_button(__('Update Balance'), function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio.inn_folio.need_to_update_balance', - args: { - folio_id: frm.doc.name - }, - callback: (r) => { - if (r.message === 1) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio.inn_folio.update_balance', - args: { - folio_id: frm.doc.name - }, - callback: (r) => { - if (r.message) { - frappe.show_alert("Balance updated."); - frm.doc.total_debit = r.message[0]; - frm.doc.total_credit = r.message[1]; - frm.doc.balance = r.message[2]; - frm.refresh_field('total_debit'); - frm.refresh_field('total_credit'); - frm.refresh_field('balance'); - } - } - }); - } - else { - frappe.show_alert('Balance already updated.'); - } - } - }); - }); - } - } - else { - toggle_visibility_buttons(frm, 1); - toggle_guest_in_type(frm, 1); - } - }, - close: function (frm) { - if (frm.doc.type != 'Desk') { - if (frm.doc.close < frm.doc.open) { - frm.set_value('close', null); - frappe.msgprint('Close Date must be greater than Open Date'); - } - } - } +frappe.ui.form.on("Inn Folio", { + before_save: function (frm) { + make_mandatory(frm); + }, + onload: function (frm) { + frm.get_field("folio_transaction").grid.only_sortable(); + make_read_only(frm); + make_fields_filtered(frm); + }, + transfer_to_another_folio: function (frm) { + if (frm.doc.__islocal !== 1) { + let trx_selected = frm.get_field("folio_transaction").grid.get_selected(); + if (trx_selected.length === 0) { + frappe.msgprint( + "Please select at least one transaction to be transfered" + ); + } else { + transfer_to_another_folio(frm, trx_selected); + } + } + }, + add_package: function (frm) { + add_package(frm); + }, + add_charge: function (frm) { + add_charge(frm); + }, + add_payment: function (frm) { + add_payment(frm); + }, + add_refund: function (frm) { + add_refund(frm); + }, + toggle_void_transaction: function (frm, cdt, cdn) { + folio_transaction = frm.get_doc(cdt, cdn).folio_transaction; + if (void_shown == false) { + folio_transaction.forEach(show_void); + void_shown = true; + frm.fields_dict["toggle_void_transaction"].label = + "Hide Void Transaction"; + frm.refresh_field("toggle_void_transaction"); + } else { + folio_transaction.forEach(hide_void); + void_shown = false; + frm.fields_dict["toggle_void_transaction"].label = + "Show Void Transaction"; + frm.refresh_field("toggle_void_transaction"); + } + }, + refresh: function (frm, cdt, cdn) { + make_read_only(frm); + if (frm.doc.__islocal !== 1) { + var x = frappe.get_doc(cdt, cdn).folio_transaction; + if (x) { + x.forEach(hide_void); + } + if (frm.doc.status === "Open") { + toggle_visibility_buttons(frm, 0); + // Auto update balance if needed + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio.inn_folio.need_to_update_balance", + args: { + folio_id: frm.doc.name, + }, + callback: (r) => { + if (r.message === 1) { + // update needed + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio.inn_folio.update_balance", + args: { + folio_id: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + frm.doc.total_debit = r.message[0]; + frm.doc.total_credit = r.message[1]; + frm.doc.balance = r.message[2]; + frm.refresh_field("total_debit"); + frm.refresh_field("total_credit"); + frm.refresh_field("balance"); + } + }, + }); + } + }, + }); + // Close folio manually for Folio type master or desk + if (frm.doc.type !== "Guest") { + frm.page.add_menu_item(__("Close Folio"), function () { + if (frm.doc.balance !== 0) { + frappe.msgprint( + "Balance is not 0. There are still transactions needed to be resolved." + ); + } else { + close_folio(frm); + } + }); + } + } + toggle_guest_in_type(frm, 0); + // Show Reservation Button + if (frm.doc.reservation_id !== undefined) { + frm.add_custom_button(__("Show Reservation"), function () { + let url = frappe.urllib.get_full_url( + "/app/inn-reservation/" + frm.doc.reservation_id + ); + if (is_check_in === "true") { + url = url + "?is_check_in=true"; + } + var w = window.open(url, "_self"); + }); + } + // Update Balance Button + if (frm.doc.status !== "Cancel") { + frm.add_custom_button(__("Update Balance"), function () { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio.inn_folio.need_to_update_balance", + args: { + folio_id: frm.doc.name, + }, + callback: (r) => { + if (r.message === 1) { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio.inn_folio.update_balance", + args: { + folio_id: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + frappe.show_alert("Balance updated."); + frm.doc.total_debit = r.message[0]; + frm.doc.total_credit = r.message[1]; + frm.doc.balance = r.message[2]; + frm.refresh_field("total_debit"); + frm.refresh_field("total_credit"); + frm.refresh_field("balance"); + } + }, + }); + } else { + frappe.show_alert("Balance already updated."); + } + }, + }); + }); + } + } else { + toggle_visibility_buttons(frm, 1); + toggle_guest_in_type(frm, 1); + } + }, + close: function (frm) { + if (frm.doc.type != "Desk") { + if (frm.doc.close < frm.doc.open) { + frm.set_value("close", null); + frappe.msgprint("Close Date must be greater than Open Date"); + } + } + }, }); -frappe.ui.form.on('Inn Folio Transaction', { - void_transaction: function (frm, cdt, cdn) { - let child = locals[cdt][cdn]; - void_transaction(child); - } +frappe.ui.form.on("Inn Folio Transaction", { + void_transaction: function (frm, cdt, cdn) { + let child = locals[cdt][cdn]; + void_transaction(child); + }, }); // Function to extract variable's value passed on URL function getUrlVars() { - var vars = {}; - var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { - vars[key] = value; - }); - return vars; + var vars = {}; + var parts = window.location.href.replace( + /[?&]+([^=&]+)=([^&]*)/gi, + function (m, key, value) { + vars[key] = value; + } + ); + return vars; } // Function to make form disabled if status cancel function make_read_only(frm) { - let active_flag = 0; - if (frm.doc.status !== 'Open') { - active_flag = 1; - } - else { - active_flag = 0; - } - - frm.set_df_property('sb4', 'hidden', active_flag); - frm.set_df_property('transfer_to_another_folio', 'hidden', active_flag); - frm.set_df_property('open', 'read_only', active_flag); - frm.set_df_property('close', 'read_only', active_flag); - frm.set_df_property('reservation_id', 'read_only', active_flag); - frm.set_df_property('customer_id', 'read_only', active_flag); - frm.set_df_property('type', 'read_only', active_flag); - frm.set_df_property('group_id', 'read_only', active_flag); + let active_flag = 0; + if (frm.doc.status !== "Open") { + active_flag = 1; + } else { + active_flag = 0; + } - frappe.meta.get_docfield('Inn Folio Transaction', 'void_transaction', frm.doc.name).hidden = active_flag; - frappe.meta.get_docfield('Inn Folio Transaction', 'flag', frm.doc.name).read_only = active_flag; - frappe.meta.get_docfield('Inn Folio Transaction', 'transaction_type', frm.doc.name).read_only = active_flag; - frappe.meta.get_docfield('Inn Folio Transaction', 'amount', frm.doc.name).read_only = active_flag; - frappe.meta.get_docfield('Inn Folio Transaction', 'debit_account', frm.doc.name).read_only = active_flag; - frappe.meta.get_docfield('Inn Folio Transaction', 'credit_account', frm.doc.name).read_only = active_flag; - frappe.meta.get_docfield('Inn Folio Transaction', 'remark', frm.doc.name).read_only = active_flag; + frm.set_df_property("sb4", "hidden", active_flag); + frm.set_df_property("transfer_to_another_folio", "hidden", active_flag); + frm.set_df_property("open", "read_only", active_flag); + frm.set_df_property("close", "read_only", active_flag); + frm.set_df_property("reservation_id", "read_only", active_flag); + frm.set_df_property("customer_id", "read_only", active_flag); + frm.set_df_property("type", "read_only", active_flag); + frm.set_df_property("group_id", "read_only", active_flag); + frappe.meta.get_docfield( + "Inn Folio Transaction", + "void_transaction", + frm.doc.name + ).hidden = active_flag; + frappe.meta.get_docfield( + "Inn Folio Transaction", + "flag", + frm.doc.name + ).read_only = active_flag; + frappe.meta.get_docfield( + "Inn Folio Transaction", + "transaction_type", + frm.doc.name + ).read_only = active_flag; + frappe.meta.get_docfield( + "Inn Folio Transaction", + "amount", + frm.doc.name + ).read_only = active_flag; + frappe.meta.get_docfield( + "Inn Folio Transaction", + "debit_account", + frm.doc.name + ).read_only = active_flag; + frappe.meta.get_docfield( + "Inn Folio Transaction", + "credit_account", + frm.doc.name + ).read_only = active_flag; + frappe.meta.get_docfield( + "Inn Folio Transaction", + "remark", + frm.doc.name + ).read_only = active_flag; } // Function to toggle visibility of buttons when necessary function toggle_visibility_buttons(frm, active_flag) { - frm.set_df_property('sb4', 'hidden', active_flag); - frm.set_df_property('transfer_to_another_folio', 'hidden', active_flag); + frm.set_df_property("sb4", "hidden", active_flag); + frm.set_df_property("transfer_to_another_folio", "hidden", active_flag); } // Function to toggle visibility of Guest options in Type function toggle_guest_in_type(frm, is_new) { - if (is_new === 1) { - frm.set_df_property('type', 'options', ['Master', 'Desk']); - frm.set_value('type', 'Master'); - } - else { - if (frm.doc.type === 'Guest') { - frm.set_df_property('type', 'read_only', 1); - frm.set_df_property('type', 'options', ['Guest', 'Master', 'Desk']); - } - else { - frm.set_df_property('type', 'options', ['Master', 'Desk']); - } - } - frm.refresh_field('type'); + if (is_new === 1) { + frm.set_df_property("type", "options", ["Master", "Desk"]); + frm.set_value("type", "Master"); + } else { + if (frm.doc.type === "Guest") { + frm.set_df_property("type", "read_only", 1); + frm.set_df_property("type", "options", ["Guest", "Master", "Desk"]); + } else { + frm.set_df_property("type", "options", ["Master", "Desk"]); + } + } + frm.refresh_field("type"); } // Function to show pop up Dialof for adding new package to the folio function add_package(frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_package.inn_package.get_package_list', - args: { - active_flag: 1 - }, - callback: (r) => { - let fields = [ - { - 'label': __('Package Name'), - 'fieldname': 'package_name', - 'fieldtype': 'Select', - 'options': r.message, - 'reqd': 1 - }, - { - 'label': __('Sub Folio'), - 'fieldname': 'sub_folio', - 'fieldtype': 'Select', - 'options': [ - {'label': __('A'), 'value': 'A'}, {'label': __('B'), 'value': 'B'}, - {'label': __('C'), 'value': 'C'}, {'label': __('D'), 'value': 'D'} - ], - 'default': 'A', - 'reqd':1 - }, - { - 'label': 'Remark', - 'fieldname': 'remark', - 'fieldtype': 'Small Text', - }, - ]; - var d = new frappe.ui.Dialog({ - title: __('Add New Package for Folio ' + frm.doc.name), - fields: fields, - }); - d.set_primary_action(__('Save'), () => { - let remark_to_save = d.get_values().package_name + '.\n'; - if (d.get_values().remark !== undefined || d.get_values().remark != null) { - remark_to_save += d.get_values().remark; - } - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_package_charge', - args: { - package_name: d.get_values().package_name, - sub_folio: d.get_values().sub_folio, - remark: remark_to_save, - parent: frm.doc.name - }, - callback: (r) => { - if (r.message) { - frappe.msgprint('Charge with ID ' + r.message + " successfully added"); - frm.reload_doc(); - } - } - }); - d.hide(); - }); - d.show(); - } - }); + frappe.call({ + method: "inn.inn_hotels.doctype.inn_package.inn_package.get_package_list", + args: { + active_flag: 1, + }, + callback: (r) => { + let fields = [ + { + label: __("Package Name"), + fieldname: "package_name", + fieldtype: "Select", + options: r.message, + reqd: 1, + }, + { + label: __("Sub Folio"), + fieldname: "sub_folio", + fieldtype: "Select", + options: [ + { label: __("A"), value: "A" }, + { label: __("B"), value: "B" }, + { label: __("C"), value: "C" }, + { label: __("D"), value: "D" }, + ], + default: "A", + reqd: 1, + }, + { + label: "Remark", + fieldname: "remark", + fieldtype: "Small Text", + }, + ]; + var d = new frappe.ui.Dialog({ + title: __("Add New Package for Folio " + frm.doc.name), + fields: fields, + }); + d.set_primary_action(__("Save"), () => { + let remark_to_save = d.get_values().package_name + ".\n"; + if ( + d.get_values().remark !== undefined || + d.get_values().remark != null + ) { + remark_to_save += d.get_values().remark; + } + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_package_charge", + args: { + package_name: d.get_values().package_name, + sub_folio: d.get_values().sub_folio, + remark: remark_to_save, + parent: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + frappe.msgprint( + "Charge with ID " + r.message + " successfully added" + ); + frm.reload_doc(); + } + }, + }); + d.hide(); + }); + d.show(); + }, + }); } // Function to show pop up Dialog for adding new charge to the folio function add_charge(frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_transaction_type', - args: { - type: 'Debit' - }, - callback: (r)=> { - let fields = [ - { - 'label': __('Transaction Type'), - 'fieldname': 'transaction_type', - 'fieldtype': 'Select', - 'options': r.message, - 'reqd': 1 - }, - { - 'fieldname': 'accb0', - 'fieldtype': 'Column Break' - }, - { - 'label': __('Amount'), - 'fieldname': 'amount', - 'fieldtype': 'Currency', - 'columns': 2, - 'reqd': 1 - }, - { - 'fieldname': 'accb1', - 'fieldtype': 'Column Break' - }, - { - 'label': __('Sub Folio'), - 'fieldname': 'sub_folio', - 'fieldtype': 'Select', - 'options': [ - {'label': __('A'), 'value': 'A'}, {'label': __('B'), 'value': 'B'}, - {'label': __('C'), 'value': 'C'}, {'label': __('D'), 'value': 'D'} - ], - 'default': 'A', - 'reqd':1 - }, - { - 'fieldname': 'acsb0', - 'fieldtype': 'Section Break' - }, - { - 'label': 'Remark', - 'fieldname': 'remark', - 'fieldtype': 'Small Text', - }, - ]; - var d = new frappe.ui.Dialog({ - title: __('Add New Charge for Folio ' + frm.doc.name), - fields: fields, - }); - d.set_primary_action(__('Save'), () => { - let remark_to_save = ''; - let values = d.get_values() - if (values.amount == 0) { - frappe.msgprint({ - title: __("Validation Error"), - indicator: "red", - message: __("Amount cannot be zero") - }) - return - } + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_transaction_type", + args: { + type: "Debit", + }, + callback: (r) => { + let fields = [ + { + label: __("Transaction Type"), + fieldname: "transaction_type", + fieldtype: "Select", + options: r.message, + reqd: 1, + }, + { + fieldname: "accb0", + fieldtype: "Column Break", + }, + { + label: __("Amount"), + fieldname: "amount", + fieldtype: "Currency", + columns: 2, + reqd: 1, + }, + { + fieldname: "accb1", + fieldtype: "Column Break", + }, + { + label: __("Sub Folio"), + fieldname: "sub_folio", + fieldtype: "Select", + options: [ + { label: __("A"), value: "A" }, + { label: __("B"), value: "B" }, + { label: __("C"), value: "C" }, + { label: __("D"), value: "D" }, + ], + default: "A", + reqd: 1, + }, + { + fieldname: "acsb0", + fieldtype: "Section Break", + }, + { + label: "Remark", + fieldname: "remark", + fieldtype: "Small Text", + }, + ]; + var d = new frappe.ui.Dialog({ + title: __("Add New Charge for Folio " + frm.doc.name), + fields: fields, + }); + d.set_primary_action(__("Save"), () => { + let remark_to_save = ""; + let values = d.get_values(); + if (values.amount == 0) { + frappe.msgprint({ + title: __("Validation Error"), + indicator: "red", + message: __("Amount cannot be zero"), + }); + return; + } - if (d.get_values().remark !== undefined || d.get_values().remark != null) { - remark_to_save = d.get_values().remark; - } - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_charge', - args: { - transaction_type: d.get_values().transaction_type, - amount: d.get_values().amount, - sub_folio: d.get_values().sub_folio, - remark: remark_to_save, - parent: frm.doc.name - }, - callback: (r) => { - if (r.message) { - frappe.msgprint('Charge with ID ' + r.message + " successfully added"); - frm.reload_doc(); - } - } - }); - d.hide(); - }); - d.show(); - } - }); + if ( + d.get_values().remark !== undefined || + d.get_values().remark != null + ) { + remark_to_save = d.get_values().remark; + } + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_charge", + args: { + transaction_type: d.get_values().transaction_type, + amount: d.get_values().amount, + sub_folio: d.get_values().sub_folio, + remark: remark_to_save, + parent: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + frappe.msgprint( + "Charge with ID " + r.message + " successfully added" + ); + frm.reload_doc(); + } + }, + }); + d.hide(); + }); + d.show(); + }, + }); } // Function to show pop up Dialog for adding new payment to the folio function add_payment(frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_transaction_type', - args: { - type: 'Credit' - }, - callback: (r)=> { - let fields = [ - { - 'label': __('Transaction Type'), - 'fieldname': 'transaction_type', - 'fieldtype': 'Select', - 'options': r.message, - 'reqd': 1 - }, - { - 'fieldname': 'accb0', - 'fieldtype': 'Column Break' - }, - { - 'label': __('Amount'), - 'fieldname': 'amount', - 'fieldtype': 'Currency', - 'columns': 2, - 'reqd': 1 - }, - { - 'fieldname': 'acsb0', - 'fieldtype': 'Section Break' - }, - { - 'label': __('Mode of Payment'), - 'fieldname': 'mode_of_payment', - 'fieldtype': 'Link', - 'options': 'Mode of Payment', - 'reqd': 1 - }, - { - 'fieldname': 'accb1', - 'fieldtype': 'Column Break' - }, - { - 'label': __('Sub Folio'), - 'fieldname': 'sub_folio', - 'fieldtype': 'Select', - 'options': [ - {'label': __('A'), 'value': 'A'}, {'label': __('B'), 'value': 'B'}, - {'label': __('C'), 'value': 'C'}, {'label': __('D'), 'value': 'D'} - ], - 'default': 'A', - 'reqd':1 - }, - { - 'fieldname': 'acsb1', - 'fieldtype': 'Section Break' - }, - { - 'label': 'Remark', - 'fieldname': 'remark', - 'fieldtype': 'Small Text', - }, - ]; - var d = new frappe.ui.Dialog({ - title: __('Add New Payment for Folio ' + frm.doc.name), - fields: fields, - }); - d.set_primary_action(__('Save'), () => { - let remark_to_save = ''; + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_transaction_type", + args: { + type: "Credit", + }, + callback: (r) => { + let fields = [ + { + label: __("Transaction Type"), + fieldname: "transaction_type", + fieldtype: "Select", + options: r.message, + reqd: 1, + }, + { + fieldname: "accb0", + fieldtype: "Column Break", + }, + { + label: __("Amount"), + fieldname: "amount", + fieldtype: "Currency", + columns: 2, + reqd: 1, + }, + { + fieldname: "acsb0", + fieldtype: "Section Break", + }, + { + label: __("Mode of Payment"), + fieldname: "mode_of_payment", + fieldtype: "Link", + options: "Mode of Payment", + reqd: 1, + }, + { + fieldname: "accb1", + fieldtype: "Column Break", + }, + { + label: __("Sub Folio"), + fieldname: "sub_folio", + fieldtype: "Select", + options: [ + { label: __("A"), value: "A" }, + { label: __("B"), value: "B" }, + { label: __("C"), value: "C" }, + { label: __("D"), value: "D" }, + ], + default: "A", + reqd: 1, + }, + { + fieldname: "acsb1", + fieldtype: "Section Break", + }, + { + label: "Remark", + fieldname: "remark", + fieldtype: "Small Text", + }, + ]; + var d = new frappe.ui.Dialog({ + title: __("Add New Payment for Folio " + frm.doc.name), + fields: fields, + }); + d.set_primary_action(__("Save"), () => { + let remark_to_save = ""; - let values = d.get_values() - if (values.amount == 0) { - frappe.msgprint({ - title: __("Validation Error"), - indicator: "red", - message: __("Amount cannot be zero") - }) - return - } + let values = d.get_values(); + if (values.amount == 0) { + frappe.msgprint({ + title: __("Validation Error"), + indicator: "red", + message: __("Amount cannot be zero"), + }); + return; + } - if (d.get_values.remark !== undefined) { - remark_to_save = d.get_values.remark; - } - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_payment', - args: { - transaction_type: d.get_values().transaction_type, - amount: d.get_values().amount, - mode_of_payment: d.get_values().mode_of_payment, - sub_folio: d.get_values().sub_folio, - remark: remark_to_save, - parent: frm.doc.name - }, - callback: (r) => { - if (r.message) { - frappe.msgprint('Payment with ID ' + r.message + " successfully added"); - frm.reload_doc(); - } - } - }); - d.hide(); - }); - d.show(); - } - }); + if (d.get_values.remark !== undefined) { + remark_to_save = d.get_values.remark; + } + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_payment", + args: { + transaction_type: d.get_values().transaction_type, + amount: d.get_values().amount, + mode_of_payment: d.get_values().mode_of_payment, + sub_folio: d.get_values().sub_folio, + remark: remark_to_save, + parent: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + frappe.msgprint( + "Payment with ID " + r.message + " successfully added" + ); + frm.reload_doc(); + } + }, + }); + d.hide(); + }); + d.show(); + }, + }); } // Function to show pop up Dialog for Adding Refund to folio function add_refund(frm) { - var d = new frappe.ui.Dialog({ - title: __('Add New Refund to Folio ' + frm.doc.name), - fields: [ - { - 'label': __('Amount'), - 'fieldname': 'amount', - 'fieldtype': 'Currency', - 'columns': 2, - 'reqd': 1 - }, - { - 'fieldname': 'arcb0', - 'fieldtype': 'Column Break' - }, - { - 'label': __('Sub Folio'), - 'fieldname': 'sub_folio', - 'fieldtype': 'Select', - 'options': [ - {'label': __('A'), 'value': 'A'}, {'label': __('B'), 'value': 'B'}, - {'label': __('C'), 'value': 'C'}, {'label': __('D'), 'value': 'D'} - ], - 'default': 'A', - 'reqd':1 - }, - { - 'fieldname': 'arsb0', - 'fieldtype': 'Section Break' - }, - { - 'label': 'Remark', - 'fieldname': 'remark', - 'fieldtype': 'Small Text', - }, - ] - }); - if (frm.doc.balance > 0) { - d.set_value('amount', frm.doc.balance); - } - d.set_primary_action(__('Save'), () => { - let remark_to_save = ''; + var d = new frappe.ui.Dialog({ + title: __("Add New Refund to Folio " + frm.doc.name), + fields: [ + { + label: __("Amount"), + fieldname: "amount", + fieldtype: "Currency", + columns: 2, + reqd: 1, + }, + { + fieldname: "arcb0", + fieldtype: "Column Break", + }, + { + label: __("Sub Folio"), + fieldname: "sub_folio", + fieldtype: "Select", + options: [ + { label: __("A"), value: "A" }, + { label: __("B"), value: "B" }, + { label: __("C"), value: "C" }, + { label: __("D"), value: "D" }, + ], + default: "A", + reqd: 1, + }, + { + fieldname: "arsb0", + fieldtype: "Section Break", + }, + { + label: "Remark", + fieldname: "remark", + fieldtype: "Small Text", + }, + ], + }); + if (frm.doc.balance > 0) { + d.set_value("amount", frm.doc.balance); + } + d.set_primary_action(__("Save"), () => { + let remark_to_save = ""; - let values = d.get_values() - if (values.amount == 0) { - frappe.msgprint({ - title: __("Validation Error"), - indicator: "red", - message: __("Amount cannot be zero") - }) - return - } - if (d.get_values.remark !== undefined) { - remark_to_save = d.get_values.remark; - } - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_charge', - args: { - transaction_type: 'Refund', - amount: d.get_values().amount, - sub_folio: d.get_values().sub_folio, - remark: remark_to_save, - parent: frm.doc.name - }, - callback: (r) => { - if (r.message) { - frappe.msgprint('Refund with ID ' + r.message + " successfully added"); - frm.reload_doc(); - } - } - }); - d.hide(); - }); - d.show(); + let values = d.get_values(); + if (values.amount == 0) { + frappe.msgprint({ + title: __("Validation Error"), + indicator: "red", + message: __("Amount cannot be zero"), + }); + return; + } + if (d.get_values.remark !== undefined) { + remark_to_save = d.get_values.remark; + } + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_charge", + args: { + transaction_type: "Refund", + amount: d.get_values().amount, + sub_folio: d.get_values().sub_folio, + remark: remark_to_save, + parent: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + frappe.msgprint( + "Refund with ID " + r.message + " successfully added" + ); + frm.reload_doc(); + } + }, + }); + d.hide(); + }); + d.show(); } // Function to show pop up Dialog for transferring transaction selected to another folio function transfer_to_another_folio(frm, trx_selected) { - var d = new frappe.ui.Dialog({ - title: __('Transfer Transactions to Another Folio'), - fields: [ - { - 'label': 'Transfer to Folio: ', - 'fieldname': 'receiving_folio', - 'fieldtype': 'Link', - 'options': 'Inn Folio', - 'get_query': function () { - return { - filters: [ - ['Inn Folio', 'name', '!=', frm.doc.name], - ['Inn Folio', 'status', '=', 'Open'], - ] - } - }, - reqd: 1 - }, - ] - }); - d.set_primary_action(__('Transfer'), () => { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio.inn_folio.transfer_to_another_folio', - args: { - trx_list: trx_selected, - old_parent: frm.doc.name, - new_parent: d.get_values().receiving_folio, - }, - callback: (r) => { - if (r.message === 0) { - frappe.msgprint('Transactions transfered to Folio ' + d.get_values().receiving_folio + ' successfully'); - frm.reload_doc(); - } - } - }); - d.hide(); - }); - d.show(); + var d = new frappe.ui.Dialog({ + title: __("Transfer Transactions to Another Folio"), + fields: [ + { + label: "Transfer to Folio: ", + fieldname: "receiving_folio", + fieldtype: "Link", + options: "Inn Folio", + get_query: function () { + return { + filters: [ + ["Inn Folio", "name", "!=", frm.doc.name], + ["Inn Folio", "status", "=", "Open"], + ], + }; + }, + reqd: 1, + }, + ], + }); + d.set_primary_action(__("Transfer"), () => { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio.inn_folio.transfer_to_another_folio", + args: { + trx_list: trx_selected, + old_parent: frm.doc.name, + new_parent: d.get_values().receiving_folio, + }, + callback: (r) => { + if (r.message === 0) { + frappe.msgprint( + "Transactions transfered to Folio " + + d.get_values().receiving_folio + + " successfully" + ); + frm.reload_doc(); + } + }, + }); + d.hide(); + }); + d.show(); } // Function to void single folio transaction function void_transaction(child) { - // frappe.confirm(__("You are about to void this transaction. Are you sure?"), function () { - // if (child.is_void === 0) { - // child.is_void = 1; - // cur_frm.save(); - // frappe.show_alert('Transaction with ID ' + child.name + ' voided successfully.'); - // } - // else { - // frappe.msgprint("This transaction already voided."); - // } - // }); - if (child.is_void === 0) { - if (!child.journal_entry_id) { - if (child.void_id) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_void_folio_transaction.inn_void_folio_transaction.request_status', - args: { - id: child.void_id - }, - callback: (r) => { - if (r.message == 'Requested') { - frappe.msgprint("This transaction already requested to be voided. Please wait for supervisor approval."); - } - else if (r.message == 'Denied') { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction_bundle.inn_folio_transaction_bundle.get_trx_list', - args: { - trx_id: child.name, - len_only: true - }, - callback: (resp) => { - if (resp.message) { - void_window(child, resp.message); - } - } - }); - } - } - }); - } - else { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction_bundle.inn_folio_transaction_bundle.get_trx_list', - args: { - trx_id: child.name, - len_only: true - }, - callback: (resp) => { - if (resp.message) { - void_window(child, resp.message); - } - } - }); - } - } else { - frappe.msgprint("Cannot void this transaction anymore, because this transaction has been inputted to Journal."); - } - - - } - else { - frappe.msgprint("This transaction already voided."); - } + // frappe.confirm(__("You are about to void this transaction. Are you sure?"), function () { + // if (child.is_void === 0) { + // child.is_void = 1; + // cur_frm.save(); + // frappe.show_alert('Transaction with ID ' + child.name + ' voided successfully.'); + // } + // else { + // frappe.msgprint("This transaction already voided."); + // } + // }); + if (child.is_void === 0) { + if (!child.journal_entry_id) { + if (child.void_id) { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_void_folio_transaction.inn_void_folio_transaction.request_status", + args: { + id: child.void_id, + }, + callback: (r) => { + if (r.message == "Requested") { + frappe.msgprint( + "This transaction already requested to be voided. Please wait for supervisor approval." + ); + } else if (r.message == "Denied") { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction_bundle.inn_folio_transaction_bundle.get_trx_list", + args: { + trx_id: child.name, + len_only: true, + }, + callback: (resp) => { + if (resp.message) { + void_window(child, resp.message); + } + }, + }); + } + }, + }); + } else { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction_bundle.inn_folio_transaction_bundle.get_trx_list", + args: { + trx_id: child.name, + len_only: true, + }, + callback: (resp) => { + if (resp.message) { + void_window(child, resp.message); + } + }, + }); + } + } else { + frappe.msgprint( + "Cannot void this transaction anymore, because this transaction has been inputted to Journal." + ); + } + } else { + frappe.msgprint("This transaction already voided."); + } } function void_window(child, bundle_len) { - let fields = []; - let default_fields= [ - { - 'label': 'Use Passcode', - 'fieldname': 'use_passcode', - 'fieldtype': 'Check', - "description": "Check if you have Supervisor Passcode to bypass the Approval Void Request by Supervisor Process", - }, - { - 'label': 'Supervisor Passcode', - 'fieldname': 'supervisor_passcode', - 'fieldtype': 'Data', - 'depends_on': 'eval:doc.use_passcode==1' - }, - { - 'label': 'Void Reason', - 'fieldname': 'applicant_reason', - 'fieldtype': 'Small Text', - 'reqd': 1 - }, - ]; - let info_field = { - 'label': 'Info:', - 'fieldname': 'Info', - 'fieldtype': 'Small Text', - 'default': 'This transaction is a part of a bundle of transaction that consist of multiple transactions.
    ' + - 'By voiding this transaction, the other transactions in the bundle will also be voided for data integrity purposes.', - 'read_only': 1 - }; - if (parseInt(bundle_len) > 1) { - fields = [info_field].concat(default_fields); - } - else { - fields = default_fields; - } - var d = new frappe.ui.Dialog({ - title: __('Request Void Transaction ' + child.name), - fields: fields - }); - d.set_primary_action(__('Request Void'), () => { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.void_transaction', - args: { - trx_id: child.name, - use_passcode: d.get_values().use_passcode, - applicant_reason: d.get_values().applicant_reason, - requester: frappe.session.user, - bundle_len: bundle_len, - supervisor_passcode: d.get_values().supervisor_passcode - }, - callback: (r) => { - if (r.message == 0) { - d.hide(); - frappe.msgprint('Transaction with ID ' + child.name + ' voided successfully. Please Reload the Page'); - } - else if (r.message == 2) { - d.hide(); - frappe.msgprint('Request to Void Transaction with ID ' + child.name + ' successfully submitted. ' + - 'Wait for Supervisor approval to finish void process. Please Reload the Page'); - } - } - }); - }); - d.show(); + let fields = []; + let default_fields = [ + { + label: "Use Passcode", + fieldname: "use_passcode", + fieldtype: "Check", + description: + "Check if you have Supervisor Passcode to bypass the Approval Void Request by Supervisor Process", + }, + { + label: "Supervisor Passcode", + fieldname: "supervisor_passcode", + fieldtype: "Data", + depends_on: "eval:doc.use_passcode==1", + }, + { + label: "Void Reason", + fieldname: "applicant_reason", + fieldtype: "Small Text", + reqd: 1, + }, + ]; + let info_field = { + label: "Info:", + fieldname: "Info", + fieldtype: "Small Text", + default: + "This transaction is a part of a bundle of transaction that consist of multiple transactions.
    " + + "By voiding this transaction, the other transactions in the bundle will also be voided for data integrity purposes.", + read_only: 1, + }; + if (parseInt(bundle_len) > 1) { + fields = [info_field].concat(default_fields); + } else { + fields = default_fields; + } + var d = new frappe.ui.Dialog({ + title: __("Request Void Transaction " + child.name), + fields: fields, + }); + d.set_primary_action(__("Request Void"), () => { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.void_transaction", + args: { + trx_id: child.name, + use_passcode: d.get_values().use_passcode, + applicant_reason: d.get_values().applicant_reason, + requester: frappe.session.user, + bundle_len: bundle_len, + supervisor_passcode: d.get_values().supervisor_passcode, + }, + callback: (r) => { + if (r.message == 0) { + d.hide(); + frappe.msgprint( + "Transaction with ID " + + child.name + + " voided successfully. Please Reload the Page" + ); + } else if (r.message == 2) { + d.hide(); + frappe.msgprint( + "Request to Void Transaction with ID " + + child.name + + " successfully submitted. " + + "Wait for Supervisor approval to finish void process. Please Reload the Page" + ); + } + }, + }); + }); + d.show(); } // Function to manually close folio function close_folio(frm) { - frappe.confirm(__("You are about to Close this Folio. Are you sure?"), function () { - frappe.call({ - method:'inn.inn_hotels.doctype.inn_folio.inn_folio.close_folio', - args: { - folio_id: frm.doc.name - }, - callback: (r) => { - if (r.message === 'Closed') { - frappe.show_alert("Folio Closed successfully"); - } - else { - frappe.msgprint(r.message); - } - } - }); - }); + frappe.confirm( + __("You are about to Close this Folio. Are you sure?"), + function () { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_folio.inn_folio.close_folio", + args: { + folio_id: frm.doc.name, + }, + callback: (r) => { + if (r.message === "Closed") { + frappe.show_alert("Folio Closed successfully"); + } else { + frappe.msgprint(r.message); + } + }, + }); + } + ); } // Function to showing voided transaction function show_void(item, index) { - if(item.is_void === 1) { - $('[data-name='+item.name+']').show(); - } + if (item.is_void === 1) { + $("[data-name=" + item.name + "]").show(); + } } // Function to hiding voided transaction function hide_void(item, index) { - if(item.is_void === 1) { - $('[data-name='+item.name+']').hide(); - } + if (item.is_void === 1) { + $("[data-name=" + item.name + "]").hide(); + } } // Function to make mandatory certain number of fields function make_mandatory(frm) { - if (frm.doc.type != 'Guest') { - if (frm.doc.group_id == undefined || frm.doc.group_id == null) { - console.log("masuk sini"); - frappe.validated = false; - frappe.msgprint("The Group field cannot be empty if folio type is " + frm.doc.type); - } - } -} \ No newline at end of file + if (frm.doc.type != "Guest") { + if (frm.doc.group_id == undefined || frm.doc.group_id == null) { + console.log("masuk sini"); + frappe.validated = false; + frappe.msgprint( + "The Group field cannot be empty if folio type is " + frm.doc.type + ); + } + } +} + +// Function to make the fields filtered +function make_fields_filtered(frm) { + const field_filters = { + debit_account: { is_group: 0 }, + credit_account: { is_group: 0 }, + }; + + // Loop through fields and apply filters + for (const [fieldname, filters] of Object.entries(field_filters)) { + frm.set_query(fieldname, "folio_transaction", function () { + return { filters: filters }; + }); + } +} diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index f7334597..a0929d3f 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -104,7 +104,10 @@ "room_service_food", "room_service_beverage", "restaurant_other", - "restaurant_beverages" + "restaurant_beverages", + "section_break_kkcy", + "ar_city_ledger_invoice_payment_account", + "column_break_wphq" ], "fields": [ { @@ -510,7 +513,7 @@ { "fieldname": "folio_default_tab", "fieldtype": "Tab Break", - "label": "Folio Default" + "label": "Hotel Default" }, { "fieldname": "credit_card_administration_fee", @@ -690,11 +693,26 @@ "fieldname": "include_tax", "fieldtype": "Check", "label": "Include Tax" + }, + { + "fieldname": "section_break_kkcy", + "fieldtype": "Section Break", + "label": "Default Accounts" + }, + { + "fieldname": "ar_city_ledger_invoice_payment_account", + "fieldtype": "Link", + "label": "AR City Ledger Invoice Payment Account", + "options": "Account" + }, + { + "fieldname": "column_break_wphq", + "fieldtype": "Column Break" } ], "issingle": 1, "links": [], - "modified": "2025-01-26 10:35:16.814025", + "modified": "2025-01-26 13:02:20.416368", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py index 6e1aeac3..6ab76fda 100644 --- a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py +++ b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py @@ -528,12 +528,14 @@ def post_room_charges(parent_id, tobe_posted_list): } if hotel_settings.include_tax: transaction_types["room_charge_tax_service"] = ( - hotel_settings.room_charge_tax_service, + hotel_settings.room_charge_tax_service ) + transaction_types["breakfast_charge_tax_service"] = ( - hotel_settings.breakfast_charge_tax_service, + hotel_settings.breakfast_charge_tax_service ) - transaction_types["fbs_tax_11"] = (hotel_settings.fbs_tax_11,) + + transaction_types["fbs_tax_11"] = hotel_settings.fbs_tax_11 # to exclude service charge from reduced because of commision / cashback room_post_settings = frappe.db.get_values_from_single( From bf13548ee6e87078d48abbbccec4a6ad803c2387 Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Sun, 26 Jan 2025 13:11:03 +0200 Subject: [PATCH 09/22] [Fix]: Removed Logs --- .../doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js | 1 - 1 file changed, 1 deletion(-) diff --git a/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js b/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js index 24936dc8..8c43c9d2 100644 --- a/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js +++ b/inn/inn_hotels/doctype/ar_city_ledger_invoice/ar_city_ledger_invoice.js @@ -100,7 +100,6 @@ function filter_folio(frm) { }, callback: (r) => { if (r.message) { - console.log(r); field.get_query = function () { return { filters: [["Inn Folio", "name", "in", r.message]], From 602aa289cb9e5472ad6b581cfb4b76bc129bb0c5 Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Tue, 28 Jan 2025 14:17:02 +0200 Subject: [PATCH 10/22] [Fix]: Some Errors --- inn/__init__.py | 2 +- .../doctype/inn_floor_plan/inn_floor_plan.js | 218 +- .../inn_hotels_setting.json | 57 +- .../inn_reservation/inn_reservation.js | 2838 +++++++++-------- inn/inn_hotels/doctype/inn_room/inn_room.py | 376 ++- 5 files changed, 1940 insertions(+), 1551 deletions(-) diff --git a/inn/__init__.py b/inn/__init__.py index a20ee89b..d268aa9e 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = "1.1.4" +__version__ = "1.1.5" diff --git a/inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js b/inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js index 9ce46102..1c26460b 100644 --- a/inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js +++ b/inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js @@ -1,12 +1,13 @@ // Copyright (c) 2020, Core Initiative and contributors // For license information, please see license.txt -frappe.ui.form.on('Inn Floor Plan', { - refresh: function(frm) { - var wrapper = frm.get_field("html").$wrapper; +frappe.ui.form.on("Inn Floor Plan", { + refresh: function (frm) { + var wrapper = frm.get_field("html").$wrapper; - var head = '' + - '\ + var head = + "" + + '\ \ \ '; - var body = '' + - '\ + var body = + "" + + '\ '; - wrapper.html(wrapper.html() + information); - } + wrapper.html(wrapper.html() + information); + }, }); diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index a0929d3f..0d9587f3 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -107,7 +107,15 @@ "restaurant_beverages", "section_break_kkcy", "ar_city_ledger_invoice_payment_account", - "column_break_wphq" + "column_break_wphq", + "default_roles_section", + "housekeeping_supervisor", + "housekeeping", + "housekeeping_assistant", + "column_break_dynj", + "booking_approver", + "restaurant_user", + "restaurant_supervisor" ], "fields": [ { @@ -708,11 +716,56 @@ { "fieldname": "column_break_wphq", "fieldtype": "Column Break" + }, + { + "fieldname": "housekeeping", + "fieldtype": "Link", + "label": "Housekeeping", + "options": "Role" + }, + { + "fieldname": "housekeeping_assistant", + "fieldtype": "Link", + "label": "Housekeeping Assistant", + "options": "Role" + }, + { + "fieldname": "restaurant_user", + "fieldtype": "Link", + "label": "Restaurant User", + "options": "Role" + }, + { + "fieldname": "restaurant_supervisor", + "fieldtype": "Link", + "label": "Restaurant Supervisor", + "options": "Role" + }, + { + "fieldname": "housekeeping_supervisor", + "fieldtype": "Link", + "label": "Housekeeping Supervisor", + "options": "Role" + }, + { + "fieldname": "booking_approver", + "fieldtype": "Link", + "label": "Booking Approver", + "options": "Role" + }, + { + "fieldname": "default_roles_section", + "fieldtype": "Section Break", + "label": "Default Roles" + }, + { + "fieldname": "column_break_dynj", + "fieldtype": "Column Break" } ], "issingle": 1, "links": [], - "modified": "2025-01-26 13:02:20.416368", + "modified": "2025-01-28 11:14:31.420714", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js index a4eb5399..f1aa2be7 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js @@ -1,1408 +1,1644 @@ // Copyright (c) 2020, Core Initiative and contributors // For license information, please see license.txt -let is_check_in = 'false'; +let is_check_in = "false"; let is_form_not_good_to_go = false; let is_error = false; -let error_message = ''; +let error_message = ""; let room_max_active_card = 5; -frappe.ui.form.on('Inn Reservation', { - onload: function (frm) { - get_room_max_active_card(); - make_read_only(frm); +frappe.ui.form.on("Inn Reservation", { + onload: function (frm) { + get_room_max_active_card(); + make_read_only(frm); - if (frm.doc.__islocal != 1) { - handle_filter_on_start_if_filled(frm) - check_is_room_booking_already_created(frm) - } - }, - refresh: function (frm) { - is_check_in = getUrlVars()['is_check_in']; - get_room_max_active_card(); - make_read_only(frm); - console.log("is error = " + is_error); - // Hide some variables that not needed to be filled first time Reservation Created - if (frm.doc.__islocal === 1) { - frm.add_custom_button(__('Check Membership Card'), function () { - check_membership_cards(); - }); - console.log("notsaved"); - frm.set_value('status', 'Reserved'); - frm.set_df_property('init_actual_room_rate', 'hidden', 0); - frm.set_df_property('arrival', 'hidden', 1); - frm.set_df_property('departure', 'hidden', 1); - frm.set_df_property('actual_room_rate', 'hidden', 1); - frm.set_df_property('actual_room_id', 'hidden', 1); - frm.set_df_property('sb1', 'hidden', 1); // Actual Room Rate Breakdown Section - frm.set_df_property('sb3', 'hidden', 1); // Issue Card Table Section - frm.set_df_property('sb4', 'hidden', 1); // Issue Card Buttons Section - toggle_room_detail(frm) - } - // Show Folio Button - if (frm.doc.__islocal !== 1) { - frm.add_custom_button(__('Show Folio'), function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.get_folio_url', - args: { - reservation_id: frm.doc.name, - }, - callback: (r) => { - if (r.message) { - let url = r.message; - if (is_check_in == 'true') { - url = r.message + '?is_check_in=true'; - } - var w = window.open(url, "_self"); - if (!w) { - frappe.msgprint(__("Please enable pop-ups")); return; - } - } - } - }); - }); - } - // Reservation is Saved, and status Reserved - if (frm.doc.__islocal !== 1 && frm.doc.status === 'Reserved') { - console.log("is saved"); - // Set all variables that hidden to be shown again - frm.set_df_property('arrival', 'hidden', 0); - frm.set_df_property('departure', 'hidden', 0); - frm.set_df_property('actual_room_id', 'hidden', 0); - frm.set_df_property('wifi_password', 'hidden', 0); - // Still hide actual room rate - frm.set_df_property('actual_room_rate', 'hidden', 1); - frm.set_df_property('init_actual_room_rate', 'hidden', 0); - console.log("is_check_in = " + is_check_in); - // Show Start Check In Process button if is_check_in flag undefined - if (is_check_in === undefined) { - console.log("is_check_in undefined"); - frm.add_custom_button(__("Start Check In Process"), function () { - is_check_in = "true"; - frappe.call({ - method: "inn.inn_hotels.doctype.inn_reservation.inn_reservation.start_check_in", - args: { - source: 'check_in_button', - reservation: frm.doc.name - }, - callback: (r) => { - if (r.message) { - window.open(r.message, "_self"); - frm.reload_doc(); - } - } - }); - }); - } - // Show Info that Check In is In Progress. Meaning button Check In clicked, either from Reservation List or - // from Start Check In Process Button - if (is_check_in === "true") { - frm.set_intro(__("In Progress Checking In Guest")); - // Assign some variables from "Reservation Detail" to "Room Stay" - autofill(frm); - is_form_not_good_to_go = is_form_good_to_in_house(frm); - console.log("is_form_not_good_to_go = " + is_form_not_good_to_go); - console.log("error_message = " + error_message); - if (is_form_not_good_to_go === true && (error_message !== '' || error_message !== 'Please fill these fields before Finishing Check In process:
      ')) { - frm.set_intro(error_message); - } - else { - frm.add_custom_button(__("Finish Check In Process"), function () { - if (frm.doc.__unsaved !== undefined || frm.doc.unsaved == 1) { - frappe.msgprint("The Reservation has been modified and not saved yet. Please click Save before Finishing Check In Process."); - } - else { - is_check_in = "false"; - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.check_in_reservation', - args: { - reservation_id: frm.doc.name - }, - callback: (r) => { - if (r.message === 'In House') { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation', - args: { - reservation_id: frm.doc.name - }, - callback: (r) => { - if (r.message) { - console.log(r.message); - } - } - }); - frappe.set_route('Form', 'Inn Reservation', frm.doc.name); - } - else { - frappe.msgprint(r.message); - } - } - }); - } - }); - // Checking if deposit is made before allow to finish checking in - // frappe.call({ - // method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.allowed_to_in_house', - // args: { - // reservation_id: frm.doc.name - // }, - // callback: (r) => { - // if (r.message === false) { - // frm.set_intro(__("Make Guest Deposit in Folio to continue Check In process.")); - // } - // else if (r.message === true) { - // frm.add_custom_button(__("Finish Check In Process"), function () { - // if (frm.doc.__unsaved !== undefined || frm.doc.unsaved === 1) { - // frappe.msgprint("The Reservation has been modified. Please click Save before Finishing Check In Process."); - // } - // else { - // is_check_in = "false"; - // frappe.call({ - // method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.check_in_reservation', - // args: { - // reservation_id: frm.doc.name - // }, - // callback: (r) => { - // if (r.message === 'In House') { - // frappe.call({ - // method: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation', - // args: { - // reservation_id: frm.doc.name - // }, - // callback: (r) => { - // if (r.message) { - // console.log(r.message); - // } - // } - // }); - // frappe.set_route('Form', 'Inn Reservation', frm.doc.name); - // } - // } - // }); - // } - // }); - // } - // } - // }); - } - } - //Add Cancel Button if Status still Reserved - frm.page.add_menu_item(__('Cancel'), function () { - frappe.confirm(__("You are about to Cancel this Reservation. Are you sure?"), function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.cancel_reservation', - args: { - source: 'cancel_button', - reservation: frm.doc.name, - }, - callback: (r) => { - if (r.message === 1) { - frappe.msgprint("Only Reservation with status Reserved can be cancelled. Please choose other Reservation"); - } - else if (r.message === 0) { - frm.refresh(); - frappe.msgprint("Reservation " + frm.doc.name + " successfully canceled."); - } - } - }); - }); - }); - // Add No Show Button if Status still Reserved - frm.page.add_menu_item(__('No Show'), function () { - frappe.confirm(__("You are about to mark the guest as No Show. Are you Sure?"), function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.no_show_reservation', - args: { - source: 'no_show_button', - reservation: frm.doc.name, - }, - callback: (r) => { - if (r.message === 1) { - frappe.msgprint("Only Reservation with status Reserved can be set to No Show. Please choose other Reservation"); - } - else if (r.message === 0) { - frm.refresh(); - frappe.msgprint("Reservation " + frm.doc.name + " successfully set to No Show."); - } - } - }); - }) - }) - } - if (frm.doc.__islocal !== 1 && frm.doc.status === 'In House') { - /* Control field visibilities */ - frm.set_df_property('init_actual_room_rate', 'hidden', 1); // Initial Actual Room rate - frm.set_df_property('sb3', 'hidden', 0); // Issue Card Table Section - frm.set_df_property('sb4', 'hidden', 0); // Issue Card Buttons Section + if (frm.doc.__islocal != 1) { + handle_filter_on_start_if_filled(frm); + check_is_room_booking_already_created(frm); + } + }, + refresh: function (frm) { + is_check_in = getUrlVars()["is_check_in"]; + get_room_max_active_card(); + make_read_only(frm); + console.log("is error = " + is_error); + // Hide some variables that not needed to be filled first time Reservation Created + if (frm.doc.__islocal === 1) { + frm.add_custom_button(__("Check Membership Card"), function () { + check_membership_cards(); + }); + console.log("notsaved"); + frm.set_value("status", "Reserved"); + frm.set_df_property("init_actual_room_rate", "hidden", 0); + frm.set_df_property("arrival", "hidden", 1); + frm.set_df_property("departure", "hidden", 1); + frm.set_df_property("actual_room_rate", "hidden", 1); + frm.set_df_property("actual_room_id", "hidden", 1); + frm.set_df_property("sb1", "hidden", 1); // Actual Room Rate Breakdown Section + frm.set_df_property("sb3", "hidden", 1); // Issue Card Table Section + frm.set_df_property("sb4", "hidden", 1); // Issue Card Buttons Section + toggle_room_detail(frm); + } + // Show Folio Button + if (frm.doc.__islocal !== 1) { + frm.add_custom_button(__("Show Folio"), function () { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.get_folio_url", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + let url = r.message; + if (is_check_in == "true") { + url = r.message + "?is_check_in=true"; + } + var w = window.open(url, "_self"); + if (!w) { + frappe.msgprint(__("Please enable pop-ups")); + return; + } + } + }, + }); + }); + } + // Reservation is Saved, and status Reserved + if (frm.doc.__islocal !== 1 && frm.doc.status === "Reserved") { + console.log("is saved"); + // Set all variables that hidden to be shown again + frm.set_df_property("arrival", "hidden", 0); + frm.set_df_property("departure", "hidden", 0); + frm.set_df_property("actual_room_id", "hidden", 0); + frm.set_df_property("wifi_password", "hidden", 0); + // Still hide actual room rate + frm.set_df_property("actual_room_rate", "hidden", 1); + frm.set_df_property("init_actual_room_rate", "hidden", 0); + console.log("is_check_in = " + is_check_in); + // Show Start Check In Process button if is_check_in flag undefined + if (is_check_in === undefined) { + console.log("is_check_in undefined"); + frm.add_custom_button(__("Start Check In Process"), function () { + is_check_in = "true"; + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.start_check_in", + args: { + source: "check_in_button", + reservation: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + window.open(r.message, "_self"); + frm.reload_doc(); + } + }, + }); + }); + } + // Show Info that Check In is In Progress. Meaning button Check In clicked, either from Reservation List or + // from Start Check In Process Button + if (is_check_in === "true") { + frm.set_intro(__("In Progress Checking In Guest")); + // Assign some variables from "Reservation Detail" to "Room Stay" + autofill(frm); + is_form_not_good_to_go = is_form_good_to_in_house(frm); + console.log("is_form_not_good_to_go = " + is_form_not_good_to_go); + console.log("error_message = " + error_message); + if ( + is_form_not_good_to_go === true && + (error_message !== "" || + error_message !== + "Please fill these fields before Finishing Check In process:
        ") + ) { + frm.set_intro(error_message); + } else { + frm.add_custom_button(__("Finish Check In Process"), function () { + if (frm.doc.__unsaved !== undefined || frm.doc.unsaved == 1) { + frappe.msgprint( + "The Reservation has been modified and not saved yet. Please click Save before Finishing Check In Process." + ); + } else { + is_check_in = "false"; + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.check_in_reservation", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message === "In House") { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + console.log(r.message); + } + }, + }); + frappe.set_route("Form", "Inn Reservation", frm.doc.name); + } else { + frappe.msgprint(r.message); + } + }, + }); + } + }); + // Checking if deposit is made before allow to finish checking in + // frappe.call({ + // method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.allowed_to_in_house', + // args: { + // reservation_id: frm.doc.name + // }, + // callback: (r) => { + // if (r.message === false) { + // frm.set_intro(__("Make Guest Deposit in Folio to continue Check In process.")); + // } + // else if (r.message === true) { + // frm.add_custom_button(__("Finish Check In Process"), function () { + // if (frm.doc.__unsaved !== undefined || frm.doc.unsaved === 1) { + // frappe.msgprint("The Reservation has been modified. Please click Save before Finishing Check In Process."); + // } + // else { + // is_check_in = "false"; + // frappe.call({ + // method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.check_in_reservation', + // args: { + // reservation_id: frm.doc.name + // }, + // callback: (r) => { + // if (r.message === 'In House') { + // frappe.call({ + // method: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation', + // args: { + // reservation_id: frm.doc.name + // }, + // callback: (r) => { + // if (r.message) { + // console.log(r.message); + // } + // } + // }); + // frappe.set_route('Form', 'Inn Reservation', frm.doc.name); + // } + // } + // }); + // } + // }); + // } + // } + // }); + } + } + //Add Cancel Button if Status still Reserved + frm.page.add_menu_item(__("Cancel"), function () { + frappe.confirm( + __("You are about to Cancel this Reservation. Are you sure?"), + function () { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.cancel_reservation", + args: { + source: "cancel_button", + reservation: frm.doc.name, + }, + callback: (r) => { + if (r.message === 1) { + frappe.msgprint( + "Only Reservation with status Reserved can be cancelled. Please choose other Reservation" + ); + } else if (r.message === 0) { + frm.refresh(); + frappe.msgprint( + "Reservation " + frm.doc.name + " successfully canceled." + ); + } + }, + }); + } + ); + }); + // Add No Show Button if Status still Reserved + frm.page.add_menu_item(__("No Show"), function () { + frappe.confirm( + __("You are about to mark the guest as No Show. Are you Sure?"), + function () { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.no_show_reservation", + args: { + source: "no_show_button", + reservation: frm.doc.name, + }, + callback: (r) => { + if (r.message === 1) { + frappe.msgprint( + "Only Reservation with status Reserved can be set to No Show. Please choose other Reservation" + ); + } else if (r.message === 0) { + frm.refresh(); + frappe.msgprint( + "Reservation " + + frm.doc.name + + " successfully set to No Show." + ); + } + }, + }); + } + ); + }); + } + if (frm.doc.__islocal !== 1 && frm.doc.status === "In House") { + /* Control field visibilities */ + frm.set_df_property("init_actual_room_rate", "hidden", 1); // Initial Actual Room rate + frm.set_df_property("sb3", "hidden", 0); // Issue Card Table Section + frm.set_df_property("sb4", "hidden", 0); // Issue Card Buttons Section - /*Add menu item buttons*/ - frm.page.add_menu_item(__('Cancel'), function () { - frappe.confirm(__("You are about to Cancel this Reservation with status already In House. Are you sure?"), function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.cancel_single_reservation_in_house', - args: { - reservation_id: frm.doc.name, - }, - callback: (r) => { - if (r.message === 0) { - frm.refresh(); - frappe.msgprint("Reservation " + frm.doc.name + " successfully canceled."); - } - else if (r.message === 1) { - frappe.msgprint("Cancellation Fail. Please try again."); - } - else if (r.message === 2) { - frappe.msgprint('There are several outstanding payments.
        ' + - 'Please go to the Folio page to complete payment process before Cancelling Reservation'); - } - } - }); - }); - }); - frm.page.add_menu_item(__('Check Out'), function () { - process_check_out(frm); - }); - frm.page.add_menu_item(__('Move Room'), function () { - move_room(frm); - }); + /*Add menu item buttons*/ + frm.page.add_menu_item(__("Cancel"), function () { + frappe.confirm( + __( + "You are about to Cancel this Reservation with status already In House. Are you sure?" + ), + function () { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.cancel_single_reservation_in_house", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message === 0) { + frm.refresh(); + frappe.msgprint( + "Reservation " + frm.doc.name + " successfully canceled." + ); + } else if (r.message === 1) { + frappe.msgprint("Cancellation Fail. Please try again."); + } else if (r.message === 2) { + frappe.msgprint( + "There are several outstanding payments.
        " + + "Please go to the Folio page to complete payment process before Cancelling Reservation" + ); + } + }, + }); + } + ); + }); + frm.page.add_menu_item(__("Check Out"), function () { + process_check_out(frm); + }); + frm.page.add_menu_item(__("Move Room"), function () { + move_room(frm); + }); - /*Add Warning when changing Arrival and Departure Data*/ - frm.fields_dict.arrival.$input.on("click", function (evt) { - frappe.show_alert(__("Warning!
        Changing Actual Arrival when Reservation status is In House may cause data inconsistencies.")); - }) - frm.fields_dict.departure.$input.on("click", function (evt) { - frappe.show_alert(__("Warning!
        Changing Actual Departure when Reservation status is In House may cause data inconsistencies.")); - }) - } - }, - after_save: function (frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio.inn_folio.create_folio', - args: { - reservation_id: frm.doc.name - }, - async: false - }); - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation', - args: { - reservation_id: frm.doc.name, - }, - callback: (r) => { - if (r.message) { - console.log(r.message); - } - } - }); - }, - expected_arrival: function (frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_audit_log.inn_audit_log.get_last_audit_date', - callback: (r) => { - if (r.message) { - if (frm.doc.expected_arrival < r.message) { - frm.set_value('expected_arrival', r.message); - frappe.msgprint("Expected Arrival must be greater than last audit date: " + r.message); - } - else { - if (frm.doc.expected_departure && (frm.doc.__islocal == 1 || frm.doc.status == 'Reserved')) { - frm.set_value('total_night', calculate_nights(frm.doc.expected_arrival, frm.doc.expected_departure)); - } - } - } - else { - frappe.msgprint("Warning: There is no audit log defined. First Audit Log must be manually defined. Contact the administrator for assistance."); - } - } - }); - }, - customer_id: function (frm) { - toggle_room_detail(frm) - }, - channel: function (frm) { - toggle_room_detail(frm) - }, - expected_departure: function (frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_audit_log.inn_audit_log.get_last_audit_date', - callback: (r) => { - if (r.message) { - if (frm.doc.expected_departure < r.message) { - frm.set_value('expected_departure', null); - frappe.msgprint("Expected Departure must be greater than last audit date: " + r.message); - } - else if (frm.doc.expected_departure <= frm.doc.expected_arrival) { - frm.set_value('expected_departure', null); - frappe.msgprint("Expected Departure must be greater than Expected Arrival."); - } - else { - if (frm.doc.expected_arrival && (frm.doc.__islocal == 1 || frm.doc.status == 'Reserved')) { - frm.set_value('total_night', calculate_nights(frm.doc.expected_arrival, frm.doc.expected_departure)); - toggle_room_detail(frm) - } - } - } - else { - frappe.msgprint("Warning: There is no audit log defined. First Audit Log must be manually defined. Contact the administrator for assistance."); - } - } - }); - }, - arrival: function (frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_audit_log.inn_audit_log.get_last_audit_date', - callback: (r) => { - if (r.message) { - let now = new Date(); - let date_arrival = new Date(frm.doc.arrival); - let date_departure = new Date(frm.doc.departure); + /*Add Warning when changing Arrival and Departure Data*/ + frm.fields_dict.arrival.$input.on("click", function (evt) { + frappe.show_alert( + __( + "Warning!
        Changing Actual Arrival when Reservation status is In House may cause data inconsistencies." + ) + ); + }); + frm.fields_dict.departure.$input.on("click", function (evt) { + frappe.show_alert( + __( + "Warning!
        Changing Actual Departure when Reservation status is In House may cause data inconsistencies." + ) + ); + }); + } + }, + after_save: function (frm) { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_folio.inn_folio.create_folio", + args: { + reservation_id: frm.doc.name, + }, + async: false, + }); + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + console.log(r.message); + } + }, + }); + }, + expected_arrival: function (frm) { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_audit_log.inn_audit_log.get_last_audit_date", + callback: (r) => { + if (r.message) { + if (frm.doc.expected_arrival < r.message) { + frm.set_value("expected_arrival", r.message); + frappe.msgprint( + "Expected Arrival must be greater than last audit date: " + + r.message + ); + } else { + if ( + frm.doc.expected_departure && + (frm.doc.__islocal == 1 || frm.doc.status == "Reserved") + ) { + frm.set_value( + "total_night", + calculate_nights( + frm.doc.expected_arrival, + frm.doc.expected_departure + ) + ); + } + } + } else { + frappe.msgprint( + "Warning: There is no audit log defined. First Audit Log must be manually defined. Contact the administrator for assistance." + ); + } + }, + }); + }, + customer_id: function (frm) { + toggle_room_detail(frm); + }, + channel: function (frm) { + toggle_room_detail(frm); + }, + expected_departure: function (frm) { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_audit_log.inn_audit_log.get_last_audit_date", + callback: (r) => { + if (r.message) { + if (frm.doc.expected_departure < r.message) { + frm.set_value("expected_departure", null); + frappe.msgprint( + "Expected Departure must be greater than last audit date: " + + r.message + ); + } else if (frm.doc.expected_departure <= frm.doc.expected_arrival) { + frm.set_value("expected_departure", null); + frappe.msgprint( + "Expected Departure must be greater than Expected Arrival." + ); + } else { + if ( + frm.doc.expected_arrival && + (frm.doc.__islocal == 1 || frm.doc.status == "Reserved") + ) { + frm.set_value( + "total_night", + calculate_nights( + frm.doc.expected_arrival, + frm.doc.expected_departure + ) + ); + toggle_room_detail(frm); + } + } + } else { + frappe.msgprint( + "Warning: There is no audit log defined. First Audit Log must be manually defined. Contact the administrator for assistance." + ); + } + }, + }); + }, + arrival: function (frm) { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_audit_log.inn_audit_log.get_last_audit_date", + callback: (r) => { + if (r.message) { + let now = new Date(); + let date_arrival = new Date(frm.doc.arrival); + let date_departure = new Date(frm.doc.departure); - let expected_arrival_date = new Date(frm.doc.expected_arrival); - expected_arrival_date.setHours(now.getHours(), now.getMinutes(), now.getSeconds()); - let default_arrival = expected_arrival_date.toISOString().replace("T", " ") - default_arrival = default_arrival.substring(0, default_arrival.length - 5) + let expected_arrival_date = new Date(frm.doc.expected_arrival); + expected_arrival_date.setHours( + now.getHours(), + now.getMinutes(), + now.getSeconds() + ); + let default_arrival = expected_arrival_date + .toISOString() + .replace("T", " "); + default_arrival = default_arrival.substring( + 0, + default_arrival.length - 5 + ); - if (frm.doc.arrival < r.message) { - frm.set_value('arrival', default_arrival); - frappe.msgprint("Actual Arrival must be greater than last audit date: " + r.message + ". Defaulted to Expected Arrival."); - } - else if (date_departure.setHours(0, 0, 0, 0) <= date_arrival.setHours(0, 0, 0, 0)) { - frm.set_value('arrival', default_arrival); - frappe.msgprint("Actual Departure must be greater than Actual Arrival. Defaulted to Expected Arrival."); - } - else if (frm.doc.arrival == null || frm.doc.arrival == undefined || frm.doc.arrival == '') { - frm.set_value('arrival', default_arrival); - frappe.msgprint("Actual Arrival cannot be empty. Defaulted to Expected Arrival."); - } - else { - calculate_rate_and_bill(frm); - if (frm.doc.departure) { - frm.set_value('total_night', calculate_nights(frm.doc.arrival, frm.doc.departure)); - } - toggle_room_detail(frm) - } - } - else { - frappe.msgprint("Warning: There is no audit log defined. First Audit Log must be manually defined. Contact the administrator for assistance."); - } - } - }); - }, - departure: function (frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_audit_log.inn_audit_log.get_last_audit_date', - callback: (r) => { - if (r.message) { - let date_arrival = new Date(frm.doc.arrival); - let date_departure = new Date(frm.doc.departure); + if (frm.doc.arrival < r.message) { + frm.set_value("arrival", default_arrival); + frappe.msgprint( + "Actual Arrival must be greater than last audit date: " + + r.message + + ". Defaulted to Expected Arrival." + ); + } else if ( + date_departure.setHours(0, 0, 0, 0) <= + date_arrival.setHours(0, 0, 0, 0) + ) { + frm.set_value("arrival", default_arrival); + frappe.msgprint( + "Actual Departure must be greater than Actual Arrival. Defaulted to Expected Arrival." + ); + } else if ( + frm.doc.arrival == null || + frm.doc.arrival == undefined || + frm.doc.arrival == "" + ) { + frm.set_value("arrival", default_arrival); + frappe.msgprint( + "Actual Arrival cannot be empty. Defaulted to Expected Arrival." + ); + } else { + calculate_rate_and_bill(frm); + if (frm.doc.departure) { + frm.set_value( + "total_night", + calculate_nights(frm.doc.arrival, frm.doc.departure) + ); + } + toggle_room_detail(frm); + } + } else { + frappe.msgprint( + "Warning: There is no audit log defined. First Audit Log must be manually defined. Contact the administrator for assistance." + ); + } + }, + }); + }, + departure: function (frm) { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_audit_log.inn_audit_log.get_last_audit_date", + callback: (r) => { + if (r.message) { + let date_arrival = new Date(frm.doc.arrival); + let date_departure = new Date(frm.doc.departure); - let default_departure_date = new Date(frm.doc.expected_departure); - default_departure_date.setHours(12, 0, 0); - let default_departure = default_departure_date.toISOString().replace("T", " ") - default_departure = default_departure.substring(0, default_departure.length - 5) + let default_departure_date = new Date(frm.doc.expected_departure); + default_departure_date.setHours(12, 0, 0); + let default_departure = default_departure_date + .toISOString() + .replace("T", " "); + default_departure = default_departure.substring( + 0, + default_departure.length - 5 + ); - if (frm.doc.departure < r.message) { - frm.set_value('departure', default_departure); - frappe.msgprint("Actual Departure must be greater than Last Audit Date: " + r.message + ". Defaulted to Expected Departure."); - } - else if (date_departure.setHours(0, 0, 0, 0) <= date_arrival.setHours(0, 0, 0, 0)) { - frm.set_value('departure', default_departure); - frappe.msgprint("Actual Departure must be greater than Actual Arrival. Defaulted to Expected Departure."); - } - else if (frm.doc.departure == null || frm.doc.departure == undefined || frm.doc.departure == '') { - frm.set_value('departure', default_departure); - frappe.msgprint("Actual Departure cannot be empty. Defaulted to Expected Departure."); - } - else { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_booking_name_by_reservation', - args: { - reservation_id: frm.doc.name - }, - callback: (r) => { - if (r.message) { - let room_booking_name = r.message; - console.log("r = " + r.message); - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_name_within_date_range', - args: { - room_id: frm.doc.actual_room_id, - start: formatDate(frm.doc.arrival), - end: formatDate(frm.doc.departure), - }, - callback: (resp) => { - console.log("resp = " + resp.message); - if (resp.message == room_booking_name || resp.message.length == 0) { - calculate_rate_and_bill(frm); - if (frm.doc.arrival) { - frm.set_value('total_night', calculate_nights(frm.doc.arrival, frm.doc.departure)); - } - } - else { - frappe.msgprint("Cannot change Actual Departure Date to " + frm.doc.departure + - ". There are already room booking for Room " + frm.doc.actual_room_id + " made for that date." + - "
        Check Room Availability Page for more detail."); - frm.set_value('departure', default_departure); - } - // if (r.message == false) { - // frappe.msgprint("gak bisa"); - // } - // else { - // calculate_rate_and_bill(frm); - // } - } - }); - } - } - }); - } - } - else { - frappe.msgprint("Warning: There is no audit log defined. First Audit Log must be manually defined. Contact the administrator for assistance."); - } - } - }); - }, - type: function (frm) { - toggle_room_detail(frm) - }, - room_type: function (frm) { - let phase = ''; - let start_date = frm.doc.expected_arrival; - if (is_check_in === 'true') { - phase = 'Check In'; - start_date = formatDate(frm.doc.arrival); - } - else if (frm.doc.status !== 'Reserved') { - start_date = formatDate(frm.doc.arrival); - } - manage_filters('room_type', phase, start_date); - }, - bed_type: function (frm) { - let phase = ''; - let start_date = frm.doc.expected_arrival; - if (is_check_in === 'true') { - phase = 'Check In'; - start_date = formatDate(frm.doc.arrival); - } - else if (frm.doc.status !== 'Reserved') { - start_date = formatDate(frm.doc.arrival); - } - manage_filters('bed_type', phase, start_date); - }, - room_id: function (frm) { - let phase = ''; - let start_date = undefined; - if (frm.doc.expected_arrival !== undefined) { - start_date = frm.doc.expected_arrival; - } - if (is_check_in === 'true') { - phase = 'Check In'; - start_date = formatDate(frm.doc.arrival); - } - else if (frm.doc.status !== 'Reserved') { - start_date = formatDate(frm.doc.arrival); - } - if (start_date !== undefined) { - manage_filters('room_id', phase, start_date); - } - }, - actual_room_id: function (frm) { - let phase = ''; - let start_date = frm.doc.expected_arrival; - if (is_check_in === 'true') { - phase = 'Check In'; - start_date = formatDate(frm.doc.arrival); - } - else if (frm.doc.status !== 'Reserved') { - start_date = formatDate(frm.doc.arrival); - } - console.log("actual room id = " + frm.doc.actual_room_id); - manage_filters('actual_room_id', phase, start_date); - }, - room_rate: function (frm) { - if (frm.doc.room_rate == undefined || frm.doc.room_rate == "") { - return - } + if (frm.doc.departure < r.message) { + frm.set_value("departure", default_departure); + frappe.msgprint( + "Actual Departure must be greater than Last Audit Date: " + + r.message + + ". Defaulted to Expected Departure." + ); + } else if ( + date_departure.setHours(0, 0, 0, 0) <= + date_arrival.setHours(0, 0, 0, 0) + ) { + frm.set_value("departure", default_departure); + frappe.msgprint( + "Actual Departure must be greater than Actual Arrival. Defaulted to Expected Departure." + ); + } else if ( + frm.doc.departure == null || + frm.doc.departure == undefined || + frm.doc.departure == "" + ) { + frm.set_value("departure", default_departure); + frappe.msgprint( + "Actual Departure cannot be empty. Defaulted to Expected Departure." + ); + } else { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_booking_name_by_reservation", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + let room_booking_name = r.message; + console.log("r = " + r.message); + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_name_within_date_range", + args: { + room_id: frm.doc.actual_room_id, + start: formatDate(frm.doc.arrival), + end: formatDate(frm.doc.departure), + }, + callback: (resp) => { + console.log("resp = " + resp.message); + if ( + resp.message == room_booking_name || + resp.message.length == 0 + ) { + calculate_rate_and_bill(frm); + if (frm.doc.arrival) { + frm.set_value( + "total_night", + calculate_nights(frm.doc.arrival, frm.doc.departure) + ); + } + } else { + frappe.msgprint( + "Cannot change Actual Departure Date to " + + frm.doc.departure + + ". There are already room booking for Room " + + frm.doc.actual_room_id + + " made for that date." + + "
        Check Room Availability Page for more detail." + ); + frm.set_value("departure", default_departure); + } + // if (r.message == false) { + // frappe.msgprint("gak bisa"); + // } + // else { + // calculate_rate_and_bill(frm); + // } + }, + }); + } + }, + }); + } + } else { + frappe.msgprint( + "Warning: There is no audit log defined. First Audit Log must be manually defined. Contact the administrator for assistance." + ); + } + }, + }); + }, + type: function (frm) { + toggle_room_detail(frm); + }, + room_type: function (frm) { + let phase = ""; + let start_date = frm.doc.expected_arrival; + if (is_check_in === "true") { + phase = "Check In"; + start_date = formatDate(frm.doc.arrival); + } else if (frm.doc.status !== "Reserved") { + start_date = formatDate(frm.doc.arrival); + } + manage_filters("room_type", phase, start_date); + }, + bed_type: function (frm) { + let phase = ""; + let start_date = frm.doc.expected_arrival; + if (is_check_in === "true") { + phase = "Check In"; + start_date = formatDate(frm.doc.arrival); + } else if (frm.doc.status !== "Reserved") { + start_date = formatDate(frm.doc.arrival); + } + manage_filters("bed_type", phase, start_date); + }, + room_id: function (frm) { + let phase = ""; + let start_date = undefined; + if (frm.doc.expected_arrival !== undefined) { + start_date = frm.doc.expected_arrival; + } + if (is_check_in === "true") { + phase = "Check In"; + start_date = formatDate(frm.doc.arrival); + } else if (frm.doc.status !== "Reserved") { + start_date = formatDate(frm.doc.arrival); + } + if (start_date !== undefined) { + manage_filters("room_id", phase, start_date); + } + }, + actual_room_id: function (frm) { + let phase = ""; + let start_date = frm.doc.expected_arrival; + if (is_check_in === "true") { + phase = "Check In"; + start_date = formatDate(frm.doc.arrival); + } else if (frm.doc.status !== "Reserved") { + start_date = formatDate(frm.doc.arrival); + } + console.log("actual room id = " + frm.doc.actual_room_id); + manage_filters("actual_room_id", phase, start_date); + }, + room_rate: function (frm) { + if (frm.doc.room_rate == undefined || frm.doc.room_rate == "") { + return; + } - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room_rate.inn_room_rate.get_base_room_rate', - args: { - room_rate_id: frm.doc.room_rate - }, - callback: (r) => { - if (r.message) { - frm.set_value('base_room_rate', r.message); - frm.refresh_field('base_room_rate'); - if (frm.doc.status == 'Reserved') { - if (parseInt(r.message) > parseInt(frm.doc.init_actual_room_rate)) { - frm.set_value('init_actual_room_rate', parseInt(r.message)); - frm.refresh_field('init_actual_room_rate'); - } - } - } - } - }); + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_rate.inn_room_rate.get_base_room_rate", + args: { + room_rate_id: frm.doc.room_rate, + }, + callback: (r) => { + if (r.message) { + frm.set_value("base_room_rate", r.message); + frm.refresh_field("base_room_rate"); + if (frm.doc.status == "Reserved") { + if (parseInt(r.message) > parseInt(frm.doc.init_actual_room_rate)) { + frm.set_value("init_actual_room_rate", parseInt(r.message)); + frm.refresh_field("init_actual_room_rate"); + } + } + } + }, + }); - - // if status is reserved, front office will trigger checkin and will trigger the nett_room_rate - if (frm.doc.status != "Reserved" || is_check_in == 'true') { - calculate_rate_and_bill(frm) - } - - - - }, - init_actual_room_rate: function (frm) { - if ((parseFloat(frm.doc.init_actual_room_rate) == 0.0) || (parseFloat(frm.doc.init_actual_room_rate) > 0 && parseInt(frm.doc.init_actual_room_rate) < parseInt(frm.doc.base_room_rate))) { - frappe.msgprint("Actual Room Rate must be equal or higher than Base Room Rate."); - frm.set_value('init_actual_room_rate', frm.doc.base_room_rate); - } - }, - actual_room_rate: function (frm) { - if (frm.doc.arrival !== undefined && frm.doc.departure !== undefined) { - if (frm.doc.actual_room_rate == null || frm.doc.actual_room_rate == '') { - frm.set_value('actual_room_rate', frm.doc.base_room_rate); - } - else if (parseFloat(frm.doc.actual_room_rate) > 0 && parseInt(frm.doc.actual_room_rate) < parseInt(frm.doc.base_room_rate)) { - frappe.msgprint("Actual Room Rate must be equal or higher than Base Room Rate."); - frm.set_value('actual_room_rate', frm.doc.base_room_rate); - } - else if (parseFloat(frm.doc.actual_room_rate) === 0.0) { - frm.set_value('room_bill', 0); - frm.set_value('actual_room_rate_tax', null); - frm.set_value('nett_actual_room_rate', 0); - frm.set_value('actual_breakfast_rate_tax', null); - frm.set_value('nett_actual_breakfast_rate', 0); - } - else { - frm.set_df_property('sb1', 'hidden', 0); // Actual Room Rate Breakdown Section - calculate_rate_and_bill(frm); - } - } else { - if (parseFloat(frm.doc.actual_room_rate) > 0) { - frappe.msgprint("Please fill Actual Arrival and Actual Departure first."); - frm.set_value('actual_room_rate', 0); - frm.set_value('room_bill', 0); - frm.set_value('actual_room_rate_tax', 0); - frm.set_value('nett_actual_room_rate', 0); - frm.set_value('actual_breakfast_rate_tax', 0); - frm.set_value('nett_actual_breakfast_rate', 0); - } - } - }, - issue_card: function (frm) { - if (frm.doc.__islocal !== 1 && frm.doc.status === 'In House') { - let current_active_card = 0; - let all_issued_card = frm.doc.issued_card; - for (let key in all_issued_card) { - current_active_card += all_issued_card[key].is_active; - } - if (current_active_card >= room_max_active_card) { - frappe.msgprint("Maximum number of active card issued is reached. Cannot issue more card"); - } - else { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_key_card.inn_key_card.issue_card', - args: { - reservation_id: frm.doc.name - }, - callback: (r) => { - if (r.message !== 'ERROR') { - frm.reload_doc(); - frappe.show_alert(__("Card " + r.message + " issued for this Reservation.")); return; - } - else { - frappe.msgprint("Error Issuing Card, Please Redo the Process.") - } - } - }); - } - } - }, - verify_card: function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_key_card.inn_key_card.verify_card', - args: { - track: "3" - } - }); - }, - test_1: function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_key_card.inn_key_card.test_api', - args: { - option: "1" - } - }); - }, - test_2: function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_key_card.inn_key_card.test_api', - args: { - option: "2" - } - }); - }, - test_3: function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_key_card.inn_key_card.test_api', - args: { - option: "3" - } - }); - }, - test_4: function () { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_key_card.inn_key_card.test_api', - args: { - option: "4" - } - }); - }, + // if status is reserved, front office will trigger checkin and will trigger the nett_room_rate + if (frm.doc.status != "Reserved" || is_check_in == "true") { + calculate_rate_and_bill(frm); + } + }, + init_actual_room_rate: function (frm) { + if ( + parseFloat(frm.doc.init_actual_room_rate) == 0.0 || + (parseFloat(frm.doc.init_actual_room_rate) > 0 && + parseInt(frm.doc.init_actual_room_rate) < + parseInt(frm.doc.base_room_rate)) + ) { + frappe.msgprint( + "Actual Room Rate must be equal or higher than Base Room Rate." + ); + frm.set_value("init_actual_room_rate", frm.doc.base_room_rate); + } + }, + actual_room_rate: function (frm) { + if (frm.doc.arrival !== undefined && frm.doc.departure !== undefined) { + if (frm.doc.actual_room_rate == null || frm.doc.actual_room_rate == "") { + frm.set_value("actual_room_rate", frm.doc.base_room_rate); + } else if ( + parseFloat(frm.doc.actual_room_rate) > 0 && + parseInt(frm.doc.actual_room_rate) < parseInt(frm.doc.base_room_rate) + ) { + frappe.msgprint( + "Actual Room Rate must be equal or higher than Base Room Rate." + ); + frm.set_value("actual_room_rate", frm.doc.base_room_rate); + } else if (parseFloat(frm.doc.actual_room_rate) === 0.0) { + frm.set_value("room_bill", 0); + frm.set_value("actual_room_rate_tax", null); + frm.set_value("nett_actual_room_rate", 0); + frm.set_value("actual_breakfast_rate_tax", null); + frm.set_value("nett_actual_breakfast_rate", 0); + } else { + frm.set_df_property("sb1", "hidden", 0); // Actual Room Rate Breakdown Section + calculate_rate_and_bill(frm); + } + } else { + if (parseFloat(frm.doc.actual_room_rate) > 0) { + frappe.msgprint( + "Please fill Actual Arrival and Actual Departure first." + ); + frm.set_value("actual_room_rate", 0); + frm.set_value("room_bill", 0); + frm.set_value("actual_room_rate_tax", 0); + frm.set_value("nett_actual_room_rate", 0); + frm.set_value("actual_breakfast_rate_tax", 0); + frm.set_value("nett_actual_breakfast_rate", 0); + } + } + }, + issue_card: function (frm) { + if (frm.doc.__islocal !== 1 && frm.doc.status === "In House") { + let current_active_card = 0; + let all_issued_card = frm.doc.issued_card; + for (let key in all_issued_card) { + current_active_card += all_issued_card[key].is_active; + } + if (current_active_card >= room_max_active_card) { + frappe.msgprint( + "Maximum number of active card issued is reached. Cannot issue more card" + ); + } else { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_key_card.inn_key_card.issue_card", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message !== "ERROR") { + frm.reload_doc(); + frappe.show_alert( + __("Card " + r.message + " issued for this Reservation.") + ); + return; + } else { + frappe.msgprint("Error Issuing Card, Please Redo the Process."); + } + }, + }); + } + } + }, + verify_card: function () { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_key_card.inn_key_card.verify_card", + args: { + track: "3", + }, + }); + }, + test_1: function () { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_key_card.inn_key_card.test_api", + args: { + option: "1", + }, + }); + }, + test_2: function () { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_key_card.inn_key_card.test_api", + args: { + option: "2", + }, + }); + }, + test_3: function () { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_key_card.inn_key_card.test_api", + args: { + option: "3", + }, + }); + }, + test_4: function () { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_key_card.inn_key_card.test_api", + args: { + option: "4", + }, + }); + }, }); -frappe.ui.form.on('Inn Key Card', { - erase_card: function (frm, cdt, cdn) { - let child = locals[cdt][cdn]; - if (child.is_active === 1) { - erase_card('with', child.name); - } - else { - frappe.msgprint("Card already deactivated."); - } - }, - deactivate_wo_card: function (frm, cdt, cdn) { - let child = locals[cdt][cdn]; - if (child.is_active === 1) { - erase_card('without', child.name); - } - else { - frappe.msgprint("Card already deactivated."); - } - } +frappe.ui.form.on("Inn Key Card", { + erase_card: function (frm, cdt, cdn) { + let child = locals[cdt][cdn]; + if (child.is_active === 1) { + erase_card("with", child.name); + } else { + frappe.msgprint("Card already deactivated."); + } + }, + deactivate_wo_card: function (frm, cdt, cdn) { + let child = locals[cdt][cdn]; + if (child.is_active === 1) { + erase_card("without", child.name); + } else { + frappe.msgprint("Card already deactivated."); + } + }, }); function toggle_room_detail(frm) { - if (frm.doc.customer_id == undefined || - frm.doc.type == undefined || - frm.doc.channel == undefined || - frm.doc.expected_arrival == undefined || - frm.doc.expected_departure == undefined) { - room_stay_detail_toggle_show(frm, true) - } else { - room_stay_detail_toggle_show(frm, false) - } + if ( + frm.doc.customer_id == undefined || + frm.doc.type == undefined || + frm.doc.channel == undefined || + frm.doc.expected_arrival == undefined || + frm.doc.expected_departure == undefined + ) { + room_stay_detail_toggle_show(frm, true); + } else { + room_stay_detail_toggle_show(frm, false); + } } function room_stay_detail_toggle_show(frm, toggle) { - frm.set_df_property("guest_name", "disabled", toggle) - frm.set_df_property("room_type", "disabled", toggle) - frm.set_df_property("bed_type", "disabled", toggle) - frm.set_df_property("room_id", "disabled", toggle) - frm.set_df_property("room_rate", "disabled", toggle) - frm.set_df_property("init_actual_room_rate", "disabled", toggle) - frm.set_df_property("adult", "disabled", toggle) - frm.set_df_property("child", "disabled", toggle) - frm.set_df_property("extra_bed", "disabled", toggle) + frm.set_df_property("guest_name", "disabled", toggle); + frm.set_df_property("room_type", "disabled", toggle); + frm.set_df_property("bed_type", "disabled", toggle); + frm.set_df_property("room_id", "disabled", toggle); + frm.set_df_property("room_rate", "disabled", toggle); + frm.set_df_property("init_actual_room_rate", "disabled", toggle); + frm.set_df_property("adult", "disabled", toggle); + frm.set_df_property("child", "disabled", toggle); + frm.set_df_property("extra_bed", "disabled", toggle); } // Function to extract variable's value passed on URL function getUrlVars() { - var vars = {}; - var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (m, key, value) { - vars[key] = value; - }); - return vars; + var vars = {}; + var parts = window.location.href.replace( + /[?&]+([^=&]+)=([^&]*)/gi, + function (m, key, value) { + vars[key] = value; + } + ); + return vars; } // Function to check if all fields needed to be filled are filled in order to change the reservation status to In House function is_form_good_to_in_house(frm) { - error_message = ''; - is_error = false; - if (frm.doc.guest_name === undefined || frm.doc.guest_name === '') { - is_error = true; - error_message += '
      • Guest Name
      • '; - } - if (frm.doc.arrival === undefined || frm.doc.arrival === '') { - is_error = true; - error_message += '
      • Actual Arrival
      • '; - } - if (frm.doc.departure === undefined || frm.doc.departure === '') { - is_error = true; - error_message += '
      • Actual Departure
      • '; - } - if (frm.doc.actual_room_id === undefined || frm.doc.actual_room_id === '') { - is_error = true; - error_message += '
      • Actual Room
      • '; - } - if (frm.doc.actual_room_rate === 0) { - is_error = true; - error_message += '
      • Actual Room Rate
      • '; - } - if (frm.doc.adult === 0) { - is_error = true; - error_message += '
      • Adult
      • '; - } - error_message += '
      '; + error_message = ""; + is_error = false; + if (frm.doc.guest_name === undefined || frm.doc.guest_name === "") { + is_error = true; + error_message += "
    • Guest Name
    • "; + } + if (frm.doc.arrival === undefined || frm.doc.arrival === "") { + is_error = true; + error_message += "
    • Actual Arrival
    • "; + } + if (frm.doc.departure === undefined || frm.doc.departure === "") { + is_error = true; + error_message += "
    • Actual Departure
    • "; + } + if (frm.doc.actual_room_id === undefined || frm.doc.actual_room_id === "") { + is_error = true; + error_message += "
    • Actual Room
    • "; + } + if (frm.doc.actual_room_rate === 0) { + is_error = true; + error_message += "
    • Actual Room Rate
    • "; + } + if (frm.doc.adult === 0) { + is_error = true; + error_message += "
    • Adult
    • "; + } + error_message += "
    "; - if (is_error === true) { - error_message = 'Please fill these fields before Finishing Check In process:
      ' + error_message; - } - else { - is_error = false; - error_message = ''; - } - return is_error; + if (is_error === true) { + error_message = + "Please fill these fields before Finishing Check In process:
        " + + error_message; + } else { + is_error = false; + error_message = ""; + } + return is_error; } function format_date_to_string_arrival(datetime) { - "12-06-2023 23:22:54" - var date = datetime.getFullYear() + "-" - + ('0' + (datetime.getMonth() + 1)).slice(-2) + '-' - + ('0' + datetime.getDate()).slice(-2) + "12-06-2023 23:22:54"; + var date = + datetime.getFullYear() + + "-" + + ("0" + (datetime.getMonth() + 1)).slice(-2) + + "-" + + ("0" + datetime.getDate()).slice(-2); - var time = ('0' + datetime.getHours()).slice(-2) + ':' - + ('0' + (datetime.getMinutes())).slice(-2) + ':' - + ('0' + (datetime.getSeconds())).slice(-2); - return date + " " + time + var time = + ("0" + datetime.getHours()).slice(-2) + + ":" + + ("0" + datetime.getMinutes()).slice(-2) + + ":" + + ("0" + datetime.getSeconds()).slice(-2); + return date + " " + time; } // Function to autofilled some of the Fields in Checkin In Process function autofill(frm) { - frm.set_df_property('init_actual_room_rate', 'hidden', 1); - frm.set_df_property('actual_room_rate', 'hidden', 0); - frm.set_df_property('sb1', 'hidden', 0); // Actual Room Rate Breakdown Section - let now = new Date(); - let expected_arrival = new Date(frm.doc.expected_arrival); - let expected_departure = new Date(frm.doc.expected_departure); - expected_arrival.setHours(now.getHours(), now.getMinutes(), now.getSeconds()); - expected_departure.setHours(12, 0, 0); - if (frm.doc.guest_name === undefined || frm.doc.guest_name == null || frm.doc.guest_name === '') { - frm.set_value('guest_name', frm.doc.customer_id); - } - if (frm.doc.arrival === undefined || frm.doc.arrival == null || frm.doc.arrival === '') { - frm.set_value('arrival', format_date_to_string_arrival(expected_arrival)); - } - if (frm.doc.departure === undefined || frm.doc.departure == null || frm.doc.departure === '') { - frm.set_value('departure', format_date_to_string_arrival(expected_departure)); - } - if (frm.doc.actual_room_rate === undefined || frm.doc.actual_room_rate == null || parseFloat(frm.doc.actual_room_rate) == 0.0) { - frm.set_value('actual_room_rate', frm.doc.init_actual_room_rate); - } - if (frm.doc.actual_room_id === undefined || frm.doc.actual_room_id == null || frm.doc.actual_room_id === '') { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room.inn_room.get_room_status', - args: { - room_id: frm.doc.room_id - }, - callback: (r) => { - if (r.message === 'Vacant Ready') { - frm.set_value('actual_room_id', frm.doc.room_id); - } - else { - get_available('actual_room_id', 'Check In'); - frappe.msgprint("Currently, Room " + frm.doc.room_id + " status is not Vacant Ready. " + - "Please consult with Room Service or choose another Room to continue Checking In.") - } - } - }); - } + frm.set_df_property("init_actual_room_rate", "hidden", 1); + frm.set_df_property("actual_room_rate", "hidden", 0); + frm.set_df_property("sb1", "hidden", 0); // Actual Room Rate Breakdown Section + let now = new Date(); + let expected_arrival = new Date(frm.doc.expected_arrival); + let expected_departure = new Date(frm.doc.expected_departure); + expected_arrival.setHours(now.getHours(), now.getMinutes(), now.getSeconds()); + expected_departure.setHours(12, 0, 0); + if ( + frm.doc.guest_name === undefined || + frm.doc.guest_name == null || + frm.doc.guest_name === "" + ) { + frm.set_value("guest_name", frm.doc.customer_id); + } + if ( + frm.doc.arrival === undefined || + frm.doc.arrival == null || + frm.doc.arrival === "" + ) { + frm.set_value("arrival", format_date_to_string_arrival(expected_arrival)); + } + if ( + frm.doc.departure === undefined || + frm.doc.departure == null || + frm.doc.departure === "" + ) { + frm.set_value( + "departure", + format_date_to_string_arrival(expected_departure) + ); + } + if ( + frm.doc.actual_room_rate === undefined || + frm.doc.actual_room_rate == null || + parseFloat(frm.doc.actual_room_rate) == 0.0 + ) { + frm.set_value("actual_room_rate", frm.doc.init_actual_room_rate); + } + if ( + frm.doc.actual_room_id === undefined || + frm.doc.actual_room_id == null || + frm.doc.actual_room_id === "" + ) { + frappe.call({ + method: "inn.inn_hotels.doctype.inn_room.inn_room.get_room_status", + args: { + room_id: frm.doc.room_id, + }, + callback: (r) => { + if (r.message === "Vacant Ready") { + frm.set_value("actual_room_id", frm.doc.room_id); + } else { + get_available("actual_room_id", "Check In"); + frappe.msgprint( + "Currently, Room " + + frm.doc.room_id + + " status is not Vacant Ready. " + + "Please consult with Room Service or choose another Room to continue Checking In." + ); + } + }, + }); + } } function handle_filter_on_start_if_filled(frm) { - let start_date = formatDate(frm.doc.arrival ? frm.doc.arrival : frm.doc.expected_arrival); - let end_date = formatDate(frm.doc.departure ? frm.doc.departure : frm.doc.expected_departure); + let start_date = formatDate( + frm.doc.arrival ? frm.doc.arrival : frm.doc.expected_arrival + ); + let end_date = formatDate( + frm.doc.departure ? frm.doc.departure : frm.doc.expected_departure + ); - let query = { - "room_id": "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_available", - "actual_room_id": "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_available", - "room_type": "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_type_available", - "bed_type": "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_bed_type_available", - } + let query = { + room_id: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_available", + actual_room_id: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_available", + room_type: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_type_available", + bed_type: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_bed_type_available", + }; - let filters = { - "start": start_date, - "end": end_date, - "reference_name": frm.doc.name, - "room_type": frm.doc.room_type, - "bed_type": frm.doc.bed_type, - "phase": "" - } + let filters = { + start: start_date, + end: end_date, + reference_name: frm.doc.name, + room_type: frm.doc.room_type, + bed_type: frm.doc.bed_type, + phase: "", + }; - for (let fieldname of ["room_id", "actual_room_id", "room_type", "bed_type"]) { - frm.set_query(fieldname, function () { - return { - query: query[fieldname], - filters: filters - } - }) - } + for (let fieldname of [ + "room_id", + "actual_room_id", + "room_type", + "bed_type", + ]) { + frm.set_query(fieldname, function () { + return { + query: query[fieldname], + filters: filters, + }; + }); + } - // get room rate - frappe.db.get_value("Customer", frm.doc.customer_id, "customer_group", (customer) => { - let customer_group_list = ["All Customer Groups"] - customer_group_list.push(customer.customer_group) - - frm.set_query("room_rate", function () { - return { - filters: [ - ['Inn Room Rate', 'room_type', '=', frm.doc.room_type], - ['Inn Room Rate', 'is_disabled', '=', 0], - ['Inn Room Rate', 'customer_group', 'in', customer_group_list], - ['Inn Room Rate', 'from_date', '<=', start_date], - ['Inn Room Rate', 'to_date', '>=', start_date], - ] - } - }) - - }) + // get room rate + frappe.db.get_value( + "Customer", + frm.doc.customer_id, + "customer_group", + (customer) => { + let customer_group_list = ["All Customer Groups"]; + customer_group_list.push(customer.customer_group); + frm.set_query("room_rate", function () { + return { + filters: [ + ["Inn Room Rate", "room_type", "=", frm.doc.room_type], + ["Inn Room Rate", "is_disabled", "=", 0], + ["Inn Room Rate", "customer_group", "in", customer_group_list], + ["Inn Room Rate", "from_date", "<=", start_date], + ["Inn Room Rate", "to_date", ">=", start_date], + ], + }; + }); + } + ); } // Function to adjust dropdown shown in cascading dropdown: room_type, bed_type, room_id/actual_room_id function manage_filters(fieldname, phase, start_date) { - console.log("masuk manage_filters from " + fieldname); - let room_chooser = 'room_id'; - if (phase === 'Check In') { - room_chooser = 'actual_room_id'; - } - else if (cur_frm.doc.status !== 'Reserved') { - room_chooser = 'actual_room_id'; - } - else { - room_chooser = 'room_id'; - } + console.log("masuk manage_filters from " + fieldname); + let room_chooser = "room_id"; + if (phase === "Check In") { + room_chooser = "actual_room_id"; + } else if (cur_frm.doc.status !== "Reserved") { + room_chooser = "actual_room_id"; + } else { + room_chooser = "room_id"; + } - if (fieldname === 'room_type') { - cur_frm.set_value('bed_type', null); - cur_frm.set_value(room_chooser, null); - get_available('bed_type', phase); - get_available(room_chooser, phase); - get_room_rate(start_date); - } - else if (fieldname === 'bed_type') { - cur_frm.set_value(room_chooser, null); - get_available(room_chooser, phase); - get_room_rate(start_date); - } - else if (fieldname === 'actual_room_id') { - get_available(room_chooser, phase); - if (cur_frm.doc.actual_room_id !== undefined) { - frappe.db.get_value('Inn Room', cur_frm.doc.actual_room_id, ['room_type', 'bed_type'], function (r) { - cur_frm.doc.room_type = r.room_type; - cur_frm.doc.bed_type = r.bed_type; - cur_frm.refresh(); - get_available('room_type', phase); - get_available('bed_type', phase); - get_room_rate(start_date); - }); - } - } - else if (fieldname === 'room_id') { - get_available(room_chooser, phase); - if (cur_frm.doc.room_id !== undefined) { - frappe.db.get_value('Inn Room', cur_frm.doc.room_id, ['room_type', 'bed_type'], function (r) { - cur_frm.doc.room_type = r.room_type; - cur_frm.doc.bed_type = r.bed_type; - cur_frm.refresh(); - get_available('room_type', phase); - get_available('bed_type', phase); - get_room_rate(start_date); - }); - } - } - else { - - } + if (fieldname === "room_type") { + cur_frm.set_value("bed_type", null); + cur_frm.set_value(room_chooser, null); + get_available("bed_type", phase); + get_available(room_chooser, phase); + get_room_rate(start_date); + } else if (fieldname === "bed_type") { + cur_frm.set_value(room_chooser, null); + get_available(room_chooser, phase); + get_room_rate(start_date); + } else if (fieldname === "actual_room_id") { + get_available(room_chooser, phase); + if (cur_frm.doc.actual_room_id !== undefined) { + frappe.db.get_value( + "Inn Room", + cur_frm.doc.actual_room_id, + ["room_type", "bed_type"], + function (r) { + cur_frm.doc.room_type = r.room_type; + cur_frm.doc.bed_type = r.bed_type; + cur_frm.refresh(); + get_available("room_type", phase); + get_available("bed_type", phase); + get_room_rate(start_date); + } + ); + } + } else if (fieldname === "room_id") { + get_available(room_chooser, phase); + if (cur_frm.doc.room_id !== undefined) { + frappe.db.get_value( + "Inn Room", + cur_frm.doc.room_id, + ["room_type", "bed_type"], + function (r) { + cur_frm.doc.room_type = r.room_type; + cur_frm.doc.bed_type = r.bed_type; + cur_frm.refresh(); + get_available("room_type", phase); + get_available("bed_type", phase); + get_room_rate(start_date); + } + ); + } + } else { + } } // Function to get available room/room_type/bed_type based on a period of time (start -> end) function get_available(fieldname, phase) { - let field = cur_frm.fields_dict[fieldname]; - let reference_name = cur_frm.doc.name; - let start = undefined; - let end = undefined; + let field = cur_frm.fields_dict[fieldname]; + let reference_name = cur_frm.doc.name; + let start = undefined; + let end = undefined; - if (phase === 'Check In') { - start = formatDate(cur_frm.doc.arrival); - end = formatDate(cur_frm.doc.departure); - } - else { - start = cur_frm.doc.expected_arrival; - end = cur_frm.doc.expected_departure; - } + if (phase === "Check In") { + start = formatDate(cur_frm.doc.arrival); + end = formatDate(cur_frm.doc.departure); + } else { + start = cur_frm.doc.expected_arrival; + end = cur_frm.doc.expected_departure; + } - let query = ''; - if (fieldname === 'room_id' || fieldname === 'actual_room_id') { - query = 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_available'; - } - else if (fieldname === 'room_type') { - query = 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_type_available'; - } - else if (fieldname === 'bed_type') { - query = 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_bed_type_available'; - } - console.log("query " + query); - field.get_query = function () { - return { - query: query, - filters: { - 'start': start, - 'end': end, - 'reference_name': reference_name, - 'room_type': cur_frm.doc.room_type, - 'bed_type': cur_frm.doc.bed_type, - 'phase': phase - } - } - } + let query = ""; + if (fieldname === "room_id" || fieldname === "actual_room_id") { + query = + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_available"; + } else if (fieldname === "room_type") { + query = + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_type_available"; + } else if (fieldname === "bed_type") { + query = + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_bed_type_available"; + } + console.log("query " + query); + field.get_query = function () { + return { + query: query, + filters: { + start: start, + end: end, + reference_name: reference_name, + room_type: cur_frm.doc.room_type, + bed_type: cur_frm.doc.bed_type, + phase: phase, + }, + }; + }; } // Function to format date to Date formatted to YYYY-MM-DD function formatDate(date) { - var d = new Date(date), - month = '' + (d.getMonth() + 1), - day = '' + d.getDate(), - year = d.getFullYear(); + var d = new Date(date), + month = "" + (d.getMonth() + 1), + day = "" + d.getDate(), + year = d.getFullYear(); - if (month.length < 2) - month = '0' + month; - if (day.length < 2) - day = '0' + day; + if (month.length < 2) month = "0" + month; + if (day.length < 2) day = "0" + day; - return [year, month, day].join('-'); + return [year, month, day].join("-"); } // Function to get maximum active card allowed to issued in one reservation function get_room_max_active_card() { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_key_card.inn_key_card.room_max_active_card', - callback: (r) => { - if (r.message) { - room_max_active_card = r.message; - console.log("rmesej = " + room_max_active_card); - } - } - }); + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_key_card.inn_key_card.room_max_active_card", + callback: (r) => { + if (r.message) { + room_max_active_card = r.message; + console.log("rmesej = " + room_max_active_card); + } + }, + }); } // Function to erase the priviledge of key card to open room door function erase_card(flag, card_name) { - console.log('card_name = ' + card_name); - let yesterday = new Date(new Date().setDate(new Date().getDate() - 1)); - console.log(yesterday); - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_key_card.inn_key_card.erase_card', - args: { - flag: flag, - card_name: card_name, - expiration_date: formatDate(yesterday) - }, - callback: (r) => { - if (r.message === 'ERROR') { - frappe.msgprint("Error Erasing Card, Please Redo the Process.") - } - else if (r.message === 0) { - cur_frm.reload_doc(); - if (flag === 'with') { - frappe.show_alert(__("Card Erased.")); return; - } - else if (flag === 'without') { - frappe.show_alert(__("Card Deactivated")); return; - } - } - } - }); + console.log("card_name = " + card_name); + let yesterday = new Date(new Date().setDate(new Date().getDate() - 1)); + console.log(yesterday); + frappe.call({ + method: "inn.inn_hotels.doctype.inn_key_card.inn_key_card.erase_card", + args: { + flag: flag, + card_name: card_name, + expiration_date: formatDate(yesterday), + }, + callback: (r) => { + if (r.message === "ERROR") { + frappe.msgprint("Error Erasing Card, Please Redo the Process."); + } else if (r.message === 0) { + cur_frm.reload_doc(); + if (flag === "with") { + frappe.show_alert(__("Card Erased.")); + return; + } else if (flag === "without") { + frappe.show_alert(__("Card Deactivated")); + return; + } + } + }, + }); } // Function to get list of Room Rate in Room Rate Dropdown. // Filtered by room_type selected and the start date of reservation function get_room_rate(start_date) { - console.log("masuk get_Room_rate"); - let field = cur_frm.fields_dict['room_rate']; - let room_type = cur_frm.doc.room_type; + console.log("masuk get_Room_rate"); + let field = cur_frm.fields_dict["room_rate"]; + let room_type = cur_frm.doc.room_type; - if (room_type !== undefined) { - frappe.db.get_value("Customer", cur_frm.doc.customer_id, "customer_group", (customer) => { - let customer_group_list = ['All Customer Groups']; - customer_group_list.push(customer.customer_group); - console.log("filters: "); - console.log("room_type = " + room_type); - console.log("customer_group_list = " + customer_group_list); - console.log("start_date = " + start_date); - field.get_query = function () { - return { - filters: [ - ['Inn Room Rate', 'room_type', '=', room_type], - ['Inn Room Rate', 'is_disabled', '=', 0], - ['Inn Room Rate', 'customer_group', 'in', customer_group_list], - ['Inn Room Rate', 'from_date', '<=', start_date], - ['Inn Room Rate', 'to_date', '>=', start_date], - ] - } - } - }); - } - else { - let query = []; - field.get_query = function () { - return { - filters: query - } - } - } + if (room_type !== undefined) { + frappe.db.get_value( + "Customer", + cur_frm.doc.customer_id, + "customer_group", + (customer) => { + let customer_group_list = ["All Customer Groups"]; + customer_group_list.push(customer.customer_group); + console.log("filters: "); + console.log("room_type = " + room_type); + console.log("customer_group_list = " + customer_group_list); + console.log("start_date = " + start_date); + field.get_query = function () { + return { + filters: [ + ["Inn Room Rate", "room_type", "=", room_type], + ["Inn Room Rate", "is_disabled", "=", 0], + ["Inn Room Rate", "customer_group", "in", customer_group_list], + ["Inn Room Rate", "from_date", "<=", start_date], + ["Inn Room Rate", "to_date", ">=", start_date], + ], + }; + }; + } + ); + } else { + let query = []; + field.get_query = function () { + return { + filters: query, + }; + }; + } } // Function to make form disabled if certain status of reservation is achieved function make_read_only(frm) { - let active_flag = 0; - if (frm.doc.status === 'Cancel' || frm.doc.status === 'Finish' || frm.doc.status === 'No Show') { - frm.disable_save(); - active_flag = 1; - } - else { - frm.enable_save(); - active_flag = 0; - } + let active_flag = 0; + if ( + frm.doc.status === "Cancel" || + frm.doc.status === "Finish" || + frm.doc.status === "No Show" + ) { + frm.disable_save(); + active_flag = 1; + } else { + frm.enable_save(); + active_flag = 0; + } - frm.set_df_property('init_actual_room_rate', 'hidden', 1); - frm.set_df_property('type', 'read_only', active_flag); - frm.set_df_property('channel', 'read_only', active_flag); - frm.set_df_property('group_id', 'read_only', active_flag); - frm.set_df_property('guest_name', 'read_only', active_flag); - frm.set_df_property('arrival', 'read_only', active_flag); - frm.set_df_property('departure', 'read_only', active_flag); - frm.set_df_property('room_type', 'read_only', active_flag); - frm.set_df_property('bed_type', 'read_only', active_flag); - frm.set_df_property('room_rate', 'read_only', active_flag); - frm.set_df_property('actual_room_id', 'read_only', active_flag); - frm.set_df_property('actual_room_rate', 'read_only', active_flag); - frm.set_df_property('adult', 'read_only', active_flag); - frm.set_df_property('child', 'read_only', active_flag); - frm.set_df_property('extra_bed', 'read_only', active_flag); - frm.set_df_property('sb4', 'hidden', active_flag); + frm.set_df_property("init_actual_room_rate", "hidden", 1); + frm.set_df_property("type", "read_only", active_flag); + frm.set_df_property("channel", "read_only", active_flag); + frm.set_df_property("group_id", "read_only", active_flag); + frm.set_df_property("guest_name", "read_only", active_flag); + frm.set_df_property("arrival", "read_only", active_flag); + frm.set_df_property("departure", "read_only", active_flag); + frm.set_df_property("room_type", "read_only", active_flag); + frm.set_df_property("bed_type", "read_only", active_flag); + frm.set_df_property("room_rate", "read_only", active_flag); + frm.set_df_property("actual_room_id", "read_only", active_flag); + frm.set_df_property("actual_room_rate", "read_only", active_flag); + frm.set_df_property("adult", "read_only", active_flag); + frm.set_df_property("child", "read_only", active_flag); + frm.set_df_property("extra_bed", "read_only", active_flag); + frm.set_df_property("sb4", "hidden", active_flag); } // Function to check out reservation function process_check_out(frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_folio.inn_folio.get_balance_by_reservation', - args: { - reservation_id: frm.doc.name - }, - callback: (r) => { - if (r.message !== 0) { - frappe.msgprint('There are several outstanding payments.
        ' + - 'Please go to the Folio page to complete payment process before Checking Out'); - } - else if (r.message == 0) { - let current_active_card = 0; - let all_issued_card = frm.doc.issued_card; - for (let key in all_issued_card) { - current_active_card += all_issued_card[key].is_active; - } - if (current_active_card > 0) { - frappe.msgprint("There are " + current_active_card + " key card(s) still active.
        " + - " Please Deactivate all key cards issued before Checking Out"); - } - else { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.check_out_reservation', - args: { - reservation_id: frm.doc.name, - }, - callback: (r) => { - if (r.message == 'Finish') { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation', - args: { - reservation_id: frm.doc.name - }, - callback: (r) => { - if (r.message) { - console.log(r.message); - } - } - }); - frappe.set_route('Form', 'Inn Reservation', frm.doc.name); - frappe.show_alert('Successfully Check Out Reservation: ' + frm.doc.name); - } - else { - frappe.msgprint(r.message); - } - } - }); - } - } - } - }); + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_folio.inn_folio.get_balance_by_reservation", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message !== 0) { + frappe.msgprint( + "There are several outstanding payments.
        " + + "Please go to the Folio page to complete payment process before Checking Out" + ); + } else if (r.message == 0) { + let current_active_card = 0; + let all_issued_card = frm.doc.issued_card; + for (let key in all_issued_card) { + current_active_card += all_issued_card[key].is_active; + } + if (current_active_card > 0) { + frappe.msgprint( + "There are " + + current_active_card + + " key card(s) still active.
        " + + " Please Deactivate all key cards issued before Checking Out" + ); + } else { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.check_out_reservation", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message == "Finish") { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + console.log(r.message); + } + }, + }); + frappe.set_route("Form", "Inn Reservation", frm.doc.name); + frappe.show_alert( + "Successfully Check Out Reservation: " + frm.doc.name + ); + } else { + frappe.msgprint(r.message); + } + }, + }); + } + } + }, + }); } // Function to move reservation's room to another room function move_room(frm) { - var d = new frappe.ui.Dialog({ - title: __('Move Room'), - fields: [ - { - 'label': __('Reason for Room Changes'), - 'fieldname': 'mv_reason', - 'fieldtype': 'Small Text', - 'reqd': 1 - }, - { - 'label': __('Room Type'), - 'fieldname': 'mv_room_type', - 'fieldtype': 'Link', - 'options': 'Inn Room Type', - 'reqd': 1, - 'onchange': () => { - console.log('Milih room type'); - if (d.fields_dict['mv_room_type'].get_value() !== '') { - d.set_df_property('mv_bed_type', 'hidden', 0); - d.fields_dict['mv_bed_type'].get_query = function () { - return { - query: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_bed_type_available', - filters: { - 'start': formatDate(new Date()), - 'end': formatDate(frm.doc.departure), - 'reference_name': frm.doc.name, - 'room_type': d.fields_dict['mv_room_type'].get_value(), - 'bed_type': d.fields_dict['mv_bed_type'].get_value(), - 'phase': 'Check In' - } - } - } - } - } - }, - { - 'label': __('Bed Type'), - 'fieldname': 'mv_bed_type', - 'fieldtype': 'Link', - 'options': 'Inn Bed Type', - 'reqd': 1, - 'onchange': () => { - console.log("milih bed type"); - if (d.fields_dict['mv_bed_type'].get_value() !== '') { - d.set_df_property('mv_room_id', 'hidden', 0); - d.fields_dict['mv_room_id'].get_query = function () { - return { - query: 'inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_available', - filters: { - 'start': formatDate(new Date()), - 'end': formatDate(frm.doc.departure), - 'reference_name': frm.doc.name, - 'room_type': d.fields_dict['mv_room_type'].get_value(), - 'bed_type': d.fields_dict['mv_bed_type'].get_value(), - 'phase': 'Check In' - } - } - } - } - } - }, - { - 'label': __('Room ID'), - 'fieldname': 'mv_room_id', - 'fieldtype': 'Link', - 'options': 'Inn Room', - 'reqd': 1, - 'onchange': () => { - console.log('milih room id'); - frappe.db.get_value("Customer", frm.doc.customer_id, "customer_group", (customer) => { - let customer_group_list = ['All Customer Groups']; - customer_group_list.push(customer.customer_group); - d.fields_dict['mv_room_rate'].get_query = function () { - return { - filters: [ - ['Inn Room Rate', 'room_type', '=', d.fields_dict['mv_room_type'].get_value()], - ['Inn Room Rate', 'is_disabled', '=', 0], - ['Inn Room Rate', 'customer_group', 'in', customer_group_list], - ['Inn Room Rate', 'from_date', '<=', formatDate(new Date())], - ['Inn Room Rate', 'to_date', '>=', formatDate(new Date())], - ] - } - } - }); - } - }, - { - 'label': __('Change Room Rate'), - 'fieldname': 'mv_change_rate', - 'fieldtype': 'Check', - 'default': 0 - }, - { - 'label': __('Room Rate'), - 'fieldname': 'mv_room_rate', - 'fieldtype': 'Link', - 'options': 'Inn Room Rate', - 'depends_on': 'eval:doc.mv_change_rate==1', - 'onchange': () => { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room_rate.inn_room_rate.get_base_room_rate', - args: { - room_rate_id: d.get_values().mv_room_rate - }, - callback: (r) => { - if (r.message) { - d.set_value('mv_actual_room_rate', r.message); - } - } - }); - } - }, - { - 'label': __('Actual Room Rate Nominal'), - 'fieldname': 'mv_actual_room_rate', - 'fieldtype': 'Currency', - 'depends_on': 'eval:doc.mv_change_rate==1' - }, - ] - }); - d.set_primary_action(__('Move Room'), () => { - let new_room_rate = null; - let new_actual_room_rate = 0.0; - let good_to_go = 1; - if (d.get_values().mv_change_rate === 1) { - if (d.get_values().mv_room_rate === undefined || d.get_values().mv_room_rate === '' || - d.get_values().mv_actual_room_rate === undefined || d.get_values().mv_actual_room_rate === 0) { - frappe.msgprint("Change Rate is checked. Please fill Room Rate and Actual Room Rate Nominal"); - good_to_go = 0; - } - else { - new_room_rate = d.get_values().mv_room_rate; - new_actual_room_rate = d.get_values().mv_actual_room_rate; - } - } - if (good_to_go === 1) { - console.log(new_room_rate); - console.log(new_actual_room_rate); - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_move_room.inn_move_room.create_move_room_by_reservation', - args: { - reservation_id: frm.doc.name, - mv_room_type: d.get_values().mv_room_type, - mv_bed_type: d.get_values().mv_bed_type, - mv_room_id: d.get_values().mv_room_id, - mv_reason: d.get_values().mv_reason, - mv_change_rate: d.get_values().mv_change_rate, - mv_room_rate: new_room_rate, - mv_actual_room_rate: new_actual_room_rate - }, - callback: (r) => { - if (r.message === 1) { - frappe.msgprint('Successfully move room.'); - frm.reload_doc(); - } - } - }); - d.hide(); - } - }); - d.set_df_property('mv_bed_type', 'hidden', 1); - d.set_df_property('mv_room_id', 'hidden', 1); - d.show(); + var d = new frappe.ui.Dialog({ + title: __("Move Room"), + fields: [ + { + label: __("Reason for Room Changes"), + fieldname: "mv_reason", + fieldtype: "Small Text", + reqd: 1, + }, + { + label: __("Room Type"), + fieldname: "mv_room_type", + fieldtype: "Link", + options: "Inn Room Type", + reqd: 1, + onchange: () => { + console.log("Milih room type"); + if (d.fields_dict["mv_room_type"].get_value() !== "") { + d.set_df_property("mv_bed_type", "hidden", 0); + d.fields_dict["mv_bed_type"].get_query = function () { + return { + query: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_bed_type_available", + filters: { + start: formatDate(new Date()), + end: formatDate(frm.doc.departure), + reference_name: frm.doc.name, + room_type: d.fields_dict["mv_room_type"].get_value(), + bed_type: d.fields_dict["mv_bed_type"].get_value(), + phase: "Check In", + }, + }; + }; + } + }, + }, + { + label: __("Bed Type"), + fieldname: "mv_bed_type", + fieldtype: "Link", + options: "Inn Bed Type", + reqd: 1, + onchange: () => { + console.log("milih bed type"); + if (d.fields_dict["mv_bed_type"].get_value() !== "") { + d.set_df_property("mv_room_id", "hidden", 0); + d.fields_dict["mv_room_id"].get_query = function () { + return { + query: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_available", + filters: { + start: formatDate(new Date()), + end: formatDate(frm.doc.departure), + reference_name: frm.doc.name, + room_type: d.fields_dict["mv_room_type"].get_value(), + bed_type: d.fields_dict["mv_bed_type"].get_value(), + phase: "Check In", + }, + }; + }; + } + }, + }, + { + label: __("Room ID"), + fieldname: "mv_room_id", + fieldtype: "Link", + options: "Inn Room", + reqd: 1, + onchange: () => { + console.log("milih room id"); + frappe.db.get_value( + "Customer", + frm.doc.customer_id, + "customer_group", + (customer) => { + let customer_group_list = ["All Customer Groups"]; + customer_group_list.push(customer.customer_group); + d.fields_dict["mv_room_rate"].get_query = function () { + return { + filters: [ + [ + "Inn Room Rate", + "room_type", + "=", + d.fields_dict["mv_room_type"].get_value(), + ], + ["Inn Room Rate", "is_disabled", "=", 0], + [ + "Inn Room Rate", + "customer_group", + "in", + customer_group_list, + ], + [ + "Inn Room Rate", + "from_date", + "<=", + formatDate(new Date()), + ], + ["Inn Room Rate", "to_date", ">=", formatDate(new Date())], + ], + }; + }; + } + ); + }, + }, + { + label: __("Change Room Rate"), + fieldname: "mv_change_rate", + fieldtype: "Check", + default: 0, + }, + { + label: __("Room Rate"), + fieldname: "mv_room_rate", + fieldtype: "Link", + options: "Inn Room Rate", + depends_on: "eval:doc.mv_change_rate==1", + onchange: () => { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_rate.inn_room_rate.get_base_room_rate", + args: { + room_rate_id: d.get_values().mv_room_rate, + }, + callback: (r) => { + if (r.message) { + d.set_value("mv_actual_room_rate", r.message); + } + }, + }); + }, + }, + { + label: __("Actual Room Rate Nominal"), + fieldname: "mv_actual_room_rate", + fieldtype: "Currency", + depends_on: "eval:doc.mv_change_rate==1", + }, + ], + }); + d.set_primary_action(__("Move Room"), () => { + let new_room_rate = null; + let new_actual_room_rate = 0.0; + let good_to_go = 1; + if (d.get_values().mv_change_rate === 1) { + if ( + d.get_values().mv_room_rate === undefined || + d.get_values().mv_room_rate === "" || + d.get_values().mv_actual_room_rate === undefined || + d.get_values().mv_actual_room_rate === 0 + ) { + frappe.msgprint( + "Change Rate is checked. Please fill Room Rate and Actual Room Rate Nominal" + ); + good_to_go = 0; + } else { + new_room_rate = d.get_values().mv_room_rate; + new_actual_room_rate = d.get_values().mv_actual_room_rate; + } + } + if (good_to_go === 1) { + console.log(new_room_rate); + console.log(new_actual_room_rate); + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_move_room.inn_move_room.create_move_room_by_reservation", + args: { + reservation_id: frm.doc.name, + mv_room_type: d.get_values().mv_room_type, + mv_bed_type: d.get_values().mv_bed_type, + mv_room_id: d.get_values().mv_room_id, + mv_reason: d.get_values().mv_reason, + mv_change_rate: d.get_values().mv_change_rate, + mv_room_rate: new_room_rate, + mv_actual_room_rate: new_actual_room_rate, + }, + callback: (r) => { + if (r.message === 1) { + frappe.msgprint("Successfully move room."); + frm.reload_doc(); + } + }, + }); + d.hide(); + } + }); + d.set_df_property("mv_bed_type", "hidden", 1); + d.set_df_property("mv_room_id", "hidden", 1); + d.show(); } function calculate_rate_and_bill(frm) { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_reservation.inn_reservation.calculate_room_bill', - args: { - arrival: frm.doc.arrival, - departure: frm.doc.departure, - actual_rate: frm.doc.actual_room_rate - }, - callback: (r) => { - if (r.message) { - console.log(r.message); - frm.set_value('room_bill', r.message); - } - } - }); - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_room_rate.inn_room_rate.get_actual_room_rate_breakdown_check_commission', - args: { - room_rate_id: frm.doc.room_rate, - actual_rate: frm.doc.actual_room_rate, - reservation_id: frm.doc.name - }, - callback: (r) => { - if (r.message) { - frm.set_value('actual_room_rate_tax', r.message[0]); - frm.set_value('nett_actual_room_rate', r.message[1]); - frm.set_value('actual_breakfast_rate_tax', r.message[2]); - frm.set_value('nett_actual_breakfast_rate', r.message[3]); - } - } - }); + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.calculate_room_bill", + args: { + arrival: frm.doc.arrival, + departure: frm.doc.departure, + actual_rate: frm.doc.actual_room_rate, + }, + callback: (r) => { + if (r.message) { + console.log(r.message); + frm.set_value("room_bill", r.message); + } + }, + }); + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_rate.inn_room_rate.get_actual_room_rate_breakdown_check_commission", + args: { + room_rate_id: frm.doc.room_rate, + actual_rate: frm.doc.actual_room_rate, + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (r.message) { + frm.set_value("actual_room_rate_tax", r.message[0]); + frm.set_value("nett_actual_room_rate", r.message[1]); + frm.set_value("actual_breakfast_rate_tax", r.message[2]); + frm.set_value("nett_actual_breakfast_rate", r.message[3]); + } + }, + }); } function calculate_nights(arrival, departure) { - console.log("calculate_nights called"); - let date_arrival = new Date(arrival); - let date_departure = new Date(departure); - let normalized_arrival = date_arrival.setHours(0, 0, 0, 0); - let normalize_departure = date_departure.setHours(0, 0, 0, 0); - let diff = date_departure.getTime() - date_arrival.getTime(); - let days = diff / 86400000; - if (days < 1) { - days = 1; - } - console.log("total nights calculated = " + days); - return days; + console.log("calculate_nights called"); + let date_arrival = new Date(arrival); + let date_departure = new Date(departure); + let normalized_arrival = date_arrival.setHours(0, 0, 0, 0); + let normalize_departure = date_departure.setHours(0, 0, 0, 0); + let diff = date_departure.getTime() - date_arrival.getTime(); + let days = diff / 86400000; + if (days < 1) { + days = 1; + } + console.log("total nights calculated = " + days); + return days; } // Function to show pop up Dialog for checking validity of membership cards function check_membership_cards() { - let fields = [ - { - 'label': __('Card Number'), - 'fieldname': 'card_number', - 'fieldtype': 'Data', - 'reqd': 1 - }, - ]; - var d = new frappe.ui.Dialog({ - title: __('Check Membership Card'), - fields: fields, - }); - d.set_primary_action(__('Check'), () => { - frappe.call({ - method: 'inn.inn_hotels.doctype.inn_membership_card.inn_membership_card.check_card', - args: { - query: d.get_values().card_number - }, - callback: (r) => { - if (r.message) { - frappe.msgprint(r.message); - } - } - }); - d.hide(); - }); - d.show(); + let fields = [ + { + label: __("Card Number"), + fieldname: "card_number", + fieldtype: "Data", + reqd: 1, + }, + ]; + var d = new frappe.ui.Dialog({ + title: __("Check Membership Card"), + fields: fields, + }); + d.set_primary_action(__("Check"), () => { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_membership_card.inn_membership_card.check_card", + args: { + query: d.get_values().card_number, + }, + callback: (r) => { + if (r.message) { + frappe.msgprint(r.message); + } + }, + }); + d.hide(); + }); + d.show(); } function check_is_room_booking_already_created(frm) { - // if this is not saved yet, dont check this - frappe.call({ - method: "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_booking_name_by_reservation", - args: { - reservation_id: frm.doc.name, - }, - callback: (r) => { - if (!r.message) { - create_booking_room(frm) - } - } - }) + // if this is not saved yet, dont check this + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_room_booking_name_by_reservation", + args: { + reservation_id: frm.doc.name, + }, + callback: (r) => { + if (!r.message) { + create_booking_room(frm); + } + }, + }); } function create_booking_room(frm) { - frappe.call({ - metrhod: "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation", - args: { - reservation_id: frm.doc.name, - } - }) -} \ No newline at end of file + frappe.call({ + metrhod: + "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.update_by_reservation", + args: { + reservation_id: frm.doc.name, + }, + }); +} diff --git a/inn/inn_hotels/doctype/inn_room/inn_room.py b/inn/inn_hotels/doctype/inn_room/inn_room.py index ca55072d..701c9ff9 100644 --- a/inn/inn_hotels/doctype/inn_room/inn_room.py +++ b/inn/inn_hotels/doctype/inn_room/inn_room.py @@ -11,193 +11,239 @@ from datetime import date, timedelta from dateutil.parser import parse + class InnRoom(Document): - pass + pass + @frappe.whitelist() def get_max_floor(): - return frappe.db.get_single_value("Inn Hotels Setting", "number_of_floor") + return frappe.db.get_single_value("Inn Hotels Setting", "number_of_floor") + @frappe.whitelist() def copy_amenities_template(amenities_type_id): - amenities_list = frappe.get_all('Inn Amenities', filters={'parent': amenities_type_id}, fields=['*']) - return amenities_list + amenities_list = frappe.get_all( + "Inn Amenities", filters={"parent": amenities_type_id}, fields=["*"] + ) + return amenities_list def calculate_total_amenities_cost(doc, method): - amenities_list = doc.get('amenities') - total_cost = 0.0 - for item in amenities_list: - item_price = frappe.db.get_value('Item Price', - {'item_code': item.item, 'item_name': item.item, 'buying': 1}, - ['price_list_rate']) - total_cost += float(item_price) * float(item.qty) + amenities_list = doc.get("amenities") + total_cost = 0.0 + for item in amenities_list: + item_price = frappe.db.get_value( + "Item Price", + {"item_code": item.item, "item_name": item.item, "buying": 1}, + ["price_list_rate"], + ) + total_cost += float(item_price) * float(item.qty) - doc.total_amenities_cost = total_cost + doc.total_amenities_cost = total_cost @frappe.whitelist() def get_room_status(room_id): - return frappe.db.get_value('Inn Room', {'name': room_id}, "room_status") + return frappe.db.get_value("Inn Room", {"name": room_id}, "room_status") @frappe.whitelist() def get_all_inn_room(): - return frappe.db.get_all('Inn Room', - fields=['name', 'room_type', 'bed_type', 'allow_smoke', 'view', 'room_status'], - order_by='name asc') + return frappe.db.get_all( + "Inn Room", + fields=["name", "room_type", "bed_type", "allow_smoke", "view", "room_status"], + order_by="name asc", + ) + @frappe.whitelist() def update_room_status(rooms, mode): - is_failed = [] - is_housekeeping_assistant = False - is_housekeeping_supervisor = False - is_administrator = False - - # Fetch role names from Inn Hotels Setting - roles = frappe.get_doc("Inn Hotels Setting") - housekeeping_assistant_role = roles.housekeeping_assistant - housekeeping_supervisor_role = roles.housekeeping_supervisor - administrator_role = "Administrator" - - for role in frappe.get_roles(frappe.session.user): - if role == housekeeping_assistant_role: - is_housekeeping_assistant = True - elif role == housekeeping_supervisor_role: - is_housekeeping_supervisor = True - elif role == administrator_role: - is_administrator = True - - if mode == 'clean': - for room in json.loads(rooms): - door_status = frappe.db.get_value('Inn Room', room, 'door_status') - room_status = frappe.db.get_value('Inn Room', room, 'room_status') - - if door_status == 'No Status' or door_status == 'Sleeping Out': - if room_status == 'Vacant Dirty': - frappe.db.set_value('Inn Room', room, 'room_status', 'Vacant Clean') - elif room_status == 'Occupied Dirty': - frappe.db.set_value('Inn Room', room, 'room_status', 'Occupied Clean') - elif room_status == 'Vacant Clean' and (is_housekeeping_supervisor or is_housekeeping_assistant or is_administrator): - frappe.db.set_value('Inn Room', room, 'room_status', 'Vacant Ready') - else: - is_failed.append(room) - - if len(is_failed) > 0: - return 'Some Rooms status updated. Some room status cannot be updated: ' + str(is_failed) - else: - return ' All Room status updated successfully.' - elif mode == 'dirty': - for room in json.loads(rooms): - room_status = frappe.db.get_value('Inn Room', room, 'room_status') - - if room_status == 'Vacant Clean' or room_status == 'Vacant Ready': - frappe.db.set_value('Inn Room', room, 'room_status', 'Vacant Dirty') - elif room_status == 'Occupied Clean': - frappe.db.set_value('Inn Room', room, 'room_status', 'Occupied Dirty') - else: - is_failed.append(room) - - if len(is_failed) > 0: - return 'Some Rooms status updated. Some room status cannot be updated: ' + str(is_failed) - else: - return ' All Room status updated successfully.' + is_failed = [] + is_housekeeping_assistant = False + is_housekeeping_supervisor = False + is_administrator = False + + # Fetch role names from Inn Hotels Setting + roles = frappe.get_doc("Inn Hotels Setting") + housekeeping_assistant_role = roles.housekeeping_assistant + housekeeping_supervisor_role = roles.housekeeping_supervisor + administrator_role = "Administrator" + + for role in frappe.get_roles(frappe.session.user): + if role == housekeeping_assistant_role: + is_housekeeping_assistant = True + elif role == housekeeping_supervisor_role: + is_housekeeping_supervisor = True + elif role == administrator_role: + is_administrator = True + + if mode == "clean": + for room in json.loads(rooms): + door_status = frappe.db.get_value("Inn Room", room, "door_status") + room_status = frappe.db.get_value("Inn Room", room, "room_status") + + if door_status == "No Status" or door_status == "Sleeping Out": + if room_status == "Vacant Dirty": + frappe.db.set_value("Inn Room", room, "room_status", "Vacant Clean") + elif room_status == "Occupied Dirty": + frappe.db.set_value( + "Inn Room", room, "room_status", "Occupied Clean" + ) + elif room_status == "Vacant Clean" and ( + is_housekeeping_supervisor + or is_housekeeping_assistant + or is_administrator + ): + frappe.db.set_value("Inn Room", room, "room_status", "Vacant Ready") + else: + is_failed.append(room) + + if len(is_failed) > 0: + return ( + "Some Rooms status updated. Some room status cannot be updated: " + + str(is_failed) + ) + else: + return " All Room status updated successfully." + elif mode == "dirty": + for room in json.loads(rooms): + room_status = frappe.db.get_value("Inn Room", room, "room_status") + + if room_status == "Vacant Clean" or room_status == "Vacant Ready": + frappe.db.set_value("Inn Room", room, "room_status", "Vacant Dirty") + elif room_status == "Occupied Clean": + frappe.db.set_value("Inn Room", room, "room_status", "Occupied Dirty") + else: + is_failed.append(room) + + if len(is_failed) > 0: + return ( + "Some Rooms status updated. Some room status cannot be updated: " + + str(is_failed) + ) + else: + return " All Room status updated successfully." + @frappe.whitelist() def update_single_room_status(room, mode): - if mode not in ["clean", "dirty", "out"]: - raise ValueError("inappropriate value of mode") - - is_failed = False - is_housekeeping = False - is_housekeeping_assistant = False - is_housekeeping_supervisor = False - is_administrator = False - - # Fetch role names from Inn Hotels Setting - roles = frappe.get_doc("Inn Hotels Setting") - housekeeping_role = roles.housekeeping - housekeeping_assistant_role = roles.housekeeping_assistant - housekeeping_supervisor_role = roles.housekeeping_supervisor - administrator_role = "Administrator" - - for role in frappe.get_roles(frappe.session.user): - if role == housekeeping_role: - is_housekeeping = True - elif role == housekeeping_assistant_role: - is_housekeeping_assistant = True - elif role == housekeeping_supervisor_role: - is_housekeeping_supervisor = True - elif role == administrator_role: - is_administrator = True - - if mode == 'clean': - door_status = frappe.db.get_value('Inn Room', room, 'door_status') - room_status = frappe.db.get_value('Inn Room', room, 'room_status') - if door_status == 'No Status' or door_status == 'Sleeping Out': - if room_status == 'Vacant Dirty': - frappe.db.set_value('Inn Room', room, 'room_status', 'Vacant Clean') - elif room_status == 'Occupied Dirty': - frappe.db.set_value('Inn Room', room, 'room_status', 'Occupied Clean') - elif room_status == 'Vacant Clean': - if not is_housekeeping and (is_housekeeping_supervisor or is_housekeeping_assistant or is_administrator): - frappe.db.set_value('Inn Room', room, 'room_status', 'Vacant Ready') - else: - pass - else: - is_failed = True - - if is_failed: - return 'Room Status cannot be updated. Please try again.' - else: - return 'Room ' + room + ' Status updated successfully' - - elif mode == 'dirty': - room_status = frappe.db.get_value('Inn Room', room, 'room_status') - - if room_status == 'Vacant Clean' or room_status == 'Vacant Ready': - frappe.db.set_value('Inn Room', room, 'room_status', 'Vacant Dirty') - elif room_status == 'Occupied Clean': - frappe.db.set_value('Inn Room', room, 'room_status', 'Occupied Dirty') - else: - is_failed = True - - if is_failed: - return 'Room Status cannot be updated. Please try again.' - else: - return 'Room ' + room + ' Status updated successfully' - - elif mode == "out": - try: - last_out = frappe.get_last_doc(doctype="Inn Room Booking", filters={"room_id": room}, order_by="creation desc") - except DoesNotExistError as e: - last_out = None - - if last_out == None or last_out.status in ["Finished", "Canceled"]: - # if there is none found or the last is already finished or canceled, then make a new one - room_booking = frappe.new_doc("Inn Room Booking") - room_booking.start = date.today() - room_booking.end = date.today() + timedelta(days=1) - room_booking.room_availability = "Out of Order" - room_booking.note = "Set out of order by mobile from user: " + frappe.session.user - room_booking.room_id = room - room_booking.insert() - return "Room " + room + " Status updated successfully" - elif last_out.room_availability == "Stayed": - # if room is stayed, then room will be set to finish and room set to out of order - # frontdesk will give guest another room, not from mobile - last_out.status = "Finisehd" - last_out.save() - - room_booking = frappe.new_doc("Inn Room Booking") - room_booking.start = date.today() - room_booking.end = date.today() + timedelta(days=1) - room_booking.room_availability = "Out of Order" - room_booking.note = "Set out of order by mobile from user: " + frappe.session.user - room_booking.room_id = room - room_booking.insert() - - last_out.status = "Finished" - last_out.save() - - return "Room " + room + " Status updated successfully" \ No newline at end of file + if mode not in ["clean", "dirty", "out"]: + raise ValueError("inappropriate value of mode") + + is_failed = False + is_housekeeping = False + is_housekeeping_assistant = False + is_housekeeping_supervisor = False + is_administrator = False + + # Fetch role names from Inn Hotels Setting + roles = frappe.get_doc("Inn Hotels Setting") + housekeeping_role = roles.housekeeping + housekeeping_assistant_role = roles.housekeeping_assistant + housekeeping_supervisor_role = roles.housekeeping_supervisor + administrator_role = "Administrator" + for role in frappe.get_roles(frappe.session.user): + if role == housekeeping_role: + is_housekeeping = True + is_housekeeping_assistant = False + is_housekeeping_supervisor = False + is_administrator = False + elif role == housekeeping_assistant_role: + is_housekeeping_assistant = True + is_housekeeping = False + is_housekeeping_supervisor = False + is_administrator = False + elif role == housekeeping_supervisor_role: + is_housekeeping_assistant = False + is_housekeeping = False + is_housekeeping_supervisor = True + is_administrator = False + elif role == administrator_role: + is_administrator = True + is_housekeeping = False + is_housekeeping_assistant = False + is_housekeeping_supervisor = False + + if mode == "clean": + door_status = frappe.db.get_value("Inn Room", room, "door_status") + room_status = frappe.db.get_value("Inn Room", room, "room_status") + if door_status == "No Status" or door_status == "Sleeping Out": + if room_status == "Vacant Dirty": + frappe.db.set_value("Inn Room", room, "room_status", "Vacant Clean") + elif room_status == "Occupied Dirty": + frappe.db.set_value("Inn Room", room, "room_status", "Occupied Clean") + elif room_status == "Vacant Clean": + if not is_housekeeping and ( + is_housekeeping_supervisor + or is_housekeeping_assistant + or is_administrator + ): + frappe.db.set_value("Inn Room", room, "room_status", "Vacant Ready") + else: + pass + else: + is_failed = True + + if is_failed: + return "Room Status cannot be updated. Please try again." + else: + return "Room " + room + " Status updated successfully" + + elif mode == "dirty": + room_status = frappe.db.get_value("Inn Room", room, "room_status") + + if room_status == "Vacant Clean" or room_status == "Vacant Ready": + frappe.db.set_value("Inn Room", room, "room_status", "Vacant Dirty") + elif room_status == "Occupied Clean": + frappe.db.set_value("Inn Room", room, "room_status", "Occupied Dirty") + else: + is_failed = True + + if is_failed: + return "Room Status cannot be updated. Please try again." + else: + return "Room " + room + " Status updated successfully" + + elif mode == "out": + try: + last_out = frappe.get_last_doc( + doctype="Inn Room Booking", + filters={"room_id": room}, + order_by="creation desc", + ) + except DoesNotExistError as e: + last_out = None + + if last_out == None or last_out.status in ["Finished", "Canceled"]: + # if there is none found or the last is already finished or canceled, then make a new one + room_booking = frappe.new_doc("Inn Room Booking") + room_booking.start = date.today() + room_booking.end = date.today() + timedelta(days=1) + room_booking.room_availability = "Out of Order" + room_booking.note = ( + "Set out of order by mobile from user: " + frappe.session.user + ) + room_booking.room_id = room + room_booking.insert() + return "Room " + room + " Status updated successfully" + elif last_out.room_availability == "Stayed": + # if room is stayed, then room will be set to finish and room set to out of order + # frontdesk will give guest another room, not from mobile + last_out.status = "Finisehd" + last_out.save() + + room_booking = frappe.new_doc("Inn Room Booking") + room_booking.start = date.today() + room_booking.end = date.today() + timedelta(days=1) + room_booking.room_availability = "Out of Order" + room_booking.note = ( + "Set out of order by mobile from user: " + frappe.session.user + ) + room_booking.room_id = room + room_booking.insert() + + last_out.status = "Finished" + last_out.save() + + return "Room " + room + " Status updated successfully" From e97462a5f147c25462bfcf651c0426d18c681e1e Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Wed, 29 Jan 2025 10:18:03 +0200 Subject: [PATCH 11/22] [Fix]: The Pos Error and added the report --- inn/__init__.py | 2 +- .../inn_hotels_setting.json | 2 +- .../page/pos_extended/pos_extended.py | 160 ++++++++++++++---- .../report/room_occupation/__init__.py | 0 .../report/room_occupation/room_occupation.js | 67 ++++++++ .../room_occupation/room_occupation.json | 45 +++++ .../report/room_occupation/room_occupation.py | 107 ++++++++++++ 7 files changed, 348 insertions(+), 35 deletions(-) create mode 100644 inn/inn_hotels/report/room_occupation/__init__.py create mode 100644 inn/inn_hotels/report/room_occupation/room_occupation.js create mode 100644 inn/inn_hotels/report/room_occupation/room_occupation.json create mode 100644 inn/inn_hotels/report/room_occupation/room_occupation.py diff --git a/inn/__init__.py b/inn/__init__.py index d268aa9e..83e779e1 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = "1.1.5" +__version__ = "1.1.6" diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index 0d9587f3..eadde9ab 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -765,7 +765,7 @@ ], "issingle": 1, "links": [], - "modified": "2025-01-28 11:14:31.420714", + "modified": "2025-01-29 09:01:00.179629", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/page/pos_extended/pos_extended.py b/inn/inn_hotels/page/pos_extended/pos_extended.py index 964c91dc..e2fedd40 100644 --- a/inn/inn_hotels/page/pos_extended/pos_extended.py +++ b/inn/inn_hotels/page/pos_extended/pos_extended.py @@ -9,6 +9,7 @@ NEW_ORDER = 1 + @frappe.whitelist() def save_pos_usage(invoice_name, action, table=None): if action not in ["save_draft", "print_captain", "print_table", "save_submit"]: @@ -29,7 +30,9 @@ def save_pos_usage(invoice_name, action, table=None): new = True else: - doc = frappe.get_last_doc("Inn POS Usage", filters={"pos_invoice": invoice_name}) + doc = frappe.get_last_doc( + "Inn POS Usage", filters={"pos_invoice": invoice_name} + ) # move table if doc.table != table: if doc.table != "" and doc.table is not None: @@ -44,7 +47,11 @@ def save_pos_usage(invoice_name, action, table=None): doc_table.save() # mainly change state except when flow repeated, will move tracked item to processed item and add new item to tracked item - if action in ["save_draft", "print_captain"] and doc.print_status == PRINT_STATUS_TABLE and not new: + if ( + action in ["save_draft", "print_captain"] + and doc.print_status == PRINT_STATUS_TABLE + and not new + ): # case if customer wants to add the order # then new item will be added to processed item # then new item will be empty to reset the tracked item @@ -80,9 +87,14 @@ def save_pos_usage(invoice_name, action, table=None): if action in ["save_draft", "print_captain"]: # add untracked child - all_item = frappe.db.get_values(doctype="POS Invoice Item", filters={"parenttype": "POS Invoice", "parent": invoice_name}, fieldname=["item_name", "qty"], as_dict=True) - - if 'tracked_item' not in locals(): + all_item = frappe.db.get_values( + doctype="POS Invoice Item", + filters={"parenttype": "POS Invoice", "parent": invoice_name}, + fieldname=["item_name", "qty"], + as_dict=True, + ) + + if "tracked_item" not in locals(): tracked_item = {x.item_name: x for x in doc.processed_item} new_item_name = {item.item_name: item for item in doc.new_item} @@ -125,13 +137,22 @@ def save_pos_usage(invoice_name, action, table=None): return {"message": "success"} + @frappe.whitelist() def get_table_number(invoice_name): - return frappe.db.get_value(doctype="Inn POS Usage", filters={"pos_invoice": invoice_name}, fieldname=["table", "transfer_to_folio"], as_dict=True) + return frappe.db.get_value( + doctype="Inn POS Usage", + filters={"pos_invoice": invoice_name}, + fieldname=["table", "transfer_to_folio"], + as_dict=True, + ) + @frappe.whitelist() def clean_table_number(invoice_name): - table_name = frappe.get_last_doc(doctype="Inn POS Usage", filters={"pos_invoice": invoice_name}) + table_name = frappe.get_last_doc( + doctype="Inn POS Usage", filters={"pos_invoice": invoice_name} + ) table_name.print_status = ORDER_FINISHED table_name.save() @@ -141,13 +162,20 @@ def clean_table_number(invoice_name): doc_table.save() return + @frappe.whitelist() def transfer_to_folio(invoice_doc, folio_name): invoice_doc = json.loads(invoice_doc) - if not frappe.db.exists({"doctype": "Inn POS Usage", "pos_invoice": invoice_doc["name"]}): - raise ValueError("save this transaction as draft first or print a captain order") - - pos_usage = frappe.get_last_doc("Inn POS Usage", filters={"pos_invoice": invoice_doc["name"]}) + if not frappe.db.exists( + {"doctype": "Inn POS Usage", "pos_invoice": invoice_doc["name"]} + ): + raise ValueError( + "save this transaction as draft first or print a captain order" + ) + + pos_usage = frappe.get_last_doc( + "Inn POS Usage", filters={"pos_invoice": invoice_doc["name"]} + ) pos_usage.transfer_to_folio = folio_name pos_usage.save() @@ -161,26 +189,45 @@ def transfer_to_folio(invoice_doc, folio_name): } # Create Inn Folio Transaction Bundle - ftb_doc = frappe.new_doc('Inn Folio Transaction Bundle') - ftb_doc.transaction_type = 'Restaurant Transfer Charges' + ftb_doc = frappe.new_doc("Inn Folio Transaction Bundle") + ftb_doc.transaction_type = "Restaurant Transfer Charges" ftb_doc.insert() - idx = frappe.get_all('Inn Folio Transaction', filters={'parent': folio_name, 'parenttype': 'Inn Folio', 'parentfield': 'folio_transaction'}) + idx = frappe.get_all( + "Inn Folio Transaction", + filters={ + "parent": folio_name, + "parenttype": "Inn Folio", + "parentfield": "folio_transaction", + }, + ) idx = len(idx) # Create folio transaction restaurant charge - food_remark = 'Transfer Restaurant Food Charges from POS Order: ' + invoice_doc["name"] - create_folio_trx(invoice_doc["name"], folio_name, invoice_doc["net_total"], transaction_types["restaurant_food"], ftb_doc, food_remark, idx) + food_remark = ( + "Transfer Restaurant Food Charges from POS Order: " + invoice_doc["name"] + ) + create_folio_trx( + invoice_doc["name"], + folio_name, + invoice_doc["net_total"], + transaction_types["restaurant_food"], + ftb_doc, + food_remark, + idx, + ) idx = idx + 1 # Create folio transaction restaurant tax and service - guest_account_receivable = frappe.db.get_single_value("Inn Hotels Setting", "guest_account_receivable") + guest_account_receivable = frappe.db.get_single_value( + "Inn Hotels Setting", "guest_account_receiveable" + ) # Dynamic tax types and remarks tax_type = [transaction_types["fbs_service_10"], transaction_types["fbs_tax_11"]] remarks = [ - 'Service of Transfer Restaurant Charges from POS Order: ' + invoice_doc["name"], - 'Tax of Transfer Restaurant Charges from POS Order: ' + invoice_doc["name"] + "Service of Transfer Restaurant Charges from POS Order: " + invoice_doc["name"], + "Tax of Transfer Restaurant Charges from POS Order: " + invoice_doc["name"], ] if len(invoice_doc["taxes"]) == 1: @@ -190,26 +237,67 @@ def transfer_to_folio(invoice_doc, folio_name): for ii in range(len(invoice_doc["taxes"])): taxe = invoice_doc["taxes"][ii] - create_folio_trx(invoice_doc["name"], folio_name, taxe["tax_amount_after_discount_amount"], tax_type[ii], ftb_doc, remarks[ii], idx, guest_account_receivable, taxe["account_head"]) + create_folio_trx( + invoice_doc["name"], + folio_name, + taxe["tax_amount_after_discount_amount"], + tax_type[ii], + ftb_doc, + remarks[ii], + idx, + guest_account_receivable, + taxe["account_head"], + ) idx = idx + 1 if "rounding_adjustment" in invoice_doc and invoice_doc["rounding_adjustment"] != 0: - roundoff_remark = 'Rounding off Amount of Transfer Restaurant Charges from Restaurant Order: ' + invoice_doc["name"] - create_folio_trx(invoice_doc["name"], folio_name, invoice_doc["rounding_adjustment"], transaction_types["round_off"], ftb_doc, roundoff_remark, idx, guest_account_receivable) + roundoff_remark = ( + "Rounding off Amount of Transfer Restaurant Charges from Restaurant Order: " + + invoice_doc["name"] + ) + create_folio_trx( + invoice_doc["name"], + folio_name, + invoice_doc["rounding_adjustment"], + transaction_types["round_off"], + ftb_doc, + roundoff_remark, + idx, + guest_account_receivable, + ) ftb_doc.save() remove_pos_invoice_bill(invoice_doc["name"], folio_name) -def create_folio_trx(invoice_name, folio, amount, type, ftb_doc, remark, index, debit_account=None, credit_account=None): + +def create_folio_trx( + invoice_name, + folio, + amount, + type, + ftb_doc, + remark, + index, + debit_account=None, + credit_account=None, +): if credit_account is None: - credit_account = frappe.get_value('Inn Folio Transaction Type', filters={"name": type}, fieldname="credit_account") + credit_account = frappe.get_value( + "Inn Folio Transaction Type", + filters={"name": type}, + fieldname="credit_account", + ) if debit_account is None: - debit_account = frappe.get_value('Inn Folio Transaction Type', filters={"name": type}, fieldname="debit_account") + debit_account = frappe.get_value( + "Inn Folio Transaction Type", + filters={"name": type}, + fieldname="debit_account", + ) # Create Inn Folio Transaction - new_doc = frappe.new_doc('Inn Folio Transaction') - new_doc.flag = 'Debit' + new_doc = frappe.new_doc("Inn Folio Transaction") + new_doc.flag = "Debit" new_doc.is_void = 0 new_doc.idx = index new_doc.transaction_type = type @@ -219,16 +307,17 @@ def create_folio_trx(invoice_name, folio, amount, type, ftb_doc, remark, index, new_doc.credit_account = credit_account new_doc.remark = remark new_doc.parent = folio - new_doc.parenttype = 'Inn Folio' - new_doc.parentfield = 'folio_transaction' + new_doc.parenttype = "Inn Folio" + new_doc.parentfield = "folio_transaction" new_doc.ftb_id = ftb_doc.name new_doc.insert() # Create Inn Folio Transaction Bundle Detail - ftbd_doc = frappe.new_doc('Inn Folio Transaction Bundle Detail') + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") ftbd_doc.transaction_type = new_doc.transaction_type ftbd_doc.transaction_id = new_doc.name - ftb_doc.append('transaction_detail', ftbd_doc) + ftb_doc.append("transaction_detail", ftbd_doc) + def remove_pos_invoice_bill(invoice_name: str, folio_name: str): pos_invoice = frappe.get_doc("POS Invoice", invoice_name) @@ -241,5 +330,10 @@ def remove_pos_invoice_bill(invoice_name: str, folio_name: str): frappe.db.set_value("POS Invoice", invoice_name, "rounded_total", 0) frappe.db.set_value("POS Invoice", invoice_name, "in_words", 0) frappe.db.set_value("POS Invoice", invoice_name, "paid_amount", 0) - frappe.db.set_value("POS Invoice", invoice_name, "consolidated_invoice", f"Transferred to {folio_name}") - frappe.db.set_value("POS Invoice", invoice_name, "status", "Consolidated") \ No newline at end of file + frappe.db.set_value( + "POS Invoice", + invoice_name, + "consolidated_invoice", + f"Transferred to {folio_name}", + ) + frappe.db.set_value("POS Invoice", invoice_name, "status", "Consolidated") diff --git a/inn/inn_hotels/report/room_occupation/__init__.py b/inn/inn_hotels/report/room_occupation/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/inn/inn_hotels/report/room_occupation/room_occupation.js b/inn/inn_hotels/report/room_occupation/room_occupation.js new file mode 100644 index 00000000..9bed2004 --- /dev/null +++ b/inn/inn_hotels/report/room_occupation/room_occupation.js @@ -0,0 +1,67 @@ +// Copyright (c) 2025, Core Initiative and contributors +// For license information, please see license.txt + +const STATUS = { + RS: "#1f78b4", + UC: "#fb9a99", + OU: "#ff7f00", + OO: "#e31a1c", + HU: "#fdbf6f", + RC: "#a6cee3", + AV: "#33a02c", +}; + +frappe.query_reports["Room Occupation"] = { + filters: [ + { + fieldname: "start_date", + label: __("Start Date"), + fieldtype: "Date", + reqd: 1, + default: frappe.datetime.month_start(), + on_change(query_report) { + validate_filter(query_report); + }, + }, + { + fieldname: "end_date", + label: __("End Date"), + fieldtype: "Date", + reqd: 1, + default: frappe.datetime.month_end(), + on_change(query_report) { + validate_filter(query_report); + }, + }, + ], + + formatter: function (value, row, column, data, default_formatter) { + let iconHTML = ""; + let color = "black"; + value = default_formatter(value, row, column, data); + + switch (column.fieldname) { + case "type": + iconHTML = ``; + break; + default: + color = STATUS[value]; + iconHTML = ``; + + return `${iconHTML} ${ + value !== "" ? value : "N/A" + }`; + } + return `${iconHTML} ${ + value !== "" ? value : "N/A" + }`; + }, +}; + +function validate_filter(query_report) { + let { start_date, end_date } = query_report.previous_filters; + if (start_date >= end_date) { + query_report.set_filter_value("end_date", ""); + frappe.throw(__("End date cannot before start date")); + } +} diff --git a/inn/inn_hotels/report/room_occupation/room_occupation.json b/inn/inn_hotels/report/room_occupation/room_occupation.json new file mode 100644 index 00000000..cf1c4b2d --- /dev/null +++ b/inn/inn_hotels/report/room_occupation/room_occupation.json @@ -0,0 +1,45 @@ +{ + "add_total_row": 0, + "columns": [], + "creation": "2025-01-28 14:24:52.220571", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "letterhead": null, + "modified": "2025-01-28 14:24:52.220571", + "modified_by": "Administrator", + "module": "Inn Hotels", + "name": "Room Occupation", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Inn Room Booking", + "report_name": "Room Occupation", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "Housekeeping" + }, + { + "role": "Housekeeping Assistant" + }, + { + "role": "Accounts User" + }, + { + "role": "Accounts Manager" + }, + { + "role": "Hotel Reservation User" + }, + { + "role": "Hotel Manager" + } + ], + "timeout": 0 +} \ No newline at end of file diff --git a/inn/inn_hotels/report/room_occupation/room_occupation.py b/inn/inn_hotels/report/room_occupation/room_occupation.py new file mode 100644 index 00000000..6b0647b4 --- /dev/null +++ b/inn/inn_hotels/report/room_occupation/room_occupation.py @@ -0,0 +1,107 @@ +# Copyright (c) 2025, Core Initiative and contributors +# For license information, please see license.txt + +# import frappe + +import frappe +from dateutil.parser import parse +from datetime import timedelta, datetime +from inn.helper.daterange import daterange + +FORMAT_DATE = "%Y-%m-%d" + +STATUS = { + "Room Sold": "RS", # #1f78b4 + "Under Construction": "UC", ##fb9a99 + "Office Use": "OU", # #ff7f00 + "Out of Order": "OO", # #e31a1c + "House Use": "HU", # #fdbf6f + "Room Compliment": "RC", # #a6cee3 + "Available": "AV", # #33a02c +} + + +def get_column(start_date: datetime, date_length: datetime): + column = [ + { + "fieldname": "type", + "label": "Room Type", + "fieldtype": "Data", + "width": 150, + } + ] + + for day in range(date_length + 1): + column.append( + { + "fieldname": (start_date + timedelta(days=day)).strftime(FORMAT_DATE), + "label": (start_date + timedelta(days=day)).strftime(FORMAT_DATE), + "fieldtype": "Data", + "width": 130, + } + ) + + return column + + +def get_data(filters): + start_date = parse(filters.start_date) + end_date = parse(filters.end_date) + + if start_date >= end_date: + raise ValueError("end date cannot before start date") + + sql = f""" + SELECT + rb.start, + rb.end, + rb.room_id, + rb.room_availability, + rb.note, + rb.reference_type, + rb.reference_name, + rb.status, + r.room_type + FROM `tabInn Room Booking` rb + LEFT JOIN `tabInn Room` r on rb.room_id = r.name + """ + + reservations = frappe.db.sql(sql, as_dict=1) + + result = {} + for booking in reservations: + if booking.room_id not in result: + result[booking.room_id] = { + "type": booking.room_id, + } + for date in daterange(start_date, end_date + timedelta(days=1)): + date = date.strftime(FORMAT_DATE) + result[booking.room_id][date] = "AV" + + cur = result[booking.room_id] + + for date in daterange(booking.start, booking.end): + date = date.strftime(FORMAT_DATE) + if date not in cur: + continue + cur[date] = STATUS[booking.room_availability] + + transposed = [] + for booking in result: + + transposed.append(result[booking]) + + return transposed + + +def execute(filters=None): + start_date = parse(filters.start_date) + end_date = parse(filters.end_date) + + if start_date >= end_date: + raise ValueError("end date cannot before start date") + + delta_time = end_date - start_date + columns = get_column(start_date, delta_time.days) + data = get_data(filters) + return columns, data From 8da211e9ec66f29fffbcf863fae0a11987a0529c Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Wed, 29 Jan 2025 11:02:44 +0200 Subject: [PATCH 12/22] [Fix]: Added the summary in report --- .../report/room_occupation/room_occupation.js | 6 +++ .../report/room_occupation/room_occupation.py | 41 ++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/inn/inn_hotels/report/room_occupation/room_occupation.js b/inn/inn_hotels/report/room_occupation/room_occupation.js index 9bed2004..ed355df3 100644 --- a/inn/inn_hotels/report/room_occupation/room_occupation.js +++ b/inn/inn_hotels/report/room_occupation/room_occupation.js @@ -13,6 +13,12 @@ const STATUS = { frappe.query_reports["Room Occupation"] = { filters: [ + { + fieldname: "room", + label: __("Room"), + fieldtype: "Link", + options: "Inn Room", + }, { fieldname: "start_date", label: __("Start Date"), diff --git a/inn/inn_hotels/report/room_occupation/room_occupation.py b/inn/inn_hotels/report/room_occupation/room_occupation.py index 6b0647b4..b6723a7a 100644 --- a/inn/inn_hotels/report/room_occupation/room_occupation.py +++ b/inn/inn_hotels/report/room_occupation/room_occupation.py @@ -51,6 +51,10 @@ def get_data(filters): if start_date >= end_date: raise ValueError("end date cannot before start date") + sql_room_filter = "" + if filters.get("room"): + sql_room_filter = f"AND rb.room_id = {frappe.db.escape(filters.room)}" + sql = f""" SELECT rb.start, @@ -64,6 +68,10 @@ def get_data(filters): r.room_type FROM `tabInn Room Booking` rb LEFT JOIN `tabInn Room` r on rb.room_id = r.name + WHERE + rb.start >= {frappe.db.escape(filters.get(start_date))} + AND rb.status != 'Canceled' + {sql_room_filter} """ reservations = frappe.db.sql(sql, as_dict=1) @@ -102,6 +110,37 @@ def execute(filters=None): raise ValueError("end date cannot before start date") delta_time = end_date - start_date + report_summary = get_report_summary() columns = get_column(start_date, delta_time.days) data = get_data(filters) - return columns, data + return columns, data, report_summary + + +def get_report_summary(): + return """ + + +
        + Room Sold (RS) + Under Construction (UC) + Office Use (OU) + Out of Order (OO) + House Use (HU) + Room Compliment (RC) + Available (AV) +
        + """ From 113a17c470ae1c12963c0ba15ad1b614442a6bf0 Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Wed, 29 Jan 2025 11:30:47 +0200 Subject: [PATCH 13/22] [Fix]: the inn floor plan --- inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js b/inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js index 1c26460b..a1c788b9 100644 --- a/inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js +++ b/inn/inn_hotels/doctype/inn_floor_plan/inn_floor_plan.js @@ -54,6 +54,10 @@ frappe.ui.form.on("Inn Floor Plan", { \ \ \ +
        \ +
        \ +
        \ +
        \
        \ '; @@ -147,7 +151,7 @@ frappe.ui.form.on("Inn Floor Plan", { method: "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_all_room_with_room_booking_status", callback: (resp) => { - console.log(resp); + console.log(resp, "resr"); resp.message.forEach((element) => { if (element.status == "AV") { document From 0be3dad29e2546d716af5b3a7a3e294f1de5f53e Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Wed, 29 Jan 2025 14:33:23 +0200 Subject: [PATCH 14/22] [Fix]: Room occupation report --- .../report/room_occupation/room_occupation.js | 17 +- .../report/room_occupation/room_occupation.py | 169 +++++++++++++----- 2 files changed, 135 insertions(+), 51 deletions(-) diff --git a/inn/inn_hotels/report/room_occupation/room_occupation.js b/inn/inn_hotels/report/room_occupation/room_occupation.js index ed355df3..c721e3d8 100644 --- a/inn/inn_hotels/report/room_occupation/room_occupation.js +++ b/inn/inn_hotels/report/room_occupation/room_occupation.js @@ -19,6 +19,12 @@ frappe.query_reports["Room Occupation"] = { fieldtype: "Link", options: "Inn Room", }, + { + fieldname: "room_type", + label: __("Room Type"), + fieldtype: "Link", + options: "Inn Room Type", + }, { fieldname: "start_date", label: __("Start Date"), @@ -27,6 +33,7 @@ frappe.query_reports["Room Occupation"] = { default: frappe.datetime.month_start(), on_change(query_report) { validate_filter(query_report); + frappe.query_report.refresh(); }, }, { @@ -37,6 +44,7 @@ frappe.query_reports["Room Occupation"] = { default: frappe.datetime.month_end(), on_change(query_report) { validate_filter(query_report); + frappe.query_report.refresh(); }, }, ], @@ -47,16 +55,19 @@ frappe.query_reports["Room Occupation"] = { value = default_formatter(value, row, column, data); switch (column.fieldname) { - case "type": + case "room_type": + iconHTML = ``; + break; + case "room_id": iconHTML = ``; break; default: color = STATUS[value]; iconHTML = ``; - - return `${iconHTML} ${ + v = `${iconHTML} ${ value !== "" ? value : "N/A" }`; + return `

        ${v}

        `; } return `${iconHTML} ${ value !== "" ? value : "N/A" diff --git a/inn/inn_hotels/report/room_occupation/room_occupation.py b/inn/inn_hotels/report/room_occupation/room_occupation.py index b6723a7a..47c54f1c 100644 --- a/inn/inn_hotels/report/room_occupation/room_occupation.py +++ b/inn/inn_hotels/report/room_occupation/room_occupation.py @@ -7,6 +7,7 @@ from dateutil.parser import parse from datetime import timedelta, datetime from inn.helper.daterange import daterange +from frappe import _ FORMAT_DATE = "%Y-%m-%d" @@ -24,11 +25,17 @@ def get_column(start_date: datetime, date_length: datetime): column = [ { - "fieldname": "type", - "label": "Room Type", + "fieldname": "room_id", + "label": _("Room"), "fieldtype": "Data", "width": 150, - } + }, + { + "fieldname": "room_type", + "label": _("Room Type"), + "fieldtype": "Data", + "width": 150, + }, ] for day in range(date_length + 1): @@ -45,61 +52,127 @@ def get_column(start_date: datetime, date_length: datetime): def get_data(filters): + start_date = parse(filters.start_date) end_date = parse(filters.end_date) if start_date >= end_date: - raise ValueError("end date cannot before start date") + raise ValueError("End date cannot be before start date") - sql_room_filter = "" - if filters.get("room"): - sql_room_filter = f"AND rb.room_id = {frappe.db.escape(filters.room)}" + sql_room_filter = ( + f"AND r.name = {frappe.db.escape(filters.room)}" if filters.get("room") else "" + ) + sql_room_type_filter = ( + f"AND r.room_type = {frappe.db.escape(filters.room_type)}" + if filters.get("room_type") + else "" + ) sql = f""" - SELECT - rb.start, - rb.end, - rb.room_id, - rb.room_availability, - rb.note, - rb.reference_type, - rb.reference_name, - rb.status, - r.room_type - FROM `tabInn Room Booking` rb - LEFT JOIN `tabInn Room` r on rb.room_id = r.name - WHERE - rb.start >= {frappe.db.escape(filters.get(start_date))} - AND rb.status != 'Canceled' - {sql_room_filter} - """ - - reservations = frappe.db.sql(sql, as_dict=1) - + SELECT + r.name AS room_id, + r.room_type, + rb.start, + rb.end, + rb.room_availability + FROM `tabInn Room` r + LEFT JOIN `tabInn Room Booking` rb + ON rb.room_id = r.name + AND rb.start >= {frappe.db.escape(filters.start_date)} + AND rb.status != 'Canceled' + WHERE 1=1 + {sql_room_filter} + {sql_room_type_filter} + ORDER BY r.name, rb.start + """ + + reservations = frappe.db.sql(sql, as_dict=True) + + # Create a dictionary with all rooms initialized as available result = {} - for booking in reservations: - if booking.room_id not in result: - result[booking.room_id] = { - "type": booking.room_id, - } - for date in daterange(start_date, end_date + timedelta(days=1)): - date = date.strftime(FORMAT_DATE) - result[booking.room_id][date] = "AV" - - cur = result[booking.room_id] - for date in daterange(booking.start, booking.end): - date = date.strftime(FORMAT_DATE) - if date not in cur: - continue - cur[date] = STATUS[booking.room_availability] + for row in reservations: + room_id = row.room_id - transposed = [] - for booking in result: - - transposed.append(result[booking]) - - return transposed + if room_id not in result: + result[room_id] = {"room_id": room_id, "room_type": row.room_type} + for date in daterange(start_date, end_date + timedelta(days=1)): + date_str = date.strftime(FORMAT_DATE) + result[room_id][date_str] = "AV" # Default to Available + + # If the room has a booking, mark the occupied dates + if row.start and row.end: + for date in daterange(row.start, row.end): + date_str = date.strftime(FORMAT_DATE) + if date_str in result[room_id]: # Only update within range + result[room_id][date_str] = STATUS.get(row.room_availability, "AV") + + return list(result.values()) + + # start_date = parse(filters.start_date) + # end_date = parse(filters.end_date) + + # if start_date >= end_date: + # raise ValueError("end date cannot before start date") + + # sql_room_filter = "" + # if filters.get("room"): + # sql_room_filter = f"AND rb.room_id = {frappe.db.escape(filters.room)}" + # sql_room_type_filter = "" + # if filters.get("room"): + # sql_room_type_filter = ( + # f"AND r.room_type = {frappe.db.escape(filters.room_type)}" + # ) + + # sql = f""" + + +# SELECT +# rb.start, +# rb.end, +# rb.room_id, +# rb.room_availability, +# rb.note, +# rb.reference_type, +# rb.reference_name, +# rb.status, +# r.room_type +# FROM `tabInn Room Booking` rb +# LEFT JOIN `tabInn Room` r on rb.room_id = r.name +# WHERE +# rb.start >= {frappe.db.escape(filters.get(start_date))} +# AND rb.status != 'Canceled' +# {sql_room_filter} +# {sql_room_type_filter} +# """ + +# reservations = frappe.db.sql(sql, as_dict=1) + +# result = {} +# for booking in reservations: +# if booking.room_id not in result: +# result[booking.room_id] = { +# "room_id": booking.room_id, +# "room_type": booking.room_type, +# } +# for date in daterange(start_date, end_date + timedelta(days=1)): +# date = date.strftime(FORMAT_DATE) +# result[booking.room_id][date] = "AV" + +# cur = result[booking.room_id] + +# for date in daterange(booking.start, booking.end): +# date = date.strftime(FORMAT_DATE) +# if date not in cur: +# continue +# cur[date] = STATUS[booking.room_availability] + +# transposed = [] +# for booking in result: + +# transposed.append(result[booking]) + +# return transposed def execute(filters=None): From 32b9d0052911927469c6421c4e2cd33a23cc83a8 Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Mon, 3 Feb 2025 15:19:32 +0200 Subject: [PATCH 15/22] [Fix]: city ledger andadded city ledger in settings --- inn/__init__.py | 2 +- inn/inn_hotels/doctype/inn_folio/inn_folio.py | 279 ++++++++++-------- .../inn_hotels_setting.json | 16 +- .../inn_room_charge_posting.py | 257 ++++++++-------- 4 files changed, 313 insertions(+), 241 deletions(-) diff --git a/inn/__init__.py b/inn/__init__.py index 83e779e1..4a4d1b0d 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = "1.1.6" +__version__ = "1.1.7" diff --git a/inn/inn_hotels/doctype/inn_folio/inn_folio.py b/inn/inn_hotels/doctype/inn_folio/inn_folio.py index d9271385..b646f071 100644 --- a/inn/inn_hotels/doctype/inn_folio/inn_folio.py +++ b/inn/inn_hotels/doctype/inn_folio/inn_folio.py @@ -1,4 +1,3 @@ - # -*- coding: utf-8 -*- # Copyright (c) 2020, Core Initiative and contributors # For license information, please see license.txt @@ -10,159 +9,199 @@ import datetime from frappe.model.document import Document + class InnFolio(Document): - pass + pass + @frappe.whitelist() def create_folio(reservation_id): - if not frappe.db.exists('Inn Folio', {'reservation_id': reservation_id}): - reservation = frappe.get_doc('Inn Reservation', reservation_id) + if not frappe.db.exists("Inn Folio", {"reservation_id": reservation_id}): + reservation = frappe.get_doc("Inn Reservation", reservation_id) + + doc = frappe.new_doc("Inn Folio") + doc.type = "Guest" + doc.reservation_id = reservation_id + doc.customer_id = reservation.customer_id + doc.open = reservation.expected_arrival + doc.close = reservation.expected_departure + doc.insert() - doc = frappe.new_doc('Inn Folio') - doc.type = 'Guest' - doc.reservation_id = reservation_id - doc.customer_id = reservation.customer_id - doc.open = reservation.expected_arrival - doc.close = reservation.expected_departure - doc.insert() def update_close_by_reservation(reservation_id): - folio_list = frappe.get_all('Inn Folio', filters={'reservation_id': reservation_id}) - reservation = frappe.get_doc('Inn Reservation', reservation_id) - # Update except status finish, because when Checking Out, Close is handled by close_folio function - if reservation.status != 'Finish': - for item in folio_list: - doc_folio = frappe.get_doc('Inn Folio', item.name) - doc_folio.close = reservation.departure.strftime('%Y-%m-%d') - doc_folio.save() + folio_list = frappe.get_all("Inn Folio", filters={"reservation_id": reservation_id}) + reservation = frappe.get_doc("Inn Reservation", reservation_id) + # Update except status finish, because when Checking Out, Close is handled by close_folio function + if reservation.status != "Finish": + for item in folio_list: + doc_folio = frappe.get_doc("Inn Folio", item.name) + doc_folio.close = reservation.departure.strftime("%Y-%m-%d") + doc_folio.save() + @frappe.whitelist() def get_reservation_id(folio_id): - doc = frappe.get_doc('Inn Folio', folio_id) - return doc.reservation_id + doc = frappe.get_doc("Inn Folio", folio_id) + return doc.reservation_id + @frappe.whitelist() def update_balance(folio_id): - doc = frappe.get_doc('Inn Folio', folio_id) - trx_list = doc.get('folio_transaction') - total_debit = 0.0 - total_credit = 0.0 - for trx in trx_list: - if trx.flag == 'Debit' and trx.is_void == 0: - total_debit += float(trx.amount) - elif trx.flag == 'Credit' and trx.is_void == 0: - total_credit += float(trx.amount) - balance = total_credit - math.ceil(total_debit) - - if balance != doc.balance: - frappe.db.set_value('Inn Folio', doc.name, 'total_debit', math.ceil(total_debit)) - frappe.db.set_value('Inn Folio', doc.name, 'total_credit', total_credit) - frappe.db.set_value('Inn Folio', doc.name, 'balance', int(balance)) - - return total_debit, total_credit, balance + doc = frappe.get_doc("Inn Folio", folio_id) + trx_list = doc.get("folio_transaction") + total_debit = 0.0 + total_credit = 0.0 + for trx in trx_list: + if trx.flag == "Debit" and trx.is_void == 0: + total_debit += float(trx.amount) + elif trx.flag == "Credit" and trx.is_void == 0: + total_credit += float(trx.amount) + balance = total_credit - math.ceil(total_debit) + + if balance != doc.balance: + frappe.db.set_value( + "Inn Folio", doc.name, "total_debit", math.ceil(total_debit) + ) + frappe.db.set_value("Inn Folio", doc.name, "total_credit", total_credit) + frappe.db.set_value("Inn Folio", doc.name, "balance", int(balance)) + + return total_debit, total_credit, balance + @frappe.whitelist() def need_to_update_balance(folio_id): - doc = frappe.get_doc('Inn Folio', folio_id) - trx_list = doc.get('folio_transaction') + doc = frappe.get_doc("Inn Folio", folio_id) + trx_list = doc.get("folio_transaction") - total_debit = 0.0 - total_credit = 0.0 - for trx in trx_list: - if trx.flag == 'Debit' and trx.is_void == 0: - total_debit += float(trx.amount) - elif trx.flag == 'Credit' and trx.is_void == 0: - total_credit += float(trx.amount) - balance = total_credit - total_debit + total_debit = 0.0 + total_credit = 0.0 + for trx in trx_list: + if trx.flag == "Debit" and trx.is_void == 0: + total_debit += float(trx.amount) + elif trx.flag == "Credit" and trx.is_void == 0: + total_credit += float(trx.amount) + balance = total_credit - total_debit - if balance != doc.balance: - return 1 - else: - return 0 + if balance != doc.balance: + return 1 + else: + return 0 @frappe.whitelist() def get_balance(folio_id): - update_balance(folio_id) - return frappe.db.get_value('Inn Folio', folio_id, ['balance']) + update_balance(folio_id) + return frappe.db.get_value("Inn Folio", folio_id, ["balance"]) + @frappe.whitelist() def get_balance_by_reservation(reservation_id): - folio = frappe.get_doc('Inn Folio', {'reservation_id': reservation_id}) - balance = get_balance(folio.name) - return balance + folio = frappe.get_doc("Inn Folio", {"reservation_id": reservation_id}) + balance = get_balance(folio.name) + return balance + @frappe.whitelist() def transfer_to_another_folio(trx_list, old_parent, new_parent): - exist_error = 0 - list_json = json.loads(trx_list) - for trx in list_json: - trx_doc = frappe.get_doc('Inn Folio Transaction', trx) - if trx_doc.parent == old_parent: - trx_doc.parent = new_parent - trx_doc.remark = 'Transferred from ' + old_parent + ' to Folio ' + new_parent - trx_doc.save() - else: - exist_error = 1 - - return exist_error + exist_error = 0 + list_json = json.loads(trx_list) + for trx in list_json: + trx_doc = frappe.get_doc("Inn Folio Transaction", trx) + if trx_doc.parent == old_parent: + trx_doc.parent = new_parent + trx_doc.remark = ( + "Transferred from " + old_parent + " to Folio " + new_parent + ) + trx_doc.save() + else: + exist_error = 1 + + return exist_error + def is_using_city_ledger(folio_id): - is_using = False - doc = frappe.get_doc('Inn Folio', folio_id) - trx_list = doc.get('folio_transaction') - for trx in trx_list: - if trx.is_void == 0 and trx.flag == 'Credit' and trx.mode_of_payment == 'City Ledger': - is_using = True - return is_using + is_using = False + doc = frappe.get_doc("Inn Folio", folio_id) + trx_list = doc.get("folio_transaction") + hotel_settings = frappe.get_doc("Inn Hotels Setting") + + for trx in trx_list: + if ( + trx.is_void == 0 + and trx.flag == "Credit" + and trx.mode_of_payment == hotel_settings.city_ledger_mode_of_payment + ): + is_using = True + return is_using + @frappe.whitelist() def close_folio(folio_id): - list = check_void_request(folio_id) - if len(list) == 0: - folio = frappe.get_doc('Inn Folio', folio_id) - folio.status = 'Closed' - folio.close = datetime.date.today() - folio.save() - - # Create AR City Ledger if There are payment using City Ledger as mode_of_payment - if is_using_city_ledger(folio_id): - total_amount = 0.0 - trx_list = frappe.get_all('Inn Folio Transaction', filters={'parent': folio_id, 'is_void': 0, 'flag': 'Credit', - 'mode_of_payment': 'City Ledger'}, fields=['amount']) - for trx in trx_list: - total_amount += trx.amount - - ar_city_ledger = frappe.new_doc('AR City Ledger') - ar_city_ledger.naming_series = 'AR-CL-.YYYY.-' - ar_city_ledger.is_paid = 0 - ar_city_ledger.customer_id = folio.customer_id - if folio.type == 'Guest': - ar_city_ledger.inn_channel_id = frappe.db.get_value('Inn Reservation', folio.reservation_id, 'channel') - else: - ar_city_ledger.inn_group_id = folio.group_id - ar_city_ledger.total_amount = total_amount - ar_city_ledger.folio_id = folio_id - ar_city_ledger.folio_type = folio.type - ar_city_ledger.folio_status = folio.status - ar_city_ledger.folio_open = folio.open - ar_city_ledger.folio_close = folio.close - ar_city_ledger.insert() - - return frappe.db.get_value('Inn Folio', folio_id, 'status') - else: - return "There are void transaction request that still not responded. " \ - "Please consult the supervisor to resolve this before closing Folio." + \ - "
        Transaction need to be resolved:
        " + list + hotel_settings = frappe.get_doc("Inn Hotels Setting") + + list = check_void_request(folio_id) + if len(list) == 0: + folio = frappe.get_doc("Inn Folio", folio_id) + folio.status = "Closed" + folio.close = datetime.date.today() + folio.save() + + # Create AR City Ledger if There are payment using City Ledger as mode_of_payment + if is_using_city_ledger(folio_id): + total_amount = 0.0 + trx_list = frappe.get_all( + "Inn Folio Transaction", + filters={ + "parent": folio_id, + "is_void": 0, + "flag": "Credit", + "mode_of_payment": hotel_settings.city_ledger_mode_of_payment, + }, + fields=["amount"], + ) + for trx in trx_list: + total_amount += trx.amount + + ar_city_ledger = frappe.new_doc("AR City Ledger") + ar_city_ledger.naming_series = "AR-CL-.YYYY.-" + ar_city_ledger.is_paid = 0 + ar_city_ledger.customer_id = folio.customer_id + if folio.type == "Guest": + ar_city_ledger.inn_channel_id = frappe.db.get_value( + "Inn Reservation", folio.reservation_id, "channel" + ) + else: + ar_city_ledger.inn_group_id = folio.group_id + ar_city_ledger.total_amount = total_amount + ar_city_ledger.folio_id = folio_id + ar_city_ledger.folio_type = folio.type + ar_city_ledger.folio_status = folio.status + ar_city_ledger.folio_open = folio.open + ar_city_ledger.folio_close = folio.close + ar_city_ledger.insert() + + return frappe.db.get_value("Inn Folio", folio_id, "status") + else: + return ( + "There are void transaction request that still not responded. " + "Please consult the supervisor to resolve this before closing Folio." + + "
        Transaction need to be resolved:
        " + + list + ) @frappe.whitelist() def check_void_request(folio_id): - need_resolve = [] - folio = frappe.get_doc('Inn Folio', folio_id) - trx_list = folio.get('folio_transaction') - for item in trx_list: - if item.is_void == 0 and item.void_id is not None: - if frappe.db.get_value('Inn Void Folio Transaction', {'name': item.void_id }, 'status') == 'Requested': - need_resolve.append(item.name) - return need_resolve + need_resolve = [] + folio = frappe.get_doc("Inn Folio", folio_id) + trx_list = folio.get("folio_transaction") + for item in trx_list: + if item.is_void == 0 and item.void_id is not None: + if ( + frappe.db.get_value( + "Inn Void Folio Transaction", {"name": item.void_id}, "status" + ) + == "Requested" + ): + need_resolve.append(item.name) + return need_resolve diff --git a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json index eadde9ab..d963afe9 100644 --- a/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json +++ b/inn/inn_hotels/doctype/inn_hotels_setting/inn_hotels_setting.json @@ -108,6 +108,8 @@ "section_break_kkcy", "ar_city_ledger_invoice_payment_account", "column_break_wphq", + "mode_of_payment_section", + "city_ledger_mode_of_payment", "default_roles_section", "housekeeping_supervisor", "housekeeping", @@ -761,11 +763,23 @@ { "fieldname": "column_break_dynj", "fieldtype": "Column Break" + }, + { + "fieldname": "mode_of_payment_section", + "fieldtype": "Section Break", + "label": "Mode Of Payment" + }, + { + "fieldname": "city_ledger_mode_of_payment", + "fieldtype": "Link", + "label": "City Ledger Mode of Payment", + "options": "Mode of Payment", + "reqd": 1 } ], "issingle": 1, "links": [], - "modified": "2025-01-29 09:01:00.179629", + "modified": "2025-02-03 15:07:07.007333", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Hotels Setting", diff --git a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py index 6ab76fda..3b98738f 100644 --- a/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py +++ b/inn/inn_hotels/doctype/inn_room_charge_posting/inn_room_charge_posting.py @@ -82,8 +82,6 @@ def post_individual_room_charges(parent_id, tobe_posted_list): # Fetch all transaction types from Inn Hotels Setting hotel_settings = frappe.get_doc("Inn Hotels Setting") transaction_types = { - "room_charge_tax_service": hotel_settings.room_charge_tax_service, - "breakfast_charge_tax_service": hotel_settings.breakfast_charge_tax_service, "credit_card_administration_fee": hotel_settings.credit_card_administration_fee, "package": hotel_settings.package, "room_charge": hotel_settings.room_charge, @@ -101,13 +99,22 @@ def post_individual_room_charges(parent_id, tobe_posted_list): "room_service_food": hotel_settings.room_service_food, "room_service_beverage": hotel_settings.room_service_beverage, "fbs_service_10": hotel_settings.fbs_service_10, - "fbs_tax_11": hotel_settings.fbs_tax_11, "round_off": hotel_settings.round_off, "laundry": hotel_settings.laundry, "cancellation_fee": hotel_settings.cancellation_fee, "late_checkout": hotel_settings.late_checkout, "early_checkin": hotel_settings.early_checkin, } + if hotel_settings.include_tax: + transaction_types["room_charge_tax_service"] = ( + hotel_settings.room_charge_tax_service + ) + + transaction_types["breakfast_charge_tax_service"] = ( + hotel_settings.breakfast_charge_tax_service + ) + + transaction_types["fbs_tax_11"] = hotel_settings.fbs_tax_11 # to exclude service charge from reduced because of commision / cashback room_post_settings = frappe.db.get_values_from_single( @@ -206,27 +213,30 @@ def post_individual_room_charges(parent_id, tobe_posted_list): ftb_doc.append("transaction_detail", ftbd_doc) fdc_room_rate = frappe.get_doc("Inn Room Rate", fdc_reservation.room_rate) - fdc_room_rate_tax = frappe.get_doc("Inn Tax", fdc_room_rate.room_rate_tax) - fdc_room_rate_tax_breakdown = fdc_room_rate_tax.inn_tax_breakdown - if fdc_room_rate_tax_breakdown[-1].breakdown_rate != 0.0: - fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ - -1 - ].breakdown_account - else: - fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ - -2 - ].breakdown_account - - # get tax breakdown account from reservation - if is_exclude_tax: - fdc_room_rate_tax = frappe.get_doc( - "Inn Tax", reservation.actual_room_rate_tax - ) - fdc_room_rate_tax_account = ( - fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_account - if fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_rate != 0 - else fdc_room_rate_tax.inn_tax_breakdown[-2].breakdown_account - ) + + if hotel_settings.include_tax: + + fdc_room_rate_tax = frappe.get_doc("Inn Tax", fdc_room_rate.room_rate_tax) + fdc_room_rate_tax_breakdown = fdc_room_rate_tax.inn_tax_breakdown + if fdc_room_rate_tax_breakdown[-1].breakdown_rate != 0.0: + fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ + -1 + ].breakdown_account + else: + fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ + -2 + ].breakdown_account + + # get tax breakdown account from reservation + if is_exclude_tax: + fdc_room_rate_tax = frappe.get_doc( + "Inn Tax", reservation.actual_room_rate_tax + ) + fdc_room_rate_tax_account = ( + fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_account + if fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_rate != 0 + else fdc_room_rate_tax.inn_tax_breakdown[-2].breakdown_account + ) if is_channel_commision: # add commission first @@ -266,40 +276,44 @@ def post_individual_room_charges(parent_id, tobe_posted_list): ) # Posting Room Charge Tax/Service - for index, room_tax_item_name in enumerate(room_tb_id): - room_tax_doc = frappe.new_doc("Inn Folio Transaction") - room_tax_doc.flag = "Debit" - room_tax_doc.is_void = 0 - room_tax_doc.idx = get_idx(item_doc.folio_id) - room_tax_doc.transaction_type = transaction_types["room_charge_tax_service"] - room_tax_doc.amount = room_tb_amount[index] - accumulated_amount += room_tb_amount[index] - room_tax_doc.credit_account = frappe.get_doc( - "Inn Tax Breakdown", room_tax_item_name - ).breakdown_account - room_tax_doc.debit_account = room_charge_debit_account - room_tax_doc.remark = ( - "Room Charge Tax Room Rate " - + room_tax_item_name - + " : " - + item_doc.room_id - + " - " - + get_last_audit_date().strftime("%d-%m-%Y") - ) - room_tax_doc.parent = item_doc.folio_id - room_tax_doc.parenttype = "Inn Folio" - room_tax_doc.parentfield = "folio_transaction" - room_tax_doc.ftb_id = ftb_doc.name - room_tax_doc.insert() + if is_exclude_tax: - if room_tax_doc.credit_account == fdc_room_rate_tax_account: - fdc_folio_trx_tax_name = room_tax_doc.name + for index, room_tax_item_name in enumerate(room_tb_id): + room_tax_doc = frappe.new_doc("Inn Folio Transaction") + room_tax_doc.flag = "Debit" + room_tax_doc.is_void = 0 + room_tax_doc.idx = get_idx(item_doc.folio_id) + room_tax_doc.transaction_type = transaction_types[ + "room_charge_tax_service" + ] + room_tax_doc.amount = room_tb_amount[index] + accumulated_amount += room_tb_amount[index] + room_tax_doc.credit_account = frappe.get_doc( + "Inn Tax Breakdown", room_tax_item_name + ).breakdown_account + room_tax_doc.debit_account = room_charge_debit_account + room_tax_doc.remark = ( + "Room Charge Tax Room Rate " + + room_tax_item_name + + " : " + + item_doc.room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + room_tax_doc.parent = item_doc.folio_id + room_tax_doc.parenttype = "Inn Folio" + room_tax_doc.parentfield = "folio_transaction" + room_tax_doc.ftb_id = ftb_doc.name + room_tax_doc.insert() - # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service - ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") - ftbd_doc.transaction_type = room_tax_doc.transaction_type - ftbd_doc.transaction_id = room_tax_doc.name - ftb_doc.append("transaction_detail", ftbd_doc) + if room_tax_doc.credit_account == fdc_room_rate_tax_account: + fdc_folio_trx_tax_name = room_tax_doc.name + + # Create Inn Folio Transaction Bundle Detail Item Room Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = room_tax_doc.transaction_type + ftbd_doc.transaction_id = room_tax_doc.name + ftb_doc.append("transaction_detail", ftbd_doc) ## corner case: if breakfast charge is 0 then don't post any breakfast related to Folio breakfast_price = float(int(reservation.nett_actual_breakfast_rate)) @@ -377,40 +391,42 @@ def post_individual_room_charges(parent_id, tobe_posted_list): reservation.actual_breakfast_rate_tax, ) - # Posting Breakfast Tax/Service - for index, breakfast_tax_item_name in enumerate(breakfast_tb_id): - breakfast_tax_doc = frappe.new_doc("Inn Folio Transaction") - breakfast_tax_doc.flag = "Debit" - breakfast_tax_doc.is_void = 0 - breakfast_tax_doc.idx = get_idx(item_doc.folio_id) - breakfast_tax_doc.transaction_type = transaction_types[ - "breakfast_charge_tax_service" - ] - breakfast_tax_doc.amount = breakfast_tb_amount[index] - accumulated_amount += breakfast_tb_amount[index] - breakfast_tax_doc.credit_account = frappe.get_doc( - "Inn Tax Breakdown", breakfast_tax_item_name - ).breakdown_account - breakfast_tax_doc.debit_account = breakfast_charge_debit_account - breakfast_tax_doc.remark = ( - "Breakfast Charge Tax Room Rate " - + breakfast_tax_item_name - + " : " - + item_doc.room_id - + " - " - + get_last_audit_date().strftime("%d-%m-%Y") - ) - breakfast_tax_doc.parent = item_doc.folio_id - breakfast_tax_doc.parenttype = "Inn Folio" - breakfast_tax_doc.parentfield = "folio_transaction" - breakfast_tax_doc.ftb_id = ftb_doc.name - breakfast_tax_doc.insert() + if hotel_settings.include_tax: - # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge Tax/Service - ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") - ftbd_doc.transaction_type = breakfast_tax_doc.transaction_type - ftbd_doc.transaction_id = breakfast_tax_doc.name - ftb_doc.append("transaction_detail", ftbd_doc) + # Posting Breakfast Tax/Service + for index, breakfast_tax_item_name in enumerate(breakfast_tb_id): + breakfast_tax_doc = frappe.new_doc("Inn Folio Transaction") + breakfast_tax_doc.flag = "Debit" + breakfast_tax_doc.is_void = 0 + breakfast_tax_doc.idx = get_idx(item_doc.folio_id) + breakfast_tax_doc.transaction_type = transaction_types[ + "breakfast_charge_tax_service" + ] + breakfast_tax_doc.amount = breakfast_tb_amount[index] + accumulated_amount += breakfast_tb_amount[index] + breakfast_tax_doc.credit_account = frappe.get_doc( + "Inn Tax Breakdown", breakfast_tax_item_name + ).breakdown_account + breakfast_tax_doc.debit_account = breakfast_charge_debit_account + breakfast_tax_doc.remark = ( + "Breakfast Charge Tax Room Rate " + + breakfast_tax_item_name + + " : " + + item_doc.room_id + + " - " + + get_last_audit_date().strftime("%d-%m-%Y") + ) + breakfast_tax_doc.parent = item_doc.folio_id + breakfast_tax_doc.parenttype = "Inn Folio" + breakfast_tax_doc.parentfield = "folio_transaction" + breakfast_tax_doc.ftb_id = ftb_doc.name + breakfast_tax_doc.insert() + + # Create Inn Folio Transaction Bundle Detail Item Breakfast Charge Tax/Service + ftbd_doc = frappe.new_doc("Inn Folio Transaction Bundle Detail") + ftbd_doc.transaction_type = breakfast_tax_doc.transaction_type + ftbd_doc.transaction_id = breakfast_tax_doc.name + ftb_doc.append("transaction_detail", ftbd_doc) print("accumulated amount = " + str(accumulated_amount)) print("math_ceil(accumulated amount) = " + str(math.ceil(accumulated_amount))) @@ -636,26 +652,28 @@ def post_room_charges(parent_id, tobe_posted_list): ftb_doc.append("transaction_detail", ftbd_doc) fdc_room_rate = frappe.get_doc("Inn Room Rate", fdc_reservation.room_rate) - fdc_room_rate_tax = frappe.get_doc("Inn Tax", fdc_room_rate.room_rate_tax) - fdc_room_rate_tax_breakdown = fdc_room_rate_tax.inn_tax_breakdown - if fdc_room_rate_tax_breakdown[-1].breakdown_rate != 0.0: - fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ - -1 - ].breakdown_account - # else: - # fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ - # -2 - # ].breakdown_account - # get tax breakdown account from reservation - if is_exclude_tax: - fdc_room_rate_tax = frappe.get_doc( - "Inn Tax", reservation.actual_room_rate_tax - ) - fdc_room_rate_tax_account = ( - fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_account - if fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_rate != 0 - else fdc_room_rate_tax[-2].breakdown_account - ) + if hotel_settings.include_tax: + + fdc_room_rate_tax = frappe.get_doc("Inn Tax", fdc_room_rate.room_rate_tax) + fdc_room_rate_tax_breakdown = fdc_room_rate_tax.inn_tax_breakdown + if fdc_room_rate_tax_breakdown[-1].breakdown_rate != 0.0: + fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ + -1 + ].breakdown_account + # else: + # fdc_room_rate_tax_account = fdc_room_rate_tax_breakdown[ + # -2 + # ].breakdown_account + # get tax breakdown account from reservation + if is_exclude_tax: + fdc_room_rate_tax = frappe.get_doc( + "Inn Tax", reservation.actual_room_rate_tax + ) + fdc_room_rate_tax_account = ( + fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_account + if fdc_room_rate_tax.inn_tax_breakdown[-1].breakdown_rate != 0 + else fdc_room_rate_tax[-2].breakdown_account + ) if is_channel_commision: # add commission first @@ -860,17 +878,18 @@ def post_room_charges(parent_id, tobe_posted_list): elif difference < 0: adjusted_room_charge_amount = room_charge_folio_trx.amount adjusted_breakfast_charge_amount = breakfast_charge_folio_trx.amount - fdc_folio_trx_tax = frappe.get_doc( - "Inn Folio Transaction", fdc_folio_trx_tax_name - ) - adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount - # TODO: ganti tambah difference ke pajak, bukan ke room rate & breakfast - for i in range(0, abs(difference)): - adjusted_room_rate_tax_amount = ( - adjusted_room_rate_tax_amount + 1.0 + if hotel_settings.include_tax: + fdc_folio_trx_tax = frappe.get_doc( + "Inn Folio Transaction", fdc_folio_trx_tax_name ) - fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount - fdc_folio_trx_tax.save() + adjusted_room_rate_tax_amount = fdc_folio_trx_tax.amount + # TODO: ganti tambah difference ke pajak, bukan ke room rate & breakfast + for i in range(0, abs(difference)): + adjusted_room_rate_tax_amount = ( + adjusted_room_rate_tax_amount + 1.0 + ) + fdc_folio_trx_tax.amount = adjusted_room_rate_tax_amount + fdc_folio_trx_tax.save() room_charge_folio_trx.amount = adjusted_room_charge_amount room_charge_folio_trx.save() From 26f5769e808bf7037ef9d50214cc2b9b0ac00ffb Mon Sep 17 00:00:00 2001 From: SofianSaleh Date: Tue, 4 Feb 2025 11:47:55 +0200 Subject: [PATCH 16/22] [Fix]: Error in Reservation room error when room is dirty [Feat]: Added discount to reservation --- inn/__init__.py | 2 +- .../inn_reservation/inn_reservation.js | 80 +-- .../inn_reservation/inn_reservation.json | 10 +- .../inn_reservation/inn_reservation.py | 550 ++++++++++-------- inn/inn_hotels/doctype/inn_room/inn_room.json | 2 +- .../doctype/inn_room_type/inn_room_type.json | 8 +- 6 files changed, 379 insertions(+), 273 deletions(-) diff --git a/inn/__init__.py b/inn/__init__.py index 4a4d1b0d..9c98c831 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = "1.1.7" +__version__ = "1.1.8" diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js index f1aa2be7..924d82dd 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js @@ -20,13 +20,11 @@ frappe.ui.form.on("Inn Reservation", { is_check_in = getUrlVars()["is_check_in"]; get_room_max_active_card(); make_read_only(frm); - console.log("is error = " + is_error); // Hide some variables that not needed to be filled first time Reservation Created if (frm.doc.__islocal === 1) { frm.add_custom_button(__("Check Membership Card"), function () { check_membership_cards(); }); - console.log("notsaved"); frm.set_value("status", "Reserved"); frm.set_df_property("init_actual_room_rate", "hidden", 0); frm.set_df_property("arrival", "hidden", 1); @@ -65,7 +63,6 @@ frappe.ui.form.on("Inn Reservation", { } // Reservation is Saved, and status Reserved if (frm.doc.__islocal !== 1 && frm.doc.status === "Reserved") { - console.log("is saved"); // Set all variables that hidden to be shown again frm.set_df_property("arrival", "hidden", 0); frm.set_df_property("departure", "hidden", 0); @@ -74,10 +71,8 @@ frappe.ui.form.on("Inn Reservation", { // Still hide actual room rate frm.set_df_property("actual_room_rate", "hidden", 1); frm.set_df_property("init_actual_room_rate", "hidden", 0); - console.log("is_check_in = " + is_check_in); // Show Start Check In Process button if is_check_in flag undefined if (is_check_in === undefined) { - console.log("is_check_in undefined"); frm.add_custom_button(__("Start Check In Process"), function () { is_check_in = "true"; frappe.call({ @@ -103,8 +98,6 @@ frappe.ui.form.on("Inn Reservation", { // Assign some variables from "Reservation Detail" to "Room Stay" autofill(frm); is_form_not_good_to_go = is_form_good_to_in_house(frm); - console.log("is_form_not_good_to_go = " + is_form_not_good_to_go); - console.log("error_message = " + error_message); if ( is_form_not_good_to_go === true && (error_message !== "" || @@ -535,7 +528,6 @@ frappe.ui.form.on("Inn Reservation", { callback: (r) => { if (r.message) { let room_booking_name = r.message; - console.log("r = " + r.message); frappe.call({ method: "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_name_within_date_range", @@ -545,7 +537,6 @@ frappe.ui.form.on("Inn Reservation", { end: formatDate(frm.doc.departure), }, callback: (resp) => { - console.log("resp = " + resp.message); if ( resp.message == room_booking_name || resp.message.length == 0 @@ -638,7 +629,6 @@ frappe.ui.form.on("Inn Reservation", { } else if (frm.doc.status !== "Reserved") { start_date = formatDate(frm.doc.arrival); } - console.log("actual room id = " + frm.doc.actual_room_id); manage_filters("actual_room_id", phase, start_date); }, room_rate: function (frm) { @@ -678,10 +668,12 @@ frappe.ui.form.on("Inn Reservation", { parseInt(frm.doc.init_actual_room_rate) < parseInt(frm.doc.base_room_rate)) ) { - frappe.msgprint( - "Actual Room Rate must be equal or higher than Base Room Rate." - ); - frm.set_value("init_actual_room_rate", frm.doc.base_room_rate); + if (frm.doc.discount === 0) { + frappe.msgprint( + "Actual Room Rate must be equal or higher than Base Room Rate." + ); + frm.set_value("init_actual_room_rate", frm.doc.base_room_rate); + } } }, actual_room_rate: function (frm) { @@ -690,7 +682,9 @@ frappe.ui.form.on("Inn Reservation", { frm.set_value("actual_room_rate", frm.doc.base_room_rate); } else if ( parseFloat(frm.doc.actual_room_rate) > 0 && - parseInt(frm.doc.actual_room_rate) < parseInt(frm.doc.base_room_rate) + parseInt(frm.doc.actual_room_rate) < parseInt(frm.doc.base_room_rate) && + // Add Discount + frm.doc.discount === 0 ) { frappe.msgprint( "Actual Room Rate must be equal or higher than Base Room Rate." @@ -720,6 +714,41 @@ frappe.ui.form.on("Inn Reservation", { } } }, + discount: function (frm) { + if (frm.doc.discount > 0) { + frappe.call({ + method: + "inn.inn_hotels.doctype.inn_reservation.inn_reservation.check_discount", + args: { + room_type: frm.doc.room_type, + discount: frm.doc.discount, + }, + callback: (r) => { + if (r.message) { + frm.set_value( + "init_actual_room_rate", + parseFloat(frm.doc.base_room_rate) * + ((100 - frm.doc.discount) / 100) + ); + frm.set_value( + "actual_room_rate", + parseFloat(frm.doc.base_room_rate) * + ((100 - frm.doc.discount) / 100) + ); + calculate_rate_and_bill(frm); + } else { + frappe.msgprint( + "Error the discount percentage entered is more than the allowable discount." + ); + frm.set_value("init_actual_room_rate", frm.doc.base_room_rate); + frm.set_value("actual_room_rate", frm.doc.base_room_rate); + frm.set_value("discount", 0); + calculate_rate_and_bill(frm); + } + }, + }); + } + }, issue_card: function (frm) { if (frm.doc.__islocal !== 1 && frm.doc.status === "In House") { let current_active_card = 0; @@ -965,6 +994,7 @@ function autofill(frm) { frm.set_value("actual_room_id", frm.doc.room_id); } else { get_available("actual_room_id", "Check In"); + console.log("test"); frappe.msgprint( "Currently, Room " + frm.doc.room_id + @@ -1045,7 +1075,6 @@ function handle_filter_on_start_if_filled(frm) { // Function to adjust dropdown shown in cascading dropdown: room_type, bed_type, room_id/actual_room_id function manage_filters(fieldname, phase, start_date) { - console.log("masuk manage_filters from " + fieldname); let room_chooser = "room_id"; if (phase === "Check In") { room_chooser = "actual_room_id"; @@ -1105,6 +1134,7 @@ function manage_filters(fieldname, phase, start_date) { // Function to get available room/room_type/bed_type based on a period of time (start -> end) function get_available(fieldname, phase) { + console.log(fieldname, phase); let field = cur_frm.fields_dict[fieldname]; let reference_name = cur_frm.doc.name; let start = undefined; @@ -1129,7 +1159,6 @@ function get_available(fieldname, phase) { query = "inn.inn_hotels.doctype.inn_room_booking.inn_room_booking.get_bed_type_available"; } - console.log("query " + query); field.get_query = function () { return { query: query, @@ -1166,7 +1195,6 @@ function get_room_max_active_card() { callback: (r) => { if (r.message) { room_max_active_card = r.message; - console.log("rmesej = " + room_max_active_card); } }, }); @@ -1174,9 +1202,7 @@ function get_room_max_active_card() { // Function to erase the priviledge of key card to open room door function erase_card(flag, card_name) { - console.log("card_name = " + card_name); let yesterday = new Date(new Date().setDate(new Date().getDate() - 1)); - console.log(yesterday); frappe.call({ method: "inn.inn_hotels.doctype.inn_key_card.inn_key_card.erase_card", args: { @@ -1204,7 +1230,6 @@ function erase_card(flag, card_name) { // Function to get list of Room Rate in Room Rate Dropdown. // Filtered by room_type selected and the start date of reservation function get_room_rate(start_date) { - console.log("masuk get_Room_rate"); let field = cur_frm.fields_dict["room_rate"]; let room_type = cur_frm.doc.room_type; @@ -1216,10 +1241,6 @@ function get_room_rate(start_date) { (customer) => { let customer_group_list = ["All Customer Groups"]; customer_group_list.push(customer.customer_group); - console.log("filters: "); - console.log("room_type = " + room_type); - console.log("customer_group_list = " + customer_group_list); - console.log("start_date = " + start_date); field.get_query = function () { return { filters: [ @@ -1357,7 +1378,6 @@ function move_room(frm) { options: "Inn Room Type", reqd: 1, onchange: () => { - console.log("Milih room type"); if (d.fields_dict["mv_room_type"].get_value() !== "") { d.set_df_property("mv_bed_type", "hidden", 0); d.fields_dict["mv_bed_type"].get_query = function () { @@ -1384,7 +1404,6 @@ function move_room(frm) { options: "Inn Bed Type", reqd: 1, onchange: () => { - console.log("milih bed type"); if (d.fields_dict["mv_bed_type"].get_value() !== "") { d.set_df_property("mv_room_id", "hidden", 0); d.fields_dict["mv_room_id"].get_query = function () { @@ -1411,7 +1430,6 @@ function move_room(frm) { options: "Inn Room", reqd: 1, onchange: () => { - console.log("milih room id"); frappe.db.get_value( "Customer", frm.doc.customer_id, @@ -1505,8 +1523,6 @@ function move_room(frm) { } } if (good_to_go === 1) { - console.log(new_room_rate); - console.log(new_actual_room_rate); frappe.call({ method: "inn.inn_hotels.doctype.inn_move_room.inn_move_room.create_move_room_by_reservation", @@ -1546,11 +1562,11 @@ function calculate_rate_and_bill(frm) { }, callback: (r) => { if (r.message) { - console.log(r.message); frm.set_value("room_bill", r.message); } }, }); + frappe.call({ method: "inn.inn_hotels.doctype.inn_room_rate.inn_room_rate.get_actual_room_rate_breakdown_check_commission", @@ -1571,7 +1587,6 @@ function calculate_rate_and_bill(frm) { } function calculate_nights(arrival, departure) { - console.log("calculate_nights called"); let date_arrival = new Date(arrival); let date_departure = new Date(departure); let normalized_arrival = date_arrival.setHours(0, 0, 0, 0); @@ -1581,7 +1596,6 @@ function calculate_nights(arrival, departure) { if (days < 1) { days = 1; } - console.log("total nights calculated = " + days); return days; } diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json index 7ddfef0f..3ea51f1b 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json @@ -29,6 +29,7 @@ "base_room_rate", "init_actual_room_rate", "actual_room_rate", + "discount", "adult", "child", "extra_bed", @@ -311,10 +312,17 @@ "label": "Comission", "precision": "2", "print_hide": 1 + }, + { + "description": "Use Percentage", + "fieldname": "discount", + "fieldtype": "Percent", + "label": "Discount", + "precision": "2" } ], "links": [], - "modified": "2024-03-14 11:16:24.086635", + "modified": "2025-02-04 09:58:03.847590", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Reservation", diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.py b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.py index 267ef46c..39e57874 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.py +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.py @@ -8,281 +8,359 @@ import json import random import string -from frappe.model.document import Document -from inn.inn_hotels.doctype.inn_channel.inn_channel import check_channel_commission, PROFIT_SHARING_ENABLED, PROFIT_SHARING_TYPE_PERCENTAGE -from inn.inn_hotels.doctype.inn_folio.inn_folio import close_folio, get_balance_by_reservation, create_folio +from frappe.model.document import Document, flt +from inn.inn_hotels.doctype.inn_channel.inn_channel import ( + check_channel_commission, + PROFIT_SHARING_ENABLED, + PROFIT_SHARING_TYPE_PERCENTAGE, +) +from inn.inn_hotels.doctype.inn_folio.inn_folio import ( + close_folio, + get_balance_by_reservation, + create_folio, +) + class InnReservation(Document): - pass + pass + @frappe.whitelist() def check_in_reservation(reservation_id): - doc = frappe.get_doc('Inn Reservation', reservation_id) - - channel = check_channel_commission(doc) - if channel.profit_sharing == PROFIT_SHARING_ENABLED: - if channel.sharing_type == PROFIT_SHARING_TYPE_PERCENTAGE: - doc.comission = channel.breakfast_cashback + channel.room_cashback - doc.save() - - room_doc = frappe.get_doc('Inn Room', doc.actual_room_id) - if room_doc.room_status == 'Vacant Ready': - if (doc.status == 'Reserved'): - doc.status = 'In House' - doc.save() - if doc.status == 'In House': - room_doc.room_status = 'Occupied Clean' - room_doc.save() - - return doc.status - else: - return "Currently, Room " + room_doc.name + "status is not Vacant Ready. " \ - "Please consult with Room Service or choose another Room to continue Checking In." + doc = frappe.get_doc("Inn Reservation", reservation_id) + + channel = check_channel_commission(doc) + if channel.profit_sharing == PROFIT_SHARING_ENABLED: + if channel.sharing_type == PROFIT_SHARING_TYPE_PERCENTAGE: + doc.comission = channel.breakfast_cashback + channel.room_cashback + doc.save() + + room_doc = frappe.get_doc("Inn Room", doc.actual_room_id) + if room_doc.room_status == "Vacant Ready": + if doc.status == "Reserved": + doc.status = "In House" + doc.save() + if doc.status == "In House": + room_doc.room_status = "Occupied Clean" + room_doc.save() + + return doc.status + else: + return ( + "Currently, Room " + room_doc.name + "status is not Vacant Ready. " + "Please consult with Room Service or choose another Room to continue Checking In." + ) + @frappe.whitelist() def start_check_in(source, reservation): - if source == 'list': - reservation_id = json.loads(reservation)[0] - elif source == 'check_in_button': - reservation_id = reservation + if source == "list": + reservation_id = json.loads(reservation)[0] + elif source == "check_in_button": + reservation_id = reservation + + if frappe.db.get_value("Inn Reservation", reservation_id, "status") == "Reserved": + generate_wifi_password(reservation_id) + return ( + frappe.utils.get_url_to_form("Inn Reservation", reservation_id) + + "?is_check_in=true" + ) + else: + frappe.msgprint("Reservation Status must be Reserved in order to be Checked In") - if frappe.db.get_value('Inn Reservation', reservation_id, 'status') == 'Reserved': - generate_wifi_password(reservation_id) - return frappe.utils.get_url_to_form('Inn Reservation', reservation_id) + '?is_check_in=true' - else: - frappe.msgprint("Reservation Status must be Reserved in order to be Checked In") @frappe.whitelist() def cancel_reservation(source, reservation): - reservation_to_cancel = [] - exist_status_not_reserved = [] - exist_cancellation_fail = [] - - if source == 'list': - reservation = json.loads(reservation) - for item in reservation: - reservation_to_cancel.append(item) - elif source == 'cancel_button': - reservation_to_cancel.append(reservation) - - for reservation_id in reservation_to_cancel: - doc = frappe.get_doc('Inn Reservation', reservation_id) - if doc.status != 'Reserved': - exist_status_not_reserved.append(reservation_id) - - if len(exist_status_not_reserved) > 0: - return 1 - else: - for reservation_id in reservation_to_cancel: - cancellation_message = cancel_single_reservation(reservation_id) - if cancellation_message == 1: - exist_cancellation_fail.append(reservation_id) - - if len(exist_cancellation_fail) > 0: - return 1 - else: - return 0 + reservation_to_cancel = [] + exist_status_not_reserved = [] + exist_cancellation_fail = [] + + if source == "list": + reservation = json.loads(reservation) + for item in reservation: + reservation_to_cancel.append(item) + elif source == "cancel_button": + reservation_to_cancel.append(reservation) + + for reservation_id in reservation_to_cancel: + doc = frappe.get_doc("Inn Reservation", reservation_id) + if doc.status != "Reserved": + exist_status_not_reserved.append(reservation_id) + + if len(exist_status_not_reserved) > 0: + return 1 + else: + for reservation_id in reservation_to_cancel: + cancellation_message = cancel_single_reservation(reservation_id) + if cancellation_message == 1: + exist_cancellation_fail.append(reservation_id) + + if len(exist_cancellation_fail) > 0: + return 1 + else: + return 0 + def cancel_single_reservation(reservation_id): - reservation = frappe.get_doc('Inn Reservation', reservation_id) - folio = frappe.get_doc('Inn Folio', {'reservation_id': reservation_id}) - room_booking = frappe.get_doc('Inn Room Booking', {'reference_type': 'Inn Reservation', 'reference_name': reservation_id}) - - if reservation.status != 'Cancel': - reservation.status = 'Cancel' - reservation.save() - if folio.status != 'Cancel': - folio.status = 'Cancel' - folio.save() - if room_booking.status != 'Canceled': - room_booking.status = 'Canceled' - room_booking.save() - - if reservation.status == 'Cancel' and folio.status == 'Cancel' and room_booking.status == 'Canceled': - return 0 - else: - return 1 + reservation = frappe.get_doc("Inn Reservation", reservation_id) + folio = frappe.get_doc("Inn Folio", {"reservation_id": reservation_id}) + room_booking = frappe.get_doc( + "Inn Room Booking", + {"reference_type": "Inn Reservation", "reference_name": reservation_id}, + ) + + if reservation.status != "Cancel": + reservation.status = "Cancel" + reservation.save() + if folio.status != "Cancel": + folio.status = "Cancel" + folio.save() + if room_booking.status != "Canceled": + room_booking.status = "Canceled" + room_booking.save() + + if ( + reservation.status == "Cancel" + and folio.status == "Cancel" + and room_booking.status == "Canceled" + ): + return 0 + else: + return 1 + @frappe.whitelist() def cancel_single_reservation_in_house(reservation_id): - # return 0 if cancel success - # return 1 if cancel fail - # return 2 if the folio balance of Folio not 0 yet - - if get_balance_by_reservation(reservation_id) == 0: - reservation = frappe.get_doc('Inn Reservation', reservation_id) - room_doc = frappe.get_doc('Inn Room', reservation.actual_room_id) - folio = frappe.get_doc('Inn Folio', {'reservation_id': reservation_id}) - room_booking = frappe.get_doc('Inn Room Booking', - {'reference_type': 'Inn Reservation', 'reference_name': reservation_id}) - - if reservation.status != 'Cancel': - reservation.status = 'Cancel' - reservation.save() - if room_doc.room_status != 'Vacant Dirty': - room_doc.room_status = 'Vacant Dirty' - room_doc.save() - if folio.status != 'Closed': - folio.status = 'Closed' - folio.save() - if room_booking.status != 'Finished': - room_booking.status = 'Finished' - room_booking.end = frappe.utils.today() - room_booking.save() - - if reservation.status == 'Cancel' and room_doc.room_status == 'Vacant Dirty' and folio.status == 'Closed' and room_booking.status == 'Finished': - return 0 - else: - return 1 - else: - return 2 + # return 0 if cancel success + # return 1 if cancel fail + # return 2 if the folio balance of Folio not 0 yet + + if get_balance_by_reservation(reservation_id) == 0: + reservation = frappe.get_doc("Inn Reservation", reservation_id) + room_doc = frappe.get_doc("Inn Room", reservation.actual_room_id) + folio = frappe.get_doc("Inn Folio", {"reservation_id": reservation_id}) + room_booking = frappe.get_doc( + "Inn Room Booking", + {"reference_type": "Inn Reservation", "reference_name": reservation_id}, + ) + + if reservation.status != "Cancel": + reservation.status = "Cancel" + reservation.save() + if room_doc.room_status != "Vacant Dirty": + room_doc.room_status = "Vacant Dirty" + room_doc.save() + if folio.status != "Closed": + folio.status = "Closed" + folio.save() + if room_booking.status != "Finished": + room_booking.status = "Finished" + room_booking.end = frappe.utils.today() + room_booking.save() + + if ( + reservation.status == "Cancel" + and room_doc.room_status == "Vacant Dirty" + and folio.status == "Closed" + and room_booking.status == "Finished" + ): + return 0 + else: + return 1 + else: + return 2 + @frappe.whitelist() def no_show_reservation(source, reservation): - reservation_to_no_show = [] - exist_status_not_reserved = [] - exist_no_show_fail = [] - - if source == 'list': - reservation = json.loads(reservation) - for item in reservation: - reservation_to_no_show.append(item) - elif source == 'no_show_button': - reservation_to_no_show.append(reservation) - - for reservation_id in reservation_to_no_show: - doc = frappe.get_doc('Inn Reservation', reservation_id) - if doc.status != 'Reserved': - exist_status_not_reserved.append(reservation_id) - - if len(exist_status_not_reserved) > 0: - return 1 - else: - for reservation_id in reservation_to_no_show: - no_show_message = no_show_single_reservation(reservation_id) - if no_show_message == 1: - exist_no_show_fail.append(reservation_id) - - if len(exist_no_show_fail) > 0: - return 1 - else: - return 0 + reservation_to_no_show = [] + exist_status_not_reserved = [] + exist_no_show_fail = [] + + if source == "list": + reservation = json.loads(reservation) + for item in reservation: + reservation_to_no_show.append(item) + elif source == "no_show_button": + reservation_to_no_show.append(reservation) + + for reservation_id in reservation_to_no_show: + doc = frappe.get_doc("Inn Reservation", reservation_id) + if doc.status != "Reserved": + exist_status_not_reserved.append(reservation_id) + + if len(exist_status_not_reserved) > 0: + return 1 + else: + for reservation_id in reservation_to_no_show: + no_show_message = no_show_single_reservation(reservation_id) + if no_show_message == 1: + exist_no_show_fail.append(reservation_id) + + if len(exist_no_show_fail) > 0: + return 1 + else: + return 0 + def no_show_single_reservation(reservation_id): - reservation = frappe.get_doc('Inn Reservation', reservation_id) - folio = frappe.get_doc('Inn Folio', {'reservation_id': reservation_id}) - room_booking = frappe.get_doc('Inn Room Booking', - {'reference_type': 'Inn Reservation', 'reference_name': reservation_id}) - - if reservation.status != 'No Show': - reservation.status = 'No Show' - reservation.save() - if folio.status != 'Cancel': - folio.status = 'Cancel' - folio.save() - if room_booking.status != 'Canceled': - room_booking.status = 'Canceled' - room_booking.save() - - if reservation.status == 'No Show' and folio.status == 'Cancel' and room_booking.status == 'Canceled': - return 0 - else: - return 1 + reservation = frappe.get_doc("Inn Reservation", reservation_id) + folio = frappe.get_doc("Inn Folio", {"reservation_id": reservation_id}) + room_booking = frappe.get_doc( + "Inn Room Booking", + {"reference_type": "Inn Reservation", "reference_name": reservation_id}, + ) + + if reservation.status != "No Show": + reservation.status = "No Show" + reservation.save() + if folio.status != "Cancel": + folio.status = "Cancel" + folio.save() + if room_booking.status != "Canceled": + room_booking.status = "Canceled" + room_booking.save() + + if ( + reservation.status == "No Show" + and folio.status == "Cancel" + and room_booking.status == "Canceled" + ): + return 0 + else: + return 1 + @frappe.whitelist() def check_out_reservation(reservation_id): - doc = frappe.get_doc('Inn Reservation', reservation_id) - room_doc = frappe.get_doc('Inn Room', doc.actual_room_id) - folio_doc = frappe.get_doc('Inn Folio', {'reservation_id': reservation_id}) - # Change folio status - folio_status = close_folio(folio_doc.name) - if folio_status == 'Closed': - if (doc.status == 'In House'): - doc.departure = datetime.datetime.now() - doc.status = 'Finish' - doc.save() - if doc.status == 'Finish': - # Change room status - room_doc.room_status = 'Vacant Dirty' - room_doc.save() - return doc.status - else: - return folio_status + doc = frappe.get_doc("Inn Reservation", reservation_id) + room_doc = frappe.get_doc("Inn Room", doc.actual_room_id) + folio_doc = frappe.get_doc("Inn Folio", {"reservation_id": reservation_id}) + # Change folio status + folio_status = close_folio(folio_doc.name) + if folio_status == "Closed": + if doc.status == "In House": + doc.departure = datetime.datetime.now() + doc.status = "Finish" + doc.save() + if doc.status == "Finish": + # Change room status + room_doc.room_status = "Vacant Dirty" + room_doc.save() + return doc.status + else: + return folio_status + def generate_wifi_password(reservation_id): - reservation = frappe.get_doc('Inn Reservation', reservation_id) - mode = frappe.db.get_single_value('Inn Hotels Setting', 'hotspot_api_mode') - - if mode == 'First Name': - guest_name = reservation.guest_name - if guest_name: - password = guest_name.partition(' ')[0] - else: - name = reservation.customer_id - password = name.partition(' ')[0].lower() - elif mode == 'Random Number': - digits = string.digits - password = ''.join(random.choice(digits) for i in range(6)) - else: - digits = string.digits - password = ''.join(random.choice(digits) for i in range(6)) - - if reservation.wifi_password is None or reservation.wifi_password == '': - frappe.db.set_value('Inn Reservation', reservation_id, 'wifi_password', password) + reservation = frappe.get_doc("Inn Reservation", reservation_id) + mode = frappe.db.get_single_value("Inn Hotels Setting", "hotspot_api_mode") + + if mode == "First Name": + guest_name = reservation.guest_name + if guest_name: + password = guest_name.partition(" ")[0] + else: + name = reservation.customer_id + password = name.partition(" ")[0].lower() + elif mode == "Random Number": + digits = string.digits + password = "".join(random.choice(digits) for i in range(6)) + else: + digits = string.digits + password = "".join(random.choice(digits) for i in range(6)) + + if reservation.wifi_password is None or reservation.wifi_password == "": + frappe.db.set_value( + "Inn Reservation", reservation_id, "wifi_password", password + ) + @frappe.whitelist() def calculate_room_bill(arrival, departure, actual_rate): - start = datetime.datetime.strptime(arrival, "%Y-%m-%d %H:%M:%S") - end = datetime.datetime.strptime(departure, "%Y-%m-%d %H:%M:%S") - total_day = (end - start).days - return float(total_day) * float(actual_rate) + start = datetime.datetime.strptime(arrival, "%Y-%m-%d %H:%M:%S") + end = datetime.datetime.strptime(departure, "%Y-%m-%d %H:%M:%S") + total_day = (end - start).days + return float(total_day) * float(actual_rate) + @frappe.whitelist() def get_folio_url(reservation_id): - - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_id}, ['name']) - if folio_name == None: - create_folio(reservation_id) - folio_name = frappe.db.get_value('Inn Folio', {'reservation_id': reservation_id}, ['name']) - return frappe.utils.get_url_to_form('Inn Folio', folio_name) + folio_name = frappe.db.get_value( + "Inn Folio", {"reservation_id": reservation_id}, ["name"] + ) + if folio_name == None: + create_folio(reservation_id) + folio_name = frappe.db.get_value( + "Inn Folio", {"reservation_id": reservation_id}, ["name"] + ) + + return frappe.utils.get_url_to_form("Inn Folio", folio_name) + @frappe.whitelist() def allowed_to_in_house(reservation_id): - deposit = False - if frappe.db.exists('Inn Folio Transaction', {'parent': frappe.get_doc('Inn Folio', {'reservation_id': reservation_id}).name, 'transaction_type': 'Deposit'}): - deposit = True - return deposit + deposit = False + if frappe.db.exists( + "Inn Folio Transaction", + { + "parent": frappe.get_doc( + "Inn Folio", {"reservation_id": reservation_id} + ).name, + "transaction_type": "Deposit", + }, + ): + deposit = True + return deposit + @frappe.whitelist() def get_total_deposit(doc): - """ - Get the total deposit for a reservation or group. - The transaction type (e.g., 'Down Payment') is dynamically fetched from Inn Hotels Setting. - """ - # Fetch the transaction type from Inn Hotels Setting - transaction_type = frappe.db.get_single_value('Inn Hotels Setting', 'down_payment') - - if not transaction_type: - frappe.throw("Transaction type for deposit is not set in Inn Hotels Setting.") - - if doc.group_id: - return frappe.db.sql(""" - SELECT SUM(amount) AS amount - FROM `tabInn Folio Transaction` ft - LEFT JOIN `tabInn Folio` f ON f.name=ft.parent - LEFT JOIN `tabInn Reservation` r ON r.name=f.reservation_id - WHERE r.group_id=%s AND ft.transaction_type=%s - """, (doc.group_id, transaction_type), as_dict=True) - else: - return frappe.db.sql(""" - SELECT SUM(amount) AS amount - FROM `tabInn Folio Transaction` ft - LEFT JOIN `tabInn Folio` f ON f.name=ft.parent - LEFT JOIN `tabInn Reservation` r ON r.name=f.reservation_id - WHERE r.name=%s AND ft.transaction_type=%s - """, (doc.name, transaction_type), as_dict=True) - + """ + Get the total deposit for a reservation or group. + The transaction type (e.g., 'Down Payment') is dynamically fetched from Inn Hotels Setting. + """ + # Fetch the transaction type from Inn Hotels Setting + transaction_type = frappe.db.get_single_value("Inn Hotels Setting", "down_payment") + + if not transaction_type: + frappe.throw("Transaction type for deposit is not set in Inn Hotels Setting.") + + if doc.group_id: + return frappe.db.sql( + """ + SELECT SUM(amount) AS amount + FROM `tabInn Folio Transaction` ft + LEFT JOIN `tabInn Folio` f ON f.name=ft.parent + LEFT JOIN `tabInn Reservation` r ON r.name=f.reservation_id + WHERE r.group_id=%s AND ft.transaction_type=%s + """, + (doc.group_id, transaction_type), + as_dict=True, + ) + else: + return frappe.db.sql( + """ + SELECT SUM(amount) AS amount + FROM `tabInn Folio Transaction` ft + LEFT JOIN `tabInn Folio` f ON f.name=ft.parent + LEFT JOIN `tabInn Reservation` r ON r.name=f.reservation_id + WHERE r.name=%s AND ft.transaction_type=%s + """, + (doc.name, transaction_type), + as_dict=True, + ) + + @frappe.whitelist() def get_date(): - return datetime.datetime.now().strftime("%d/%m/%Y") \ No newline at end of file + return datetime.datetime.now().strftime("%d/%m/%Y") + + +@frappe.whitelist() +def check_discount(room_type, discount): + maximum_discount = frappe.db.get_value( + "Inn Room Type", room_type, "maximum_discount_percentage" + ) + return flt(discount, 3) <= flt(maximum_discount, 3) diff --git a/inn/inn_hotels/doctype/inn_room/inn_room.json b/inn/inn_hotels/doctype/inn_room/inn_room.json index 5dc912d5..4e76afdd 100644 --- a/inn/inn_hotels/doctype/inn_room/inn_room.json +++ b/inn/inn_hotels/doctype/inn_room/inn_room.json @@ -128,7 +128,7 @@ } ], "links": [], - "modified": "2024-03-14 11:19:14.876492", + "modified": "2025-02-04 10:12:27.722707", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Room", diff --git a/inn/inn_hotels/doctype/inn_room_type/inn_room_type.json b/inn/inn_hotels/doctype/inn_room_type/inn_room_type.json index c4382fa2..748b9eea 100644 --- a/inn/inn_hotels/doctype/inn_room_type/inn_room_type.json +++ b/inn/inn_hotels/doctype/inn_room_type/inn_room_type.json @@ -8,6 +8,7 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ + "maximum_discount_percentage", "description" ], "fields": [ @@ -15,10 +16,15 @@ "fieldname": "description", "fieldtype": "Small Text", "label": "Description" + }, + { + "fieldname": "maximum_discount_percentage", + "fieldtype": "Percent", + "label": "Maximum Discount Percentage" } ], "links": [], - "modified": "2024-03-14 12:01:14.126641", + "modified": "2025-02-04 10:12:45.234298", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Room Type", From 353beced24c31fa428fc510e5d6b1d83a32c62a6 Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Wed, 5 Mar 2025 13:45:00 +0300 Subject: [PATCH 17/22] (edit) tag 1.1.9 --- inn/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inn/__init__.py b/inn/__init__.py index 9c98c831..afdd45db 100644 --- a/inn/__init__.py +++ b/inn/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = "1.1.8" +__version__ = "1.1.9" From e19cca2324946f3b753b5b30749a35bb5420c3e0 Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Wed, 5 Mar 2025 22:51:35 +0300 Subject: [PATCH 18/22] (edit) print format in Inn Folio --- .../folio_a_commission.json | 6 +-- .../proforma_invoice/proforma_invoice.json | 52 +++++++++++-------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/inn/inn_hotels/print_format/folio_a_commission/folio_a_commission.json b/inn/inn_hotels/print_format/folio_a_commission/folio_a_commission.json index 4b3e79a8..a0a84c2f 100644 --- a/inn/inn_hotels/print_format/folio_a_commission/folio_a_commission.json +++ b/inn/inn_hotels/print_format/folio_a_commission/folio_a_commission.json @@ -3,20 +3,20 @@ "align_labels_right": 0, "creation": "2024-03-06 11:23:10.060463", "custom_format": 1, - "default_print_language": "en", + "default_print_language": "ar", "disabled": 0, "doc_type": "Inn Folio", "docstatus": 0, "doctype": "Print Format", "font_size": 14, - "html": "{% set company = frappe.get_doc(\"Global Defaults\").default_company %}\n{% set setting = frappe.get_doc(\"Inn Hotels Setting\") %}\n{% set address = setting.address %}\n{% set phone = setting.phone %}\n{% set customer = frappe.get_doc(\"Customer\", doc.customer_id) %}\n{% set accumulator1 = namespace(debit = 0.0) %}\n{% set accumulator2 = namespace(credit = 0.0) %}\n{% set accumulator3 = namespace(refund = 0.0) %}\n{% set room_charge = {} %}\n{% set package = {} %}\n\n{% set commission = namespace(commission = 0.0, remarks = '') %}\n{% set commission_transaction_type = setting.profit_sharing_transaction_type %}\n\n\n{% for row in doc.folio_transaction %}\n {% if row.sub_folio == 'A' and row.is_void == 0 %}\n {% if row.flag == 'Debit' %}\n {% set accumulator1.debit = accumulator1.debit + row.amount %}\n {% elif row.flag == 'Credit' %}\n {% set accumulator2.credit = accumulator2.credit + row.amount %}\n {% endif %}\n\n {% if row.transaction_type == 'Room Charge' %}\n {% set _ = room_charge.update({row.ftb_id: row.amount}) %}\n {% elif row.transaction_type == 'Package' %}\n {% set _ = package.update({row.ftb_id: row.amount}) %}\n {% endif %}\n {% endif %}\n{% endfor %}\n
        \n
        \n
        \n \"\"\n
        \n
        \n

        {{company|upper}}

        \n

        {{address}}

        \n

        Phone: {{phone}}

        \n
        \n
        \n
        \n
        \n
        \n{% for row in doc.folio_transaction %}\n {% if row.sub_folio == 'A' and row.is_void == 0 %}\n {% if row.transaction_type != 'Room Charge' and row.transaction_type != 'Package'%}\n {% if row.ftb_id in room_charge %}\n {% set _ = room_charge.update({row.ftb_id: room_charge[row.ftb_id] + row.amount}) %}\n {% elif row.ftb_id in package %}\n {% set _ = package.update({row.ftb_id: package[row.ftb_id] + row.amount}) %}\n {% endif %}\n {% endif %}\n {% endif %}\n{% endfor %}\n\n
        \n
        \n
        Customer:
        \n
        {{ doc.customer_id | upper }}
        \n
        Type:
        \n
        {{ doc.type }}
        \n
        Address:
        \n {% if customer.primary_address != None %}\n
        {{ customer.primary_address }}
        \n {% else %}\n
        \n {% endif%}\n
        \n
        \n \n \n \n \n \n \n \n \n \n {% if doc.reservation_id != None %}\n {% set reservation = frappe.get_doc(\"Inn Reservation\", doc.reservation_id) %}\n \n \n \n {% else %}\n \n \n \n {% endif %}\n \n \n \n
        ReservationCheck InCheck OutFolioBalance
        {{doc.reservation_id}}{{(reservation.arrival|string)[:11]}}{{(reservation.departure|string)[:11]}}{{(doc.open|string)[:11]}}{{doc.close}}{{doc.name}}{{ frappe.format_value(accumulator2.credit-accumulator1.debit, {\"fieldtype\":\"Currency\"}) }}
        \n
        \n
        \n\n
        \n
        \n \n \n \n \n \n \n \n \n \n\n {% for row in doc.folio_transaction %}\n {% if row.sub_folio == 'A' and row.is_void == 0 %}\n {% if row.transaction_type not in ['Room Charge Tax/Service', 'Breakfast Charge Tax/Service', 'Breakfast Charge', 'Package Tax'] %}\n {% if row.transaction_type == commission_transaction_type %}\n {% set commission.commission = commission.commission + row.amount %}\n {% set commission.remarks = row.remarks %}\n {% else %}\n \n \n \n {% if row.mode_of_payment != None %}\n \n {% else %}\n \n {% endif %}\n \n\n {% if row.flag == 'Debit' %}\n \n \n {% elif row.flag == 'Credit' %}\n \n \n {% endif %}\n\n {% if row.transaction_type == 'Refund' %}\n {% set accumulator3.refund = accumulator3.refund + row.amount %}\n {% endif %}\n \n {% endif %}\n {% endif %}\n {% endif %}\n {% endfor %}\n\n \n \n \n \n \n
        DateTypeMode of PaymentDescription/RemarkDebitCredit
        {{row.audit_date}}{{row.transaction_type}}{{row.mode_of_payment}}{{row.remark}}\n {% if row.transaction_type == 'Room Charge' %}\n {{ frappe.format_value(room_charge[row.ftb_id], {\"fieldtype\":\"Currency\"}) }}\n\t {% elif row.transaction_type == 'Package' %}\n {{ frappe.format_value(package[row.ftb_id], {\"fieldtype\":\"Currency\"}) }}\n {% else %}\n {{ frappe.format_value(row.amount, {\"fieldtype\":\"Currency\"}) }}\n\t {% endif %}\n --\n {{ frappe.format_value(row.amount, {\"fieldtype\":\"Currency\"}) }}\n
        Total\n {{ frappe.format_value(accumulator1.debit, {\"fieldtype\":\"Currency\"}) }}\n \n {{ frappe.format_value(accumulator2.credit, {\"fieldtype\":\"Currency\"}) }}\n
        \n\n {% set charge = accumulator1.debit - accumulator3.refund %}\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
        \n Total Charge:\n
        \n Total Payment:\n
        \n {{ frappe.format_value(charge, {\"fieldtype\":\"Currency\"}) }}\n
        \n
        \n
        \n {{ frappe.format_value(accumulator2.credit, {\"fieldtype\":\"Currency\"}) }}\n
        Total Commission:{{ frappe.format_value(commission.commission, {\"fieldtype\":\"Currency\"}) }}
        Total Refund:{{ frappe.format_value(accumulator3.refund, {\"fieldtype\":\"Currency\"}) }}
        \n
        \n
        \n\n
        \n
        \n\t\n\t\t\n\t\t\n\t\t\n \n \n \n \n \n \n
        {{ doc.customer_id }}
        Customer
        \n
        \n
        \n
        \n
        \n \n \n {% set employee = frappe.db.get_value('Employee',{'user_id':frappe.user},'name') %}\n\t\t \n\t\t\n\t\t\n \n \n \n \n \n
        \"\"
        {{ frappe.db.get_value(\"User\", frappe.user,\"full_name\") }}
        Staf/Personnel
        \n
        \n
        ", + "html": "{% set company = frappe.get_doc(\"Global Defaults\").default_company %}\n{% set setting = frappe.get_doc(\"Inn Hotels Setting\") %}\n{% set address = setting.address %}\n{% set phone = setting.phone %}\n{% set customer = frappe.get_doc(\"Customer\", doc.customer_id) %}\n{% set accumulator1 = namespace(debit = 0.0) %}\n{% set accumulator2 = namespace(credit = 0.0) %}\n{% set accumulator3 = namespace(refund = 0.0) %}\n{% set room_charge = {} %}\n{% set package = {} %}\n\n{% set commission = namespace(commission = 0.0, remarks = '') %}\n{% set commission_transaction_type = setting.profit_sharing_transaction_type %}\n\n\n{% for row in doc.folio_transaction %}\n {% if row.sub_folio == 'A' and row.is_void == 0 %}\n {% if row.flag == 'Debit' %}\n {% set accumulator1.debit = accumulator1.debit + row.amount %}\n {% elif row.flag == 'Credit' %}\n {% set accumulator2.credit = accumulator2.credit + row.amount %}\n {% endif %}\n\n {% if row.transaction_type == 'Room Charge' %}\n {% set _ = room_charge.update({row.ftb_id: row.amount}) %}\n {% elif row.transaction_type == 'Package' %}\n {% set _ = package.update({row.ftb_id: row.amount}) %}\n {% endif %}\n {% endif %}\n{% endfor %}\n
        \n
        \n
        \n \n
        \n

        {{ company | upper }}

        \n

        {{ address }}

        \n

        Phone: {{ phone }}

        \n
        \n\n \n
        \n \"Company\n
        \n\n \n
        \n
        \n
        \n
        \n\n\n
        \n{% for row in doc.folio_transaction %}\n {% if row.sub_folio == 'A' and row.is_void == 0 %}\n {% if row.transaction_type != 'Room Charge' and row.transaction_type != 'Package'%}\n {% if row.ftb_id in room_charge %}\n {% set _ = room_charge.update({row.ftb_id: room_charge[row.ftb_id] + row.amount}) %}\n {% elif row.ftb_id in package %}\n {% set _ = package.update({row.ftb_id: package[row.ftb_id] + row.amount}) %}\n {% endif %}\n {% endif %}\n {% endif %}\n{% endfor %}\n\n
        \n
        \n
        Customer:
        \n
        {{ doc.customer_id | upper }}
        \n
        Type:
        \n
        {{ doc.type }}
        \n
        Address:
        \n {% if customer.primary_address != None %}\n
        {{ customer.primary_address }}
        \n {% else %}\n
        \n {% endif%}\n
        \n
        \n \n \n \n \n \n \n \n \n \n {% if doc.reservation_id != None %}\n {% set reservation = frappe.get_doc(\"Inn Reservation\", doc.reservation_id) %}\n \n \n \n {% else %}\n \n \n \n {% endif %}\n \n \n \n
        ReservationCheck InCheck OutFolioBalance
        {{doc.reservation_id}}{{(reservation.arrival|string)[:11]}}{{(reservation.departure|string)[:11]}}{{(doc.open|string)[:11]}}{{doc.close}}{{doc.name}}{{ frappe.format_value(accumulator2.credit-accumulator1.debit, {\"fieldtype\":\"Currency\"}) }}
        \n
        \n
        \n\n
        \n
        \n \n \n \n \n \n \n \n \n \n\n {% for row in doc.folio_transaction %}\n {% if row.sub_folio == 'A' and row.is_void == 0 %}\n {% if row.transaction_type not in ['Room Charge Tax/Service', 'Breakfast Charge Tax/Service', 'Breakfast Charge', 'Package Tax'] %}\n {% if row.transaction_type == commission_transaction_type %}\n {% set commission.commission = commission.commission + row.amount %}\n {% set commission.remarks = row.remarks %}\n {% else %}\n \n \n \n {% if row.mode_of_payment != None %}\n \n {% else %}\n \n {% endif %}\n \n\n {% if row.flag == 'Debit' %}\n \n \n {% elif row.flag == 'Credit' %}\n \n \n {% endif %}\n\n {% if row.transaction_type == 'Refund' %}\n {% set accumulator3.refund = accumulator3.refund + row.amount %}\n {% endif %}\n \n {% endif %}\n {% endif %}\n {% endif %}\n {% endfor %}\n\n \n \n \n \n \n
        DateTypeMode of PaymentDescription/RemarkDebitCredit
        {{row.audit_date}}{{row.transaction_type}}{{row.mode_of_payment}}{{row.remark}}\n {% if row.transaction_type == 'Room Charge' %}\n {{ frappe.format_value(room_charge[row.ftb_id], {\"fieldtype\":\"Currency\"}) }}\n\t {% elif row.transaction_type == 'Package' %}\n {{ frappe.format_value(package[row.ftb_id], {\"fieldtype\":\"Currency\"}) }}\n {% else %}\n {{ frappe.format_value(row.amount, {\"fieldtype\":\"Currency\"}) }}\n\t {% endif %}\n --\n {{ frappe.format_value(row.amount, {\"fieldtype\":\"Currency\"}) }}\n
        Total\n {{ frappe.format_value(accumulator1.debit, {\"fieldtype\":\"Currency\"}) }}\n \n {{ frappe.format_value(accumulator2.credit, {\"fieldtype\":\"Currency\"}) }}\n
        \n\n {% set charge = accumulator1.debit - accumulator3.refund %}\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
        \n Total Charge:\n
        \n Total Payment:\n
        \n {{ frappe.format_value(charge, {\"fieldtype\":\"Currency\"}) }}\n
        \n
        \n
        \n {{ frappe.format_value(accumulator2.credit, {\"fieldtype\":\"Currency\"}) }}\n
        Total Commission:{{ frappe.format_value(commission.commission, {\"fieldtype\":\"Currency\"}) }}
        Total Refund:{{ frappe.format_value(accumulator3.refund, {\"fieldtype\":\"Currency\"}) }}
        \n
        \n
        \n\n
        \n
        \n\t\n\t\t\n\t\t\n\t\t\n \n \n \n \n \n \n
        {{ doc.customer_id }}
        Customer
        \n
        \n
        \n
        \n
        \n \n \n {% set employee = frappe.db.get_value('Employee',{'user_id':frappe.user},'name') %}\n\t\t \n\t\t\n\t\t\n \n \n \n \n \n
        \"\"
        {{ frappe.db.get_value(\"User\", frappe.user,\"full_name\") }}
        Staf/Personnel
        \n
        \n
        ", "idx": 0, "line_breaks": 0, "margin_bottom": 15.0, "margin_left": 15.0, "margin_right": 15.0, "margin_top": 15.0, - "modified": "2024-03-13 11:01:14.681935", + "modified": "2025-03-05 14:59:08.346909", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Folio A Commission", diff --git a/inn/inn_hotels/print_format/proforma_invoice/proforma_invoice.json b/inn/inn_hotels/print_format/proforma_invoice/proforma_invoice.json index 2458aa6a..f21db62f 100644 --- a/inn/inn_hotels/print_format/proforma_invoice/proforma_invoice.json +++ b/inn/inn_hotels/print_format/proforma_invoice/proforma_invoice.json @@ -1,24 +1,32 @@ { - "align_labels_right": 0, - "creation": "2020-05-04 11:58:49.217732", - "css": ".print-format { \n\tfont-size: 11px;\n}\n.table {\n\tmargin: 0;\n}", - "custom_format": 1, - "default_print_language": "en", - "disabled": 0, - "doc_type": "AR City Ledger Invoice", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "{% set company = frappe.get_doc(\"Global Defaults\").default_company %}\n{% set contact_person = frappe.get_doc(\"Customer\", doc.customer_id) %}\n\n
        \n\t
        \n\t\t

         

        \n\t\tTo:
        \n\t\t{{contact_person.get_formatted(\"salutation\")}} {{contact_person.name}}
        \n\t\tPhone:
        \n\t\t{{contact_person.get_formatted(\"mobile_no\")}}\n\t
        \t\n\t
        \n\t\t

        Proforma Invoice

        \n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t
        Invoice Number:{{doc.name}}
        Issued Date:{{ doc.get_formatted(\"issued_date\")}}
        Due Date:{{ doc.get_formatted(\"due_date\")}}
        \t\n\t\t
        \n
        \n
        \n
        \n\t
        \n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- for row in doc.folio -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- endfor -%}\n\t
        FolioCustomer NameAmount
        {{row.folio_id}}{{row.customer_id}}Rp.{{row.get_formatted(\"amount\")}}
        \n\t
        \n
        \n
        \n
        \n\t
        \n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\n\t\t
        Total Amount:Rp.{{doc.get_formatted(\"total_amount\")}}
        Paid:Rp.{{ frappe.format_value(doc.total_amount -\n doc.outstanding, {\"fieldtype\":\"Currency\"}) }}
        Outstanding Amount:Rp.{{doc.get_formatted(\"outstanding\")}}
        \n\t
        \n
        \n
        \nBank Transfer Info\n\n\t\n\t\t\n\t\t\n\t\t\n\t\n\t{% set accounts = frappe.get_all(\"Bank Account\", filters={\"account\": [\"like\", \"1121.0%\"]}, fields=[\"bank\", \"account_name\", \"bank_account_no\"]) %}\n\t{%- for row in accounts -%}\n\t\n\t\t\n\t\t\n\t\t\n\t\n\t{%- endfor -%}\n
        Bank NameAccount NumberAccount Name
        {{row.bank}}{{row.bank_account_no}}{{row.account_name}}
        \n\n
        \n
        \n
        \n \n \n \n \n \n \n \n
        {{ frappe.db.get_value(\"User\", frappe.user,\n \"full_name\") }}
        Income Audit
        \n
        \n
        \n\n", - "idx": 0, - "line_breaks": 0, - "modified": "2020-05-04 12:06:29.740642", - "modified_by": "Administrator", - "module": "Inn Hotels", - "name": "Proforma Invoice", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Jinja", - "show_section_headings": 0, - "standard": "Yes" + "absolute_value": 0, + "align_labels_right": 0, + "creation": "2020-05-04 11:58:49.217732", + "css": ".print-format { \n\tfont-size: 11px;\n}\n.table {\n\tmargin: 0;\n}", + "custom_format": 1, + "default_print_language": "en", + "disabled": 0, + "doc_type": "AR City Ledger Invoice", + "docstatus": 0, + "doctype": "Print Format", + "font": "Default", + "font_size": 0, + "html": "{% set company = frappe.get_doc(\"Global Defaults\").default_company %}\n{% set contact_person = frappe.get_doc(\"Customer\", doc.customer_id) %}\n\n\n\n\n
        \n\t
        \n\t\t

         

        \n\t\tTo:
        \n\t\t{{contact_person.get_formatted(\"salutation\")}} {{contact_person.name}}
        \n\t\tPhone:
        \n\t\t{{contact_person.get_formatted(\"mobile_no\")}}\n\t
        \t\n\t
        \n\t\t

        Proforma Invoice

        \n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t
        Invoice Number:{{doc.name}}
        Issued Date:{{ doc.get_formatted(\"issued_date\")}}
        Due Date:{{ doc.get_formatted(\"due_date\")}}
        \t\n\t\t
        \n
        \n
        \n
        \n\t
        \n\t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- for row in doc.folio -%}\n\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\t{%- endfor -%}\n\t
        FolioCustomer NameAmount
        {{row.folio_id}}{{row.customer_id}}Rp.{{row.get_formatted(\"amount\")}}
        \n\t
        \n
        \n
        \n
        \n\t
        \n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\n\t\t
        Total Amount:Rp.{{doc.get_formatted(\"total_amount\")}}
        Paid:Rp.{{ frappe.format_value(doc.total_amount -\n doc.outstanding, {\"fieldtype\":\"Currency\"}) }}
        Outstanding Amount:Rp.{{doc.get_formatted(\"outstanding\")}}
        \n\t
        \n
        \n
        \nBank Transfer Info\n\n\t\n\t\t\n\t\t\n\t\t\n\t\n\t{% set accounts = frappe.get_all(\"Bank Account\", filters={\"account\": [\"like\", \"1121.0%\"]}, fields=[\"bank\", \"account_name\", \"bank_account_no\"]) %}\n\t{%- for row in accounts -%}\n\t\n\t\t\n\t\t\n\t\t\n\t\n\t{%- endfor -%}\n
        Bank NameAccount NumberAccount Name
        {{row.bank}}{{row.bank_account_no}}{{row.account_name}}
        \n\n
        \n
        \n
        \n \n \n \n \n \n \n \n
        {{ frappe.db.get_value(\"User\", frappe.user,\n \"full_name\") }}
        Income Audit
        \n
        \n
        \n\n", + "idx": 0, + "line_breaks": 0, + "margin_bottom": 0.0, + "margin_left": 0.0, + "margin_right": 0.0, + "margin_top": 0.0, + "modified": "2025-03-05 21:49:10.807738", + "modified_by": "Administrator", + "module": "Inn Hotels", + "name": "Proforma Invoice", + "owner": "Administrator", + "print_format_builder": 0, + "print_format_builder_beta": 0, + "print_format_type": "Jinja", + "raw_printing": 0, + "show_section_headings": 0, + "standard": "Yes" } \ No newline at end of file From 1b4288cce5954f3e7c3e71664456fa1d974358de Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Wed, 5 Mar 2025 13:36:16 +0300 Subject: [PATCH 19/22] (edit) in inn_folio and nn_reservation add Multi Currency --- inn/inn_hotels/doctype/inn_folio/inn_folio.js | 220 +++++++++++++++--- .../doctype/inn_folio/inn_folio.json | 23 +- .../inn_folio_transaction_type.py | 39 +++- .../inn_reservation/inn_reservation.js | 58 +++++ .../inn_reservation/inn_reservation.json | 22 +- 5 files changed, 328 insertions(+), 34 deletions(-) diff --git a/inn/inn_hotels/doctype/inn_folio/inn_folio.js b/inn/inn_hotels/doctype/inn_folio/inn_folio.js index 84c8bab3..22cf2e45 100644 --- a/inn/inn_hotels/doctype/inn_folio/inn_folio.js +++ b/inn/inn_hotels/doctype/inn_folio/inn_folio.js @@ -7,12 +7,59 @@ var folio_transaction = null; frappe.ui.form.on("Inn Folio", { before_save: function (frm) { make_mandatory(frm); - }, - onload: function (frm) { - frm.get_field("folio_transaction").grid.only_sortable(); - make_read_only(frm); - make_fields_filtered(frm); - }, +}, +onload: function (frm) { + frm.get_field("folio_transaction").grid.only_sortable(); + make_read_only(frm); + make_fields_filtered(frm); + + // Fetch the exchange rate and currency symbol from the linked Inn Reservation + frappe.call({ + method: "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_exchange_rate", + args: { + reservation_id: frm.doc.reservation_id, + }, + callback: (response) => { + const exchange_rate = response.message.exchange_rate; + const currency_symbol = response.message.currency_symbol; + // console.log("444444444444444444444444444444444",currency_symbol) + + // Proceed with calculations only if exchange_rate is available + if (exchange_rate) { + const total_debit = frm.doc.total_debit || 0; + const total_credit = frm.doc.total_credit || 0; + const balance = frm.doc.balance || 0; + + // Calculate amounts in the base currency + const total_debit_by_currency = total_debit / exchange_rate; + const total_credit_by_currency = total_credit / exchange_rate; + const balance_by_currency = balance / exchange_rate; + + // Format the values with the currency symbol for display + const formatted_total_debit_by_currency = format_currency(total_debit_by_currency, currency_symbol); + const formatted_total_credit_by_currency = format_currency(total_credit_by_currency, currency_symbol); + const formatted_balance_by_currency = format_currency(balance_by_currency, currency_symbol); + + // Set the calculated values back to the form fields + frm.set_value("total_debit_by_currency", formatted_total_debit_by_currency); + frm.set_value("total_credit_by_currency", formatted_total_credit_by_currency); + frm.set_value("balance_by_currency", formatted_balance_by_currency); + + // Refresh the fields to reflect the updated values + frm.refresh_field("total_debit_by_currency"); + frm.refresh_field("total_credit_by_currency"); + frm.refresh_field("balance_by_currency"); + + // Display formatted values in the UI (optional) + frm.fields_dict.total_debit_by_currency.$wrapper.find(".control-value").text(formatted_total_debit_by_currency); + frm.fields_dict.total_credit_by_currency.$wrapper.find(".control-value").text(formatted_total_credit_by_currency); + frm.fields_dict.balance_by_currency.$wrapper.find(".control-value").text(formatted_balance_by_currency); + } else { + frappe.msgprint(__("Exchange rate not found for the linked reservation.")); + } + }, + }); +}, transfer_to_another_folio: function (frm) { if (frm.doc.__islocal !== 1) { let trx_selected = frm.get_field("folio_transaction").grid.get_selected(); @@ -340,8 +387,8 @@ function add_package(frm) { // Function to show pop up Dialog for adding new charge to the folio function add_charge(frm) { frappe.call({ - method: - "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_transaction_type", + method: + "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_transaction_type", args: { type: "Debit", }, @@ -365,6 +412,13 @@ function add_charge(frm) { columns: 2, reqd: 1, }, + { + label: __("Base Room Rate By Currency"), + fieldname: "base_room_rate_by_currency", + fieldtype: "Currency", + columns: 2, + reqd: 1, + }, { fieldname: "accb1", fieldtype: "Column Break", @@ -396,6 +450,37 @@ function add_charge(frm) { title: __("Add New Charge for Folio " + frm.doc.name), fields: fields, }); + + // Fetch exchange rate and currency symbol + frappe.call({ + method: "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_exchange_rate", + args: { reservation_id: frm.doc.reservation_id }, + callback: (exchange_rate_response) => { + const { exchange_rate, currency_symbol } = exchange_rate_response.message; + + // Add currency symbol to labels for clarity + d.fields_dict.amount.df.label = __("Amount") + ` (${frappe.sys_defaults.currency})`; + d.fields_dict.base_room_rate_by_currency.df.label = + __("Base Room Rate By Currency") + ` (${currency_symbol})`; + d.refresh(); + + // Add event listeners for dynamic calculations + d.fields_dict.amount.$input.on("input", () => { + const amount = d.get_value("amount"); + if (amount && exchange_rate) { + d.set_value("base_room_rate_by_currency", amount / exchange_rate); + } + }); + + d.fields_dict.base_room_rate_by_currency.$input.on("input", () => { + const base_room_rate_by_currency = d.get_value("base_room_rate_by_currency"); + if (base_room_rate_by_currency && exchange_rate) { + d.set_value("amount", base_room_rate_by_currency * exchange_rate); + } + }); + }, + }); + d.set_primary_action(__("Save"), () => { let remark_to_save = ""; let values = d.get_values(); @@ -443,13 +528,13 @@ function add_charge(frm) { // Function to show pop up Dialog for adding new payment to the folio function add_payment(frm) { frappe.call({ - method: - "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_transaction_type", - args: { - type: "Credit", - }, + method: + "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_transaction_type", + args: { + type: "Credit" + }, callback: (r) => { - let fields = [ + const fields = [ { label: __("Transaction Type"), fieldname: "transaction_type", @@ -458,9 +543,9 @@ function add_payment(frm) { reqd: 1, }, { - fieldname: "accb0", - fieldtype: "Column Break", - }, + fieldname: "accb0", + fieldtype: "Column Break" + }, { label: __("Amount"), fieldname: "amount", @@ -469,8 +554,14 @@ function add_payment(frm) { reqd: 1, }, { - fieldname: "acsb0", - fieldtype: "Section Break", + label: __("Base Room Rate By Currency"), + fieldname: "base_room_rate_by_currency", + fieldtype: "Currency", + columns: 2, + reqd: 1, + }, + { fieldname: "acsb0", + fieldtype: "Section Break" }, { label: __("Mode of Payment"), @@ -479,10 +570,9 @@ function add_payment(frm) { options: "Mode of Payment", reqd: 1, }, - { - fieldname: "accb1", - fieldtype: "Column Break", - }, + { fieldname: "accb1", + fieldtype: "Column Break" + }, { label: __("Sub Folio"), fieldname: "sub_folio", @@ -496,20 +586,52 @@ function add_payment(frm) { default: "A", reqd: 1, }, - { + { fieldname: "acsb1", - fieldtype: "Section Break", - }, + fieldtype: "Section Break" + }, { - label: "Remark", + label: __("Remark"), fieldname: "remark", fieldtype: "Small Text", }, ]; - var d = new frappe.ui.Dialog({ + + const d = new frappe.ui.Dialog({ title: __("Add New Payment for Folio " + frm.doc.name), fields: fields, }); + + // Fetch exchange rate and currency symbol + frappe.call({ + method: "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_exchange_rate", + args: { reservation_id: frm.doc.reservation_id }, + callback: (exchange_rate_response) => { + const { exchange_rate, currency_symbol } = exchange_rate_response.message; + + // Add currency symbol to labels for clarity + d.fields_dict.amount.df.label = __("Amount") + ` (${frappe.sys_defaults.currency})`; + d.fields_dict.base_room_rate_by_currency.df.label = + __("Base Room Rate By Currency") + ` (${currency_symbol})`; + d.refresh(); + + // Add event listeners for dynamic calculations + d.fields_dict.amount.$input.on("input", () => { + const amount = d.get_value("amount"); + if (amount && exchange_rate) { + d.set_value("base_room_rate_by_currency", amount / exchange_rate); + } + }); + + d.fields_dict.base_room_rate_by_currency.$input.on("input", () => { + const base_room_rate_by_currency = d.get_value("base_room_rate_by_currency"); + if (base_room_rate_by_currency && exchange_rate) { + d.set_value("amount", base_room_rate_by_currency * exchange_rate); + } + }); + }, + }); + d.set_primary_action(__("Save"), () => { let remark_to_save = ""; @@ -522,7 +644,7 @@ function add_payment(frm) { }); return; } - + if (d.get_values.remark !== undefined) { remark_to_save = d.get_values.remark; } @@ -565,6 +687,13 @@ function add_refund(frm) { columns: 2, reqd: 1, }, + { + label: __("Base Room Rate By Currency"), + fieldname: "base_room_rate_by_currency", + fieldtype: "Currency", + columns: 2, + reqd: 1, + }, { fieldname: "arcb0", fieldtype: "Column Break", @@ -596,9 +725,40 @@ function add_refund(frm) { if (frm.doc.balance > 0) { d.set_value("amount", frm.doc.balance); } + + + // Fetch exchange rate and currency symbol + frappe.call({ + method: "inn.inn_hotels.doctype.inn_folio_transaction_type.inn_folio_transaction_type.get_exchange_rate", + args: { reservation_id: frm.doc.reservation_id }, + callback: (exchange_rate_response) => { + const { exchange_rate, currency_symbol } = exchange_rate_response.message; + + // Add currency symbol to labels for clarity + d.fields_dict.amount.df.label = __("Amount") + ` (${frappe.sys_defaults.currency})`; + d.fields_dict.base_room_rate_by_currency.df.label = + __("Base Room Rate By Currency") + ` (${currency_symbol})`; + d.refresh(); + + // Add event listeners for dynamic calculations + d.fields_dict.amount.$input.on("input", () => { + const amount = d.get_value("amount"); + if (amount && exchange_rate) { + d.set_value("base_room_rate_by_currency", amount / exchange_rate); + } + }); + + d.fields_dict.base_room_rate_by_currency.$input.on("input", () => { + const base_room_rate_by_currency = d.get_value("base_room_rate_by_currency"); + if (base_room_rate_by_currency && exchange_rate) { + d.set_value("amount", base_room_rate_by_currency * exchange_rate); + } + }); + }, + }); d.set_primary_action(__("Save"), () => { let remark_to_save = ""; - + let values = d.get_values(); if (values.amount == 0) { frappe.msgprint({ diff --git a/inn/inn_hotels/doctype/inn_folio/inn_folio.json b/inn/inn_hotels/doctype/inn_folio/inn_folio.json index 7ae8502f..a80c8830 100644 --- a/inn/inn_hotels/doctype/inn_folio/inn_folio.json +++ b/inn/inn_hotels/doctype/inn_folio/inn_folio.json @@ -30,10 +30,13 @@ "channel", "sb3", "total_debit", + "total_debit_by_currency", "cb4", "total_credit", + "total_credit_by_currency", "cb5", "balance", + "balance_by_currency", "sb0", "toggle_void_transaction", "folio_transaction", @@ -236,10 +239,28 @@ "label": "Channel", "options": "Inn Channel", "read_only": 1 + }, + { + "fieldname": "total_debit_by_currency", + "fieldtype": "Data", + "label": "Total Debit By Currency", + "read_only": 1 + }, + { + "fieldname": "total_credit_by_currency", + "fieldtype": "Data", + "label": "Total Credit By Currency", + "read_only": 1 + }, + { + "fieldname": "balance_by_currency", + "fieldtype": "Data", + "label": "Balance By Currency", + "read_only": 1 } ], "links": [], - "modified": "2024-07-30 16:33:41.091293", + "modified": "2025-03-05 02:40:17.921502", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Folio", diff --git a/inn/inn_hotels/doctype/inn_folio_transaction_type/inn_folio_transaction_type.py b/inn/inn_hotels/doctype/inn_folio_transaction_type/inn_folio_transaction_type.py index 09a0b1c2..673e286a 100644 --- a/inn/inn_hotels/doctype/inn_folio_transaction_type/inn_folio_transaction_type.py +++ b/inn/inn_hotels/doctype/inn_folio_transaction_type/inn_folio_transaction_type.py @@ -5,6 +5,8 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from frappe import cache +import json class InnFolioTransactionType(Document): pass @@ -26,9 +28,42 @@ def get_accounts_from_id(id): def get_transaction_type(type): return_list = [] type_list = frappe.get_all('Inn Folio Transaction Type', - filters=[['type', '=', type], ['is_included', '=', 1]], - fields=['name']) + filters=[['type', '=', type], ['is_included', '=', 1]], + fields=['name']) for item in type_list: option_item = {'label': item.name, 'value': item.name} return_list.append(option_item) return return_list + + + + +@frappe.whitelist() +def get_exchange_rate(reservation_id): + try: + reservation = frappe.get_doc("Inn Reservation", reservation_id) + except frappe.DoesNotExistError: + frappe.throw(_("Reservation with ID {0} not found").format(reservation_id)) + + exchange_rate = reservation.exchange_rate + if not exchange_rate or exchange_rate <= 0: + frappe.throw(_("Invalid or missing exchange rate for reservation {0}").format(reservation_id)) + + currency_symbol = frappe.db.get_value("Currency", reservation.currency, "symbol") + result = { + "exchange_rate": exchange_rate, + "currency_symbol": currency_symbol or reservation.currency, # Fallback to currency code + } + + # Cache the result for 1 hour + cache_key = f"exchange_rate:{reservation_id}" + serialized_result = json.dumps(result) + frappe.cache().setex(cache_key, 3600, serialized_result) + + return result + +# @frappe.whitelist() +# def get_exchange_rate(reservation_id): +# reservation = frappe.get_doc("Inn Reservation", reservation_id) +# print("3333333333333333333333333333333333333333333333",reservation) +# return reservation.exchange_rate \ No newline at end of file diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js index 924d82dd..aeac3c96 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.js @@ -365,7 +365,65 @@ frappe.ui.form.on("Inn Reservation", { }, customer_id: function (frm) { toggle_room_detail(frm); + frm.trigger("fetch_currency"); }, + + fetch_currency: function (frm) { + // Check if customer_id is set + if (frm.doc.customer_id) { + frappe.call({ + method: "frappe.client.get_value", + args: { + doctype: "Customer", + fieldname: "default_currency", + filters: { name: frm.doc.customer_id } + }, + callback: function(r) { + if (r.message) { + frm.set_value("currency", r.message.default_currency); + } + } + }); + } else { + // If customer_id is not set, clear the currency field + frm.set_value("currency", ""); + } +}, + +before_save: function (frm) { + console.log("Before Save Event Triggered"); + + var base_room_rate = frm.doc.base_room_rate; + var exchange_rate = frm.doc.exchange_rate; + var currency = frm.doc.currency; + + // Log input values for debugging + // console.log("Base Room Rate:", base_room_rate); + // console.log("Exchange Rate:", exchange_rate); + // console.log("Currency:", currency); + + // Validate inputs + // if (!base_room_rate || !exchange_rate || !currency) { + // frappe.throw(__("Please ensure base_room_rate, exchange_rate, and currency are set.")); + // return; + // } + + // if (!exchange_rate || exchange_rate <= 0) { + // frappe.throw(__("Exchange rate must be greater than zero.")); + // return; + // } + + var base_room_rate_by_currency = base_room_rate / exchange_rate; + + base_room_rate_by_currency = Math.round(base_room_rate_by_currency * 100) / 100; + + var formatted_amount = format_currency(base_room_rate_by_currency, currency); + // console.log("Formatted Amount:", formatted_amount); + + frm.set_value ('base_room_rate_by_currency', formatted_amount); + + frm.refresh_field('base_room_rate_by_currency'); +}, channel: function (frm) { toggle_room_detail(frm); }, diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json index 3ea51f1b..7019c846 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json @@ -9,6 +9,8 @@ "naming_series", "status", "customer_id", + "currency", + "exchange_rate", "type", "group_id", "channel", @@ -27,6 +29,7 @@ "cb1", "room_rate", "base_room_rate", + "base_room_rate_by_currency", "init_actual_room_rate", "actual_room_rate", "discount", @@ -319,10 +322,27 @@ "fieldtype": "Percent", "label": "Discount", "precision": "2" + }, + { + "fieldname": "currency", + "fieldtype": "Link", + "label": "Currency", + "options": "Currency" + }, + { + "fieldname": "exchange_rate", + "fieldtype": "Float", + "label": "Exchange Rate" + }, + { + "fieldname": "base_room_rate_by_currency", + "fieldtype": "Data", + "label": "Base Room Rate By Currency", + "read_only": 1 } ], "links": [], - "modified": "2025-02-04 09:58:03.847590", + "modified": "2025-03-05 01:00:25.354481", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Reservation", From c935a46e0888151c103e73fca5794b2c64530fb6 Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Fri, 7 Mar 2025 02:44:19 +0300 Subject: [PATCH 20/22] (fix) in inn_folio and inn_folio_transaction_type/inn_folio_transaction_type --- inn/inn_hotels/doctype/inn_folio/inn_folio.js | 73 +++++++++++-------- .../inn_folio_transaction_type.py | 23 +++--- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/inn/inn_hotels/doctype/inn_folio/inn_folio.js b/inn/inn_hotels/doctype/inn_folio/inn_folio.js index 22cf2e45..fb73bca2 100644 --- a/inn/inn_hotels/doctype/inn_folio/inn_folio.js +++ b/inn/inn_hotels/doctype/inn_folio/inn_folio.js @@ -20,46 +20,57 @@ onload: function (frm) { reservation_id: frm.doc.reservation_id, }, callback: (response) => { - const exchange_rate = response.message.exchange_rate; - const currency_symbol = response.message.currency_symbol; - // console.log("444444444444444444444444444444444",currency_symbol) + if (response.message) { + const { exchange_rate, currency_symbol } = response.message; + + // Proceed only if exchange_rate is available and valid + if (exchange_rate) { + const total_debit = frm.doc.total_debit || 0; + const total_credit = frm.doc.total_credit || 0; + const balance = frm.doc.balance || 0; - // Proceed with calculations only if exchange_rate is available - if (exchange_rate) { - const total_debit = frm.doc.total_debit || 0; - const total_credit = frm.doc.total_credit || 0; - const balance = frm.doc.balance || 0; + // Calculate amounts in the base currency + const total_debit_by_currency = total_debit / exchange_rate; + const total_credit_by_currency = total_credit / exchange_rate; + const balance_by_currency = balance / exchange_rate; - // Calculate amounts in the base currency - const total_debit_by_currency = total_debit / exchange_rate; - const total_credit_by_currency = total_credit / exchange_rate; - const balance_by_currency = balance / exchange_rate; + // Format the values with the currency symbol for display + const formatted_total_debit_by_currency = format_currency(total_debit_by_currency, currency_symbol); + const formatted_total_credit_by_currency = format_currency(total_credit_by_currency, currency_symbol); + const formatted_balance_by_currency = format_currency(balance_by_currency, currency_symbol); - // Format the values with the currency symbol for display - const formatted_total_debit_by_currency = format_currency(total_debit_by_currency, currency_symbol); - const formatted_total_credit_by_currency = format_currency(total_credit_by_currency, currency_symbol); - const formatted_balance_by_currency = format_currency(balance_by_currency, currency_symbol); + // Set the calculated values back to the form fields + frm.set_value("total_debit_by_currency", formatted_total_debit_by_currency); + frm.set_value("total_credit_by_currency", formatted_total_credit_by_currency); + frm.set_value("balance_by_currency", formatted_balance_by_currency); - // Set the calculated values back to the form fields - frm.set_value("total_debit_by_currency", formatted_total_debit_by_currency); - frm.set_value("total_credit_by_currency", formatted_total_credit_by_currency); - frm.set_value("balance_by_currency", formatted_balance_by_currency); + // Refresh the fields to reflect the updated values + frm.refresh_field("total_debit_by_currency"); + frm.refresh_field("total_credit_by_currency"); + frm.refresh_field("balance_by_currency"); - // Refresh the fields to reflect the updated values - frm.refresh_field("total_debit_by_currency"); - frm.refresh_field("total_credit_by_currency"); - frm.refresh_field("balance_by_currency"); - - // Display formatted values in the UI (optional) - frm.fields_dict.total_debit_by_currency.$wrapper.find(".control-value").text(formatted_total_debit_by_currency); - frm.fields_dict.total_credit_by_currency.$wrapper.find(".control-value").text(formatted_total_credit_by_currency); - frm.fields_dict.balance_by_currency.$wrapper.find(".control-value").text(formatted_balance_by_currency); - } else { - frappe.msgprint(__("Exchange rate not found for the linked reservation.")); + // Optionally, update the UI display if the fields exist + if (frm.fields_dict.total_debit_by_currency && frm.fields_dict.total_debit_by_currency.$wrapper) { + frm.fields_dict.total_debit_by_currency.$wrapper.find(".control-value").text(formatted_total_debit_by_currency); + } + if (frm.fields_dict.total_credit_by_currency && frm.fields_dict.total_credit_by_currency.$wrapper) { + frm.fields_dict.total_credit_by_currency.$wrapper.find(".control-value").text(formatted_total_credit_by_currency); + } + if (frm.fields_dict.balance_by_currency && frm.fields_dict.balance_by_currency.$wrapper) { + frm.fields_dict.balance_by_currency.$wrapper.find(".control-value").text(formatted_balance_by_currency); + } + } else { + // Hide the currency fields if exchange_rate is not available + frm.toggle_display("total_debit_by_currency", false); + frm.toggle_display("total_credit_by_currency", false); + frm.toggle_display("balance_by_currency", false); + // frappe.msgprint(__("Exchange rate not found for the linked reservation.")); + } } }, }); }, + transfer_to_another_folio: function (frm) { if (frm.doc.__islocal !== 1) { let trx_selected = frm.get_field("folio_transaction").grid.get_selected(); diff --git a/inn/inn_hotels/doctype/inn_folio_transaction_type/inn_folio_transaction_type.py b/inn/inn_hotels/doctype/inn_folio_transaction_type/inn_folio_transaction_type.py index 673e286a..79cd8a38 100644 --- a/inn/inn_hotels/doctype/inn_folio_transaction_type/inn_folio_transaction_type.py +++ b/inn/inn_hotels/doctype/inn_folio_transaction_type/inn_folio_transaction_type.py @@ -43,25 +43,30 @@ def get_exchange_rate(reservation_id): try: reservation = frappe.get_doc("Inn Reservation", reservation_id) except frappe.DoesNotExistError: - frappe.throw(_("Reservation with ID {0} not found").format(reservation_id)) + return { + "exchange_rate": 0, + "currency_symbol": "" + } exchange_rate = reservation.exchange_rate + # Instead of throwing an error, return exchange_rate as 0 if missing or invalid if not exchange_rate or exchange_rate <= 0: - frappe.throw(_("Invalid or missing exchange rate for reservation {0}").format(reservation_id)) + result = { + "exchange_rate": 0, + "currency_symbol": reservation.currency + } + cache_key = f"exchange_rate:{reservation_id}" + frappe.cache().setex(cache_key, 3600, json.dumps(result)) + return result currency_symbol = frappe.db.get_value("Currency", reservation.currency, "symbol") result = { "exchange_rate": exchange_rate, - "currency_symbol": currency_symbol or reservation.currency, # Fallback to currency code + "currency_symbol": currency_symbol or reservation.currency } - - # Cache the result for 1 hour cache_key = f"exchange_rate:{reservation_id}" - serialized_result = json.dumps(result) - frappe.cache().setex(cache_key, 3600, serialized_result) - + frappe.cache().setex(cache_key, 3600, json.dumps(result)) return result - # @frappe.whitelist() # def get_exchange_rate(reservation_id): # reservation = frappe.get_doc("Inn Reservation", reservation_id) From b3a52f61dca1397a611fa03619177be33ac32b7d Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Fri, 7 Mar 2025 03:31:59 +0300 Subject: [PATCH 21/22] (edit) in folio show or hide Base Room Rate By Currency --- inn/inn_hotels/doctype/inn_folio/inn_folio.js | 65 ++++++++++++++----- .../inn_reservation/inn_reservation.json | 2 +- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/inn/inn_hotels/doctype/inn_folio/inn_folio.js b/inn/inn_hotels/doctype/inn_folio/inn_folio.js index fb73bca2..7d6fe947 100644 --- a/inn/inn_hotels/doctype/inn_folio/inn_folio.js +++ b/inn/inn_hotels/doctype/inn_folio/inn_folio.js @@ -429,6 +429,7 @@ function add_charge(frm) { fieldtype: "Currency", columns: 2, reqd: 1, + hidden: 1, }, { fieldname: "accb1", @@ -469,23 +470,30 @@ function add_charge(frm) { callback: (exchange_rate_response) => { const { exchange_rate, currency_symbol } = exchange_rate_response.message; + // Show or hide the Base Room Rate By Currency field based on exchange_rate + if (exchange_rate && exchange_rate !== 0) { + d.fields_dict.base_room_rate_by_currency.df.hidden = 0; + d.fields_dict.base_room_rate_by_currency.df.label = + __("Base Room Rate By Currency") + ` (${currency_symbol})`; + } else { + d.fields_dict.base_room_rate_by_currency.df.hidden = 1; + } + // Add currency symbol to labels for clarity d.fields_dict.amount.df.label = __("Amount") + ` (${frappe.sys_defaults.currency})`; - d.fields_dict.base_room_rate_by_currency.df.label = - __("Base Room Rate By Currency") + ` (${currency_symbol})`; d.refresh(); // Add event listeners for dynamic calculations d.fields_dict.amount.$input.on("input", () => { const amount = d.get_value("amount"); - if (amount && exchange_rate) { + if (amount && exchange_rate && exchange_rate !== 0) { d.set_value("base_room_rate_by_currency", amount / exchange_rate); } }); d.fields_dict.base_room_rate_by_currency.$input.on("input", () => { const base_room_rate_by_currency = d.get_value("base_room_rate_by_currency"); - if (base_room_rate_by_currency && exchange_rate) { + if (base_room_rate_by_currency && exchange_rate && exchange_rate !== 0) { d.set_value("amount", base_room_rate_by_currency * exchange_rate); } }); @@ -570,6 +578,7 @@ function add_payment(frm) { fieldtype: "Currency", columns: 2, reqd: 1, + hidden: 1, }, { fieldname: "acsb0", fieldtype: "Section Break" @@ -620,23 +629,30 @@ function add_payment(frm) { callback: (exchange_rate_response) => { const { exchange_rate, currency_symbol } = exchange_rate_response.message; + // Show or hide the Base Room Rate By Currency field based on exchange_rate + if (exchange_rate && exchange_rate !== 0) { + d.fields_dict.base_room_rate_by_currency.df.hidden = 0; + d.fields_dict.base_room_rate_by_currency.df.label = + __("Base Room Rate By Currency") + ` (${currency_symbol})`; + } else { + d.fields_dict.base_room_rate_by_currency.df.hidden = 1; + } + // Add currency symbol to labels for clarity d.fields_dict.amount.df.label = __("Amount") + ` (${frappe.sys_defaults.currency})`; - d.fields_dict.base_room_rate_by_currency.df.label = - __("Base Room Rate By Currency") + ` (${currency_symbol})`; d.refresh(); // Add event listeners for dynamic calculations d.fields_dict.amount.$input.on("input", () => { const amount = d.get_value("amount"); - if (amount && exchange_rate) { + if (amount && exchange_rate && exchange_rate !== 0) { d.set_value("base_room_rate_by_currency", amount / exchange_rate); } }); d.fields_dict.base_room_rate_by_currency.$input.on("input", () => { const base_room_rate_by_currency = d.get_value("base_room_rate_by_currency"); - if (base_room_rate_by_currency && exchange_rate) { + if (base_room_rate_by_currency && exchange_rate && exchange_rate !== 0) { d.set_value("amount", base_room_rate_by_currency * exchange_rate); } }); @@ -656,8 +672,8 @@ function add_payment(frm) { return; } - if (d.get_values.remark !== undefined) { - remark_to_save = d.get_values.remark; + if (d.get_values().remark !== undefined) { + remark_to_save = d.get_values().remark; } frappe.call({ method: @@ -704,6 +720,7 @@ function add_refund(frm) { fieldtype: "Currency", columns: 2, reqd: 1, + hidden: 1, }, { fieldname: "arcb0", @@ -733,10 +750,11 @@ function add_refund(frm) { }, ], }); + + // Set default amount to the current balance if balance is positive if (frm.doc.balance > 0) { d.set_value("amount", frm.doc.balance); } - // Fetch exchange rate and currency symbol frappe.call({ @@ -745,31 +763,39 @@ function add_refund(frm) { callback: (exchange_rate_response) => { const { exchange_rate, currency_symbol } = exchange_rate_response.message; + // Show or hide the Base Room Rate By Currency field based on exchange_rate + if (exchange_rate && exchange_rate !== 0) { + d.fields_dict.base_room_rate_by_currency.df.hidden = 0; + d.fields_dict.base_room_rate_by_currency.df.label = + __("Base Room Rate By Currency") + ` (${currency_symbol})`; + } else { + d.fields_dict.base_room_rate_by_currency.df.hidden = 1; + } + // Add currency symbol to labels for clarity d.fields_dict.amount.df.label = __("Amount") + ` (${frappe.sys_defaults.currency})`; - d.fields_dict.base_room_rate_by_currency.df.label = - __("Base Room Rate By Currency") + ` (${currency_symbol})`; d.refresh(); // Add event listeners for dynamic calculations d.fields_dict.amount.$input.on("input", () => { const amount = d.get_value("amount"); - if (amount && exchange_rate) { + if (amount && exchange_rate && exchange_rate !== 0) { d.set_value("base_room_rate_by_currency", amount / exchange_rate); } }); d.fields_dict.base_room_rate_by_currency.$input.on("input", () => { const base_room_rate_by_currency = d.get_value("base_room_rate_by_currency"); - if (base_room_rate_by_currency && exchange_rate) { + if (base_room_rate_by_currency && exchange_rate && exchange_rate !== 0) { d.set_value("amount", base_room_rate_by_currency * exchange_rate); } }); }, }); + d.set_primary_action(__("Save"), () => { let remark_to_save = ""; - + let values = d.get_values(); if (values.amount == 0) { frappe.msgprint({ @@ -779,9 +805,11 @@ function add_refund(frm) { }); return; } - if (d.get_values.remark !== undefined) { - remark_to_save = d.get_values.remark; + + if (d.get_values().remark !== undefined) { + remark_to_save = d.get_values().remark; } + frappe.call({ method: "inn.inn_hotels.doctype.inn_folio_transaction.inn_folio_transaction.add_charge", @@ -803,6 +831,7 @@ function add_refund(frm) { }); d.hide(); }); + d.show(); } diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json index 7019c846..db39b7d8 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json @@ -342,7 +342,7 @@ } ], "links": [], - "modified": "2025-03-05 01:00:25.354481", + "modified": "2025-03-07 02:06:50.830874", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Reservation", From 385604d20d0a31766d736d1bc214d0112c2ca0a1 Mon Sep 17 00:00:00 2001 From: sadiqalmusali Date: Fri, 7 Mar 2025 03:39:45 +0300 Subject: [PATCH 22/22] (edit) in inn_reservation update currency Mandatory if Exchange Rate > 0 --- inn/inn_hotels/doctype/inn_reservation/inn_reservation.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json index db39b7d8..3fb1753a 100644 --- a/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json +++ b/inn/inn_hotels/doctype/inn_reservation/inn_reservation.json @@ -327,6 +327,7 @@ "fieldname": "currency", "fieldtype": "Link", "label": "Currency", + "mandatory_depends_on": "eval:doc.exchange_rate > 0", "options": "Currency" }, { @@ -342,7 +343,7 @@ } ], "links": [], - "modified": "2025-03-07 02:06:50.830874", + "modified": "2025-03-07 02:37:31.635677", "modified_by": "Administrator", "module": "Inn Hotels", "name": "Inn Reservation",