diff --git a/erpnext/translations/fr.csv b/erpnext/translations/fr.csv index 78fedea82661f9263b0491e0d5b2e6d822e2d94c..e31327a789f601993f7e7974c45708ead4dc9340 100644 --- a/erpnext/translations/fr.csv +++ b/erpnext/translations/fr.csv @@ -12902,6 +12902,7 @@ Venue Registration Form,Formulaire d'inscription au lieu, Venue Selected Company,Société sélectionnée par lieu, Venue Settings,Paramètres du lieu, Venue Units of Measure,Unités de mesure du lieu, +Venue UOM Conversion,Conversion d'unité du lieu, Venue,Lieu, Verification failed please check the link,La vérification a échoué. Veuillez vérifier votre lien., Verified By,Vérifié Par, @@ -13807,4 +13808,11 @@ you must select Capital Work in Progress Account in accounts table,Vous devez s 🗃️ Manufacturing Data & Transactions,🗃️ Données de production & Transactions, 🗃️ Projects Data,🗃️ Données des projets, 🗃️ Reports & Masters,🗃️ Rapports & Données de base, -Accounting Data and Transactions,Données comptables et Transactions, \ No newline at end of file +Accounting Data and Transactions,Données comptables et Transactions, +Week UOM,Unité de mesure de semaine, +Day UOM,Unité de mesure de jour, +Short Bookings,Réservations courtes, +Long Bookings,Réservations longues, +Example: For the unit '3 month' set a quantity of 3 and a target unit of Month.,"Exemple : Pour l'unité '3 mois', définissez une quantité de 3 et une unité cible de Mois.", +Source UOM,Unité de mesure source, +Target UOM,Unité de mesure cible, \ No newline at end of file diff --git a/erpnext/venue/doctype/item_booking/item_booking.py b/erpnext/venue/doctype/item_booking/item_booking.py index d78f2f9667fcddc21de4060857f7a91deea34df3..af34159dfef540e8fd142ff163661309824c6ea2 100644 --- a/erpnext/venue/doctype/item_booking/item_booking.py +++ b/erpnext/venue/doctype/item_booking/item_booking.py @@ -817,7 +817,7 @@ class ItemBookingAvailabilities: as_dict=True, ) - self.uom = uom or self.item_doc.sales_uom + self.uom = uom or self.item_doc.sales_uom or self.item_doc.stock_uom self.duration = get_uom_in_minutes(self.uom) if self.item_doc.enable_item_booking and self.duration == 0: diff --git a/erpnext/venue/doctype/venue_settings/venue_settings.json b/erpnext/venue/doctype/venue_settings/venue_settings.json index 4fa3cc9d9fea363ae9d942956b197264e575a5b2..d6028eeb61fcca67bce813c83a4e11b63fbc280d 100644 --- a/erpnext/venue/doctype/venue_settings/venue_settings.json +++ b/erpnext/venue/doctype/venue_settings/venue_settings.json @@ -21,11 +21,17 @@ "enable_multi_companies", "cart_settings_overrides", "unit_of_measure_tab", + "short_bookings_section", "minute_uom", - "column_break_8", - "month_uom", + "venue_units_of_measure", "section_break_20", - "venue_units_of_measure" + "month_uom", + "column_break_uuvm", + "week_uom", + "column_break_jmrs", + "day_uom", + "section_break_lnrr", + "venue_long_uoms" ], "fields": [ { @@ -38,6 +44,7 @@ "fieldname": "minute_uom", "fieldtype": "Link", "label": "Minute UOM", + "mandatory_depends_on": "eval:doc.venue_units_of_measure?.length", "options": "UOM" }, { @@ -70,10 +77,6 @@ "label": "Month UOM", "options": "UOM" }, - { - "fieldname": "column_break_8", - "fieldtype": "Column Break" - }, { "default": "0", "fieldname": "no_overlap_per_item", @@ -144,19 +147,58 @@ "label": "Units of Measure" }, { + "description": "Example: For the unit Half-Day set a duration of 4 hours.", "fieldname": "venue_units_of_measure", "fieldtype": "Table", - "label": "Venue Units of Measure", + "label": "Conversion Table", "options": "Venue Units of Measure" }, { "fieldname": "section_break_20", + "fieldtype": "Section Break", + "hide_border": 1, + "label": "Long Bookings" + }, + { + "fieldname": "short_bookings_section", + "fieldtype": "Section Break", + "label": "Short Bookings" + }, + { + "fieldname": "week_uom", + "fieldtype": "Link", + "label": "Week UOM", + "options": "UOM" + }, + { + "fieldname": "column_break_uuvm", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_lnrr", "fieldtype": "Section Break" + }, + { + "description": "Example: For the unit '3 month' set a quantity of 3 and a target unit of Month.", + "fieldname": "venue_long_uoms", + "fieldtype": "Table", + "label": "Conversion Table", + "options": "Venue UOM Conversion" + }, + { + "fieldname": "column_break_jmrs", + "fieldtype": "Column Break" + }, + { + "fieldname": "day_uom", + "fieldtype": "Link", + "label": "Day UOM", + "options": "UOM" } ], "issingle": 1, "links": [], - "modified": "2023-06-08 15:08:57.220809", + "modified": "2024-02-28 15:25:05.173966", "modified_by": "Administrator", "module": "Venue", "name": "Venue Settings", diff --git a/erpnext/venue/doctype/venue_settings/venue_settings.py b/erpnext/venue/doctype/venue_settings/venue_settings.py index 4ea19a3a21e54e8345259b8e3e566de1bbfc989b..1720ba35dea514e0e809c73e5b58bba2b9d19de5 100644 --- a/erpnext/venue/doctype/venue_settings/venue_settings.py +++ b/erpnext/venue/doctype/venue_settings/venue_settings.py @@ -7,45 +7,100 @@ from frappe.utils import cint class VenueSettings(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + from erpnext.venue.doctype.venue_cart_settings.venue_cart_settings import VenueCartSettings + from erpnext.venue.doctype.venue_units_of_measure.venue_units_of_measure import ( + VenueUnitsofMeasure, + ) + from erpnext.venue.doctype.venue_uom_conversion.venue_uom_conversion import VenueUOMConversion + + allow_event_cancellation: DF.Check + cancellation_delay: DF.Duration | None + cart_settings_overrides: DF.Table[VenueCartSettings] + clear_item_booking_draft_duration: DF.Int + confirm_booking_after_payment: DF.Check + day_uom: DF.Link | None + enable_multi_companies: DF.Check + enable_simultaneous_booking: DF.Check + minute_uom: DF.Link | None + month_uom: DF.Link | None + no_overlap_per_item: DF.Check + registration_item_code: DF.Link | None + role_allowed_to_skip_cart: DF.Link | None + sync_with_google_calendar: DF.Check + venue_long_uoms: DF.Table[VenueUOMConversion] + venue_units_of_measure: DF.Table[VenueUnitsofMeasure] + week_uom: DF.Link | None + # end: auto-generated types + # Support for multiple companies/venues with distinct items def onload(self): # see: webshop_settings.py self.get("__onload").quotation_series = frappe.get_meta("Quotation").get_options("naming_series") def configure_uom_conversions(self): - if not self.minute_uom: - pass - - for row in self.venue_units_of_measure: - duration = cint(row.duration) / 60 - if value := frappe.db.get_value( - "UOM Conversion Factor", dict(from_uom=row.unit_of_measure, to_uom=self.minute_uom), "value" - ): - if value != duration: - frappe.db.set_value( - "UOM Conversion Factor", - dict(from_uom=row.unit_of_measure, to_uom=self.minute_uom), - "value", - duration, - ) - - else: - category = frappe.db.exists("UOM Category", "Time") - if not category: - category = frappe.db.exists("UOM Category", _("Time")) - - if not category: - category_doc = frappe.new_doc("UOM Category", _("Time")) - category_doc.category_name = _("Time") - category_doc.insert(ignore_permissions=True) - category = category_doc.name - - conversion = frappe.new_doc("UOM Conversion Factor") - conversion.category = category - conversion.from_uom = row.unit_of_measure - conversion.to_uom = self.minute_uom - conversion.value = duration - conversion.insert(ignore_permissions=True) + if self.minute_uom: + for row in self.venue_units_of_measure: + self.venue_upsert_uom_conversion(row.unit_of_measure, self.minute_uom, cint(row.duration) / 60) + + self.venue_configure_long_uom_conversions() + + def venue_upsert_uom_conversion(self, from_uom: str, to_uom: str, value: int | float): + if not from_uom or not to_uom or value <= 0: + return + + conversion = frappe.db.get_value( + "UOM Conversion Factor", + filters={"from_uom": from_uom, "to_uom": to_uom}, + fieldname=["name", "value"], + as_dict=True, + for_update=True, + ) + if conversion and conversion.value == value: + return + + if conversion: + conversion = frappe.get_doc("UOM Conversion Factor", conversion) + else: + conversion = frappe.new_doc("UOM Conversion Factor") + + conversion.category = self.venue_make_time_category() + conversion.from_uom = from_uom + conversion.to_uom = to_uom + conversion.value = value + conversion.save(ignore_permissions=True) + + def venue_configure_long_uom_conversions(self): + uom_mapping = { + "Month": self.month_uom, + "Week": self.week_uom, + "Day": self.day_uom, + "Minute": self.minute_uom, + } + for row in self.venue_long_uoms: + to_uom = uom_mapping[row.target_type] + if to_uom: + self.venue_upsert_uom_conversion(row.from_uom, to_uom, row.value) + + def venue_make_time_category(self): + category = frappe.db.exists("UOM Category", "Time") + if not category: + category = frappe.db.exists("UOM Category", _("Time")) + + if not category: + category_doc = frappe.new_doc("UOM Category") + category_doc.category_name = _("Time") + category_doc.insert(ignore_permissions=True) + category = category_doc.name + + return category @frappe.whitelist() @@ -85,11 +140,24 @@ def simultaneous_booking_enabled(): @frappe.whitelist() def get_booking_uoms(*args): - minute = frappe.db.get_single_value("Venue Settings", "minute_uom") - month = frappe.db.get_single_value("Venue Settings", "month_uom") - - uoms = [[month]] if month else [] - return uoms + [ - [uom] - for uom in frappe.get_all("UOM Conversion Factor", filters={"to_uom": minute}, pluck="from_uom") - ] + valid_uoms: list[str] = [] + + venue_settings = frappe.get_single("Venue Settings") + for fieldname in ["minute_uom", "day_uom", "week_uom", "month_uom"]: + if uom := venue_settings.get(fieldname): + valid_uoms.append(uom) + + all_uoms = valid_uoms + frappe.get_all( + "UOM Conversion Factor", filters={"to_uom": ("in", valid_uoms)}, pluck="from_uom" + ) + + out = [] + seen = set() + for uom in all_uoms: + print(uom) + if uom not in seen: + out.append([uom]) + seen.add(uom) + + out.sort() + return out diff --git a/erpnext/venue/doctype/venue_units_of_measure/venue_units_of_measure.json b/erpnext/venue/doctype/venue_units_of_measure/venue_units_of_measure.json index 67dd100197755f48119936444758c6a3ee383939..09d98ba9da00fb6b8b497fcaf640de8816fdbf4d 100644 --- a/erpnext/venue/doctype/venue_units_of_measure/venue_units_of_measure.json +++ b/erpnext/venue/doctype/venue_units_of_measure/venue_units_of_measure.json @@ -29,7 +29,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2023-06-08 15:03:39.899851", + "modified": "2024-02-28 14:58:03.712023", "modified_by": "Administrator", "module": "Venue", "name": "Venue Units of Measure", diff --git a/erpnext/venue/doctype/venue_units_of_measure/venue_units_of_measure.py b/erpnext/venue/doctype/venue_units_of_measure/venue_units_of_measure.py index 4a81d233528360430f5383b583c564d0c53610f2..8745cc1f99523924b0454597d2865d1636f4cce9 100644 --- a/erpnext/venue/doctype/venue_units_of_measure/venue_units_of_measure.py +++ b/erpnext/venue/doctype/venue_units_of_measure/venue_units_of_measure.py @@ -5,4 +5,19 @@ from frappe.model.document import Document class VenueUnitsofMeasure(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + duration: DF.Duration + parent: DF.Data + parentfield: DF.Data + parenttype: DF.Data + unit_of_measure: DF.Link + # end: auto-generated types + pass diff --git a/erpnext/venue/doctype/venue_uom_conversion/__init__.py b/erpnext/venue/doctype/venue_uom_conversion/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/erpnext/venue/doctype/venue_uom_conversion/venue_uom_conversion.json b/erpnext/venue/doctype/venue_uom_conversion/venue_uom_conversion.json new file mode 100644 index 0000000000000000000000000000000000000000..4d3638ea73043c88e593faec21180bbb0e780256 --- /dev/null +++ b/erpnext/venue/doctype/venue_uom_conversion/venue_uom_conversion.json @@ -0,0 +1,61 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2024-02-28 13:18:30.708890", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "from_uom", + "value", + "target_type", + "to_uom" + ], + "fields": [ + { + "fieldname": "from_uom", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Source UOM", + "link_filters": "[[{\"fieldname\":\"uom\",\"field_option\":\"UOM\"},\"enabled\",\"=\",1]]", + "options": "UOM", + "reqd": 1 + }, + { + "default": "1", + "fieldname": "value", + "fieldtype": "Int", + "in_list_view": 1, + "label": "Quantity", + "non_negative": 1, + "reqd": 1 + }, + { + "fieldname": "target_type", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Target UOM", + "options": "Month\nWeek\nDay", + "reqd": 1 + }, + { + "fieldname": "to_uom", + "fieldtype": "Link", + "hidden": 1, + "options": "Item", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2024-02-28 13:31:47.522923", + "modified_by": "Administrator", + "module": "Venue", + "name": "Venue UOM Conversion", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} diff --git a/erpnext/venue/doctype/venue_uom_conversion/venue_uom_conversion.py b/erpnext/venue/doctype/venue_uom_conversion/venue_uom_conversion.py new file mode 100644 index 0000000000000000000000000000000000000000..c8244c0467fff7b4e1274b7c5029a1b87b169019 --- /dev/null +++ b/erpnext/venue/doctype/venue_uom_conversion/venue_uom_conversion.py @@ -0,0 +1,26 @@ +# Copyright (c) 2024, Dokos SAS and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class VenueUOMConversion(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + from_uom: DF.Link + parent: DF.Data + parentfield: DF.Data + parenttype: DF.Data + target_type: DF.Literal["Month", "Week", "Day"] + to_uom: DF.Link | None + value: DF.Int + # end: auto-generated types + + pass