diff --git a/erpnext/public/scss/erpnext.scss b/erpnext/public/scss/erpnext.scss index c86d7114946c67dca0da3164817e6f5c17e195d5..c3f1f5df00676eb99876ef2a39778398e55bba78 100644 --- a/erpnext/public/scss/erpnext.scss +++ b/erpnext/public/scss/erpnext.scss @@ -207,4 +207,30 @@ .frappe-control[data-fieldname="deductible_details"] .like-disabled-input, .frappe-control[data-fieldname="collected_details"] .like-disabled-input { background-color: transparent; +} + +/* Venue Module: removed in v5 */ +.conversions-table-row { + color: var(--gray-900); + line-height: var(--text-line-height-3xl); + font-size: var(--text-md); + font-weight: var(--weight-medium); + padding: 20px; + background-color: rgb(247, 249, 252); + border-radius: 12px; + + .conversions-table-row-delete { + cursor: pointer; + } +} + +.empty-conversion-table { + border: 1px dashed var(--gray-400); + border-radius: 5px; + min-height: 80px; + + .empty-conversion-table-text { + color: var(--gray-600); + font-weight: var(--weight-medium); + } } \ No newline at end of file diff --git a/erpnext/venue/doctype/booking_credit_type/booking_credit_type.js b/erpnext/venue/doctype/booking_credit_type/booking_credit_type.js index dcb5a44bd727b72ffe46c2da98204cf84784a2d1..81044afdc5f6a172223be6e299286ed3a18f317f 100644 --- a/erpnext/venue/doctype/booking_credit_type/booking_credit_type.js +++ b/erpnext/venue/doctype/booking_credit_type/booking_credit_type.js @@ -1,54 +1,141 @@ -// Copyright (c) 2023, Dokos SAS and contributors +// Copyright (c) 2025, Dokos SAS and contributors // For license information, please see license.txt -frappe.ui.form.on('Booking Credit Type', { - setup: function(frm) { - frm.set_query("uom", "conversion_table", function(doc) { +frappe.ui.form.on("Booking Credit Type", { + setup(frm) { + frm.set_query("uom", "conversion_table", function (doc) { return { - query: "erpnext.venue.doctype.venue_settings.venue_settings.get_booking_uoms", + query: "bookings.bookings.doctype.venue_settings.venue_settings.get_booking_uoms", }; }); - frm.set_query("item", "conversion_table", function(doc) { + frm.set_query("item", "conversion_table", function (doc) { return { - "filters": { - "enable_item_booking": 1 - } + filters: { + enable_item_booking: 1, + }, }; }); + }, + + refresh(frm) { + if (!frm.conversion_rules) { + frm.conversion_rules = new ConversionRuleTable({ frm: frm }); + } + + frm.conversion_rules.refresh() + }, + + new_rule_button(frm) { + const dialog = new frappe.ui.Dialog({ + title: __("Add a new conversion rule for this credit type"), + fields: [ + { + label: __("How many credits should be used ?"), + fieldname: "credits", + fieldtype: "Int", + placeholder: "1", + required: true + }, + { + label: __("Against one"), + fieldname: "uom", + fieldtype: "Link", + options: "UOM", + placeholder: "Unit", + required: true, + get_query: function () { + return { query: "bookings.bookings.doctype.venue_settings.venue_settings.get_booking_uoms" }; + } + }, + { + label: __("For this resource"), + fieldname: "item", + fieldtype: "Link", + options: "Item", + placeholder: __("20 coworking days ticket"), + required: true, + get_query: function () { + return { + filters: { + enable_item_booking: 1, + }, + }; + } + } + ], + primary_action_label: __("Add this rule"), + primary_action: () => { + frm.add_child("conversion_table", dialog.get_values()); + frm.conversion_rules && frm.conversion_rules.refresh(); + dialog.hide(); + } + }); + dialog.show() } }); -frappe.tour['Booking Credit Type'] = { - "fr": [ - { - fieldname: "label", - description: "Le libellé de votre type de crédit de réservation. Le libellé vous permet de distinguer facilement vos types de crédits." - }, - { - fieldname: "item", - description: "L'article auquel ce type de crédit de réservation est associé. Le couple Article/Unité de mesure permet au système de déterminer le bon type de crédits à ajouter/déduire." - }, - { - fieldname: "uom", - description: "L'unité de mesure à laquelle ce type de crédits de réservation s'applique. Le couple Article/Unité de mesure permet au système de déterminer le bon type de crédits à ajouter/déduire." - }, - { - fieldname: "credits", - description: "Le nombre de crédits de réservation qu'une unité du couple Article/Unité de mesure permet d'allouer." - }, - { - fieldname: "validity", - description: "Nombre de jours pendant lesquels les crédits alloués sont disponibles avant d'expirer." - }, - { - fieldname: "conversion_table", - description: ` - Ce tableau permet de définir les articles réservables pouvant être échangés contre un crédit de réservation de ce type.
- La conversion se fera toujours pour un couple Article/Unité de mesure.
- Le champ "Crédits" permet de définir un coefficient de conversion.
- Ex. 1 ticket coworking demi-journée peut être échangé contre 4 heures de coworking. - ` - }, - ] -} \ No newline at end of file + +class ConversionRuleTable { + constructor(opts) { + Object.assign(this, opts) + } + + refresh() { + this.frm.get_field("conversion_table_html").wrapper.innerHTML = "" + this.get_table_content() + this.frm.get_field("conversion_table_html").wrapper.appendChild(this.content) + this.frm.refresh_fields("conversion_table_html"); + } + + get_table_content() { + const rows_content = this.frm.doc.conversion_table.map(row => { + const container = document.createElement("div"); + container.classList.add("my-2", "py-2", "conversions-table-row", "d-flex"); + const credits = document.createElement("span"); + credits.innerHTML = + frappe.utils.icon("es-line-check") + + " " + + __("{} credit gives access to 1", [row.credits || "0"]) + + " " + + __("{} of", [__(row.uom)]) + + " " + + `${row.item}` + + container.appendChild(credits) + + const delete_button = document.createElement("div"); + delete_button.classList.add("ml-auto", "conversions-table-row-delete") + delete_button.innerHTML = frappe.utils.icon("es-line-delete") + delete_button.addEventListener("click", () => { + this.frm.clear_table("conversion_table"); + const new_items = this.frm.doc.conversion_table.filter(item => item.name != row.name); + new_items.forEach(new_item => { + this.frm.add_child("conversion_table", new_item); + }) + this.refresh() + }) + + container.appendChild(delete_button) + + return container + }) + + const outerContainer = document.createElement("div"); + outerContainer.classList.add("my-4"); + + if (rows_content.length) { + rows_content.forEach(r => outerContainer.appendChild(r)) + } else { + const emptyState = document.createElement("div"); + emptyState.classList.add("my-2", "py-2", "d-flex", "empty-conversion-table"); + const emptyStateText = document.createElement("div"); + emptyStateText.classList.add("m-auto", "empty-conversion-table-text") + emptyStateText.textContent = __("No rules added") + emptyState.appendChild(emptyStateText) + outerContainer.appendChild(emptyState); + } + + this.content = outerContainer + } +} diff --git a/erpnext/venue/doctype/booking_credit_type/booking_credit_type.json b/erpnext/venue/doctype/booking_credit_type/booking_credit_type.json index 1be16c4d0db614cbc63a32e9799a2dd474a94198..f92203f9ff59861e2460a7b802ab200dd3506381 100644 --- a/erpnext/venue/doctype/booking_credit_type/booking_credit_type.json +++ b/erpnext/venue/doctype/booking_credit_type/booking_credit_type.json @@ -1,145 +1,174 @@ { - "actions": [], - "allow_rename": 1, - "autoname": "field:label", - "creation": "2023-03-13 10:19:07.269371", - "default_view": "List", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "disabled", - "section_break_2", - "label", - "item", - "uom", - "column_break_3", - "credits", - "validity", - "conversions_section", - "conversion_table" - ], - "fields": [ - { - "fieldname": "label", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Label", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "item", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Item", - "options": "Item", - "reqd": 1 - }, - { - "depends_on": "eval:!doc.__islocal", - "fieldname": "conversions_section", - "fieldtype": "Section Break", - "label": "Conversions" - }, - { - "fieldname": "conversion_table", - "fieldtype": "Table", - "label": "Conversion Table", - "options": "Booking Credit Type Conversions" - }, - { - "fieldname": "column_break_3", - "fieldtype": "Column Break" - }, - { - "description": "Leave empty if credits have a no validity end date", - "fieldname": "validity", - "fieldtype": "Duration", - "label": "Validity" - }, - { - "default": "1", - "description": "Number of credits allocation for each item purchase", - "fieldname": "credits", - "fieldtype": "Int", - "in_list_view": 1, - "label": "Credits", - "reqd": 1 - }, - { - "fieldname": "uom", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Unit of Measure", - "options": "UOM", - "reqd": 1 - }, - { - "default": "0", - "depends_on": "eval:!doc.__islocal", - "fieldname": "disabled", - "fieldtype": "Check", - "label": "Disabled" - }, - { - "fieldname": "section_break_2", - "fieldtype": "Section Break" - } - ], - "index_web_pages_for_search": 1, - "links": [ - { - "group": "Links", - "link_doctype": "Booking Credit", - "link_fieldname": "booking_credit_type" - }, - { - "group": "Links", - "link_doctype": "Booking Credit Usage", - "link_fieldname": "booking_credit_type" - }, - { - "group": "Links", - "link_doctype": "Booking Credit Ledger", - "link_fieldname": "booking_credit_type" - } - ], - "modified": "2024-11-26 16:39:32.210780", - "modified_by": "Administrator", - "module": "Venue", - "name": "Booking Credit Type", - "naming_rule": "By fieldname", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "select": 1, - "share": 1, - "write": 1 - }, - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Venue Manager", - "select": 1, - "share": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "states": [] -} + "actions": [], + "allow_rename": 1, + "autoname": "field:label", + "creation": "2023-03-13 10:19:07.269371", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "disabled", + "section_break_2", + "label", + "item", + "uom", + "column_break_3", + "credits", + "validity", + "conversions_section", + "conversion_table_html", + "new_rule_button", + "conversion_table" + ], + "fields": [ + { + "default": "0", + "depends_on": "eval:!doc.__islocal", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled" + }, + { + "fieldname": "section_break_2", + "fieldtype": "Section Break" + }, + { + "description": "eg. 20 coworking days - 2025", + "fieldname": "label", + "fieldtype": "Data", + "in_list_view": 1, + "label": "What is the name of your booking credit type ?", + "placeholder": "20 coworking days - 2025", + "reqd": 1, + "unique": 1 + }, + { + "depends_on": "eval:doc.label", + "description": "eg. 20 coworking days ticket", + "fieldname": "item", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Which item will be used for invoicing ?", + "options": "Item", + "placeholder": "20 coworking days", + "reqd": 1 + }, + { + "depends_on": "eval:doc.label&&doc.item", + "description": "eg. Unit", + "fetch_from": "item.sales_uom", + "fetch_if_empty": 1, + "fieldname": "uom", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Which invoicing unit of measure should generate credits ?", + "options": "UOM", + "reqd": 1 + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "default": "1", + "depends_on": "eval:doc.label&&doc.item&&doc.uom", + "description": "eg. 1 unit of the item \"20 coworking days\" should give 20 credits to the buyer", + "fieldname": "credits", + "fieldtype": "Int", + "in_list_view": 1, + "label": "How many credit should be attributed for each sales ?", + "placeholder": "20", + "reqd": 1 + }, + { + "depends_on": "eval:doc.label&&doc.item&&doc.uom&&doc.credits", + "description": "Add a duration to set an expiry period or leave empty if these credits have no validity end date", + "fieldname": "validity", + "fieldtype": "Duration", + "label": "How long should these credits stay active ?", + "placeholder": "360j" + }, + { + "depends_on": "eval:doc.label&&doc.item&&doc.uom", + "fieldname": "conversions_section", + "fieldtype": "Section Break", + "label": "Conversion Rules" + }, + { + "fieldname": "conversion_table", + "fieldtype": "Table", + "hidden": 1, + "label": "Conversion Table", + "options": "Booking Credit Type Conversions" + }, + { + "fieldname": "conversion_table_html", + "fieldtype": "HTML", + "label": "Conversion Table HTML" + }, + { + "fieldname": "new_rule_button", + "fieldtype": "Button", + "label": "New rule" + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "links": [ + { + "group": "Links", + "link_doctype": "Booking Credit", + "link_fieldname": "booking_credit_type" + }, + { + "group": "Links", + "link_doctype": "Booking Credit Usage", + "link_fieldname": "booking_credit_type" + }, + { + "group": "Links", + "link_doctype": "Booking Credit Ledger", + "link_fieldname": "booking_credit_type" + } + ], + "modified": "2025-03-25 13:55:18.780111", + "modified_by": "Administrator", + "module": "Venue", + "name": "Booking Credit Type", + "naming_rule": "By fieldname", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "select": 1, + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Venue Manager", + "select": 1, + "share": 1, + "write": 1 + } + ], + "row_format": "Dynamic", + "sort_field": "modified", + "sort_order": "DESC", + "states": [] + } + \ No newline at end of file