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