diff --git a/sale_crm_event_reservation/README.rst b/sale_crm_event_reservation/README.rst new file mode 100644 index 000000000..22c7712fa --- /dev/null +++ b/sale_crm_event_reservation/README.rst @@ -0,0 +1,138 @@ +========================================== +Create event quotations from opportunities +========================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:08a4d72558ab1cb7796630463d64cce3503eaa98283529e2132d7cd067fbc2b2 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Mature-brightgreen.png + :target: https://odoo-community.org/page/development-status + :alt: Mature +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fevent-lightgray.png?logo=github + :target: https://github.com/OCA/event/tree/17.0/sale_crm_event_reservation + :alt: OCA/event +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/event-17-0/event-17-0-sale_crm_event_reservation + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/event&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of *crm_event*, +*event_sale_reservation* and *sale_crm* to support fast generation of +event quotations from opportunities and to allow you to sell events like +a boss. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +To install this module, you need to: + +1. Install *crm_event* and *event_sale_reservation* from + https://github.com/OCA/event. + +Configuration +============= + +To make use of this module, a user needs these minimal permissions: + +- Sales / User: Own Documents Only +- Events / User + +Usage +===== + +To use this module, you need to: + +1. Go to *CRM > My Pipeline*. +2. Create one opportunity. +3. Set basic fields. +4. Set *Customer*, *Event type* and *Seats Wanted*. +5. Click on *New Event Quotation*. + +A wizard will open. If you want to register the customer in an scheduled +event: + +1. Select *Mode = Register in scheduled event*. +2. Select *Event* and *Ticket* +3. Click on *Generate quotation* + +Instead, if you want to reserve some seats for the customer in some +upcoming event: + +1. Select *Mode = Reserve upcoming event*. +2. Select *Product*, which must be a reservation product for the chosen + event type. +3. Click on *Generate quotation* + +In either case, you will be presented with a sale order created just for +you. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Jairo Llopis + - Stefan Ungureanu + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-chienandalu| image:: https://github.com/chienandalu.png?size=40px + :target: https://github.com/chienandalu + :alt: chienandalu +.. |maintainer-pilarvargas-tecnativa| image:: https://github.com/pilarvargas-tecnativa.png?size=40px + :target: https://github.com/pilarvargas-tecnativa + :alt: pilarvargas-tecnativa + +Current `maintainers `__: + +|maintainer-chienandalu| |maintainer-pilarvargas-tecnativa| + +This module is part of the `OCA/event `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_crm_event_reservation/__init__.py b/sale_crm_event_reservation/__init__.py new file mode 100644 index 000000000..8b31d3971 --- /dev/null +++ b/sale_crm_event_reservation/__init__.py @@ -0,0 +1,2 @@ +from . import reports +from . import wizards diff --git a/sale_crm_event_reservation/__manifest__.py b/sale_crm_event_reservation/__manifest__.py new file mode 100644 index 000000000..318e4c0b3 --- /dev/null +++ b/sale_crm_event_reservation/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2021 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Create event quotations from opportunities", + "summary": "Combine event reservations, opportunities and quotations", + "version": "17.0.1.0.0", + "development_status": "Mature", + "category": "Marketing", + "website": "https://github.com/OCA/event", + "author": "Tecnativa, Odoo Community Association (OCA)", + "maintainers": ["chienandalu", "pilarvargas-tecnativa"], + "license": "AGPL-3", + "application": False, + "installable": True, + "auto_install": True, + "depends": ["crm_event", "event_sale_reservation", "sale_crm"], + "data": [ + "reports/event_type_report_views.xml", + "security/ir.model.access.csv", + "wizards/crm_lead_event_sale_wizard_views.xml", + "views/crm_lead_views.xml", + ], +} diff --git a/sale_crm_event_reservation/i18n/es.po b/sale_crm_event_reservation/i18n/es.po new file mode 100644 index 000000000..7be28b76a --- /dev/null +++ b/sale_crm_event_reservation/i18n/es.po @@ -0,0 +1,173 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_crm_event_reservation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-05 16:37+0000\n" +"PO-Revision-Date: 2023-10-29 20:41+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_lead_event_sale_wizard_view_form +msgid "Cancel" +msgstr "Cancelar" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__create_date +msgid "Created on" +msgstr "Creado en" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_id +msgid "Event" +msgstr "Evento" + +#. module: sale_crm_event_reservation +#: model:ir.model,name:sale_crm_event_reservation.model_event_type_report +msgid "Event categories analysis report" +msgstr "Informe de análisis de categorías de Eventos" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_type_id +msgid "Event category" +msgstr "Categoría de evento" + +#. module: sale_crm_event_reservation +#: model:ir.actions.act_window,name:sale_crm_event_reservation.crm_lead_event_sale_wizard_action +msgid "Generate event quotation" +msgstr "Generar presupuesto para evento" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_lead_event_sale_wizard_view_form +msgid "Generate quotation" +msgstr "Generar presupuesto" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__mode +msgid "How to create the event quotation?" +msgstr "¿Cómo presupuestar el evento?" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__id +msgid "ID" +msgstr "ID" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__seats_wanted +msgid "" +"If this lead/opportunity is related to a specific event category, indicate " +"how many seats would you sell if won." +msgstr "" +"Si esta iniciativa u oportunidad está relacionada con una categoría " +"específica de evento, indique cuántas plazas vendería si se gana." + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_type_id +msgid "" +"If this lead/opportunity is related to a specific event category, indicate " +"it here." +msgstr "" +"Si esta iniciativa u oportunidad está relacionada con una categoría " +"específica de evento, indíquelo aquí." + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__write_uid +msgid "Last Updated by" +msgstr "Última actualización de" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__mode +msgid "Mode" +msgstr "Modo" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_case_form_view_oppor +msgid "New Event Quotation" +msgstr "Presupuestar evento" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__opportunity_id +msgid "Opportunity" +msgstr "Oportunidad" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__product_id +msgid "Product" +msgstr "Producto" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields.selection,name:sale_crm_event_reservation.selection__crm_lead_event_sale_wizard__mode__register +msgid "Register in scheduled event" +msgstr "Registrar en un evento ya programado" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields.selection,name:sale_crm_event_reservation.selection__crm_lead_event_sale_wizard__mode__reserve +msgid "Reserve upcoming event" +msgstr "Reservar un evento futuro" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_event_type_report__seats_reservation_total +msgid "Reserved seats" +msgstr "Plazas reservadas" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__seats_wanted +msgid "Seats Wanted" +msgstr "Asientos deseados" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_ticket_id +msgid "Ticket" +msgstr "Billete" + +#. module: sale_crm_event_reservation +#: model:ir.model,name:sale_crm_event_reservation.model_crm_lead_event_sale_wizard +msgid "Wizard to generate event quotation from event opportunity" +msgstr "Asistente para presupuestar eventos desde una oportunidad de evento" + +#~ msgid "Event type" +#~ msgstr "Categoría de evento" + +#~ msgid "" +#~ "If this lead/opportunity is related to a specific event type, indicate " +#~ "how many seats would you sell if won." +#~ msgstr "" +#~ "Si esta iniciativa u oportunidad está relacionada con una categoría " +#~ "específica de evento, indique cuántas plazas vendería si se gana." + +#~ msgid "" +#~ "If this lead/opportunity is related to a specific event type, indicate it " +#~ "here." +#~ msgstr "" +#~ "Si esta iniciativa u oportunidad está relacionada con una categoría " +#~ "específica de evento, indíquelo aquí." diff --git a/sale_crm_event_reservation/i18n/it.po b/sale_crm_event_reservation/i18n/it.po new file mode 100644 index 000000000..8d594381a --- /dev/null +++ b/sale_crm_event_reservation/i18n/it.po @@ -0,0 +1,157 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_crm_event_reservation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-07-31 12:10+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_lead_event_sale_wizard_view_form +msgid "Cancel" +msgstr "Annulla" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_id +msgid "Event" +msgstr "Evento" + +#. module: sale_crm_event_reservation +#: model:ir.model,name:sale_crm_event_reservation.model_event_type_report +msgid "Event categories analysis report" +msgstr "Resoconto analisi categorie evento" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_type_id +msgid "Event category" +msgstr "Categoria evento" + +#. module: sale_crm_event_reservation +#: model:ir.actions.act_window,name:sale_crm_event_reservation.crm_lead_event_sale_wizard_action +msgid "Generate event quotation" +msgstr "Genera preventivo evento" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_lead_event_sale_wizard_view_form +msgid "Generate quotation" +msgstr "Genera preventivo" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__mode +msgid "How to create the event quotation?" +msgstr "Come creare una preventivo evento?" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__id +msgid "ID" +msgstr "ID" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__seats_wanted +msgid "" +"If this lead/opportunity is related to a specific event category, indicate " +"how many seats would you sell if won." +msgstr "" +"Se questo contatto/opportunità è relativo ad una specifica categoria evento, " +"indica quanti posti verranno venduti in caso di vincita." + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_type_id +msgid "" +"If this lead/opportunity is related to a specific event category, indicate " +"it here." +msgstr "" +"Se questo contatto/opportunità è relativo ad una specifica categoria evento, " +"indicarla qui." + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__mode +msgid "Mode" +msgstr "Modo" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_case_form_view_oppor +msgid "New Event Quotation" +msgstr "Nuovo preventivo evento" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__opportunity_id +msgid "Opportunity" +msgstr "Opportunità" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__product_id +msgid "Product" +msgstr "Prodotto" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields.selection,name:sale_crm_event_reservation.selection__crm_lead_event_sale_wizard__mode__register +msgid "Register in scheduled event" +msgstr "Registrare in evento schedulato" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields.selection,name:sale_crm_event_reservation.selection__crm_lead_event_sale_wizard__mode__reserve +msgid "Reserve upcoming event" +msgstr "Prenota prossimo evento" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_event_type_report__seats_reservation_total +msgid "Reserved seats" +msgstr "Posti prenotati" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__seats_wanted +msgid "Seats Wanted" +msgstr "Posti richiesti" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_ticket_id +msgid "Ticket" +msgstr "Biglietto" + +#. module: sale_crm_event_reservation +#: model:ir.model,name:sale_crm_event_reservation.model_crm_lead_event_sale_wizard +msgid "Wizard to generate event quotation from event opportunity" +msgstr "" +"Procedura guidata per generare una preventivo evento da una opportunità " +"evento" diff --git a/sale_crm_event_reservation/i18n/sale_crm_event_reservation.pot b/sale_crm_event_reservation/i18n/sale_crm_event_reservation.pot new file mode 100644 index 000000000..c197292f3 --- /dev/null +++ b/sale_crm_event_reservation/i18n/sale_crm_event_reservation.pot @@ -0,0 +1,148 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_crm_event_reservation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_lead_event_sale_wizard_view_form +msgid "Cancel" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__create_uid +msgid "Created by" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__create_date +msgid "Created on" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__display_name +msgid "Display Name" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_id +msgid "Event" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model,name:sale_crm_event_reservation.model_event_type_report +msgid "Event categories analysis report" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_type_id +msgid "Event category" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.actions.act_window,name:sale_crm_event_reservation.crm_lead_event_sale_wizard_action +msgid "Generate event quotation" +msgstr "" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_lead_event_sale_wizard_view_form +msgid "Generate quotation" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__mode +msgid "How to create the event quotation?" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__id +msgid "ID" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__seats_wanted +msgid "" +"If this lead/opportunity is related to a specific event category, indicate " +"how many seats would you sell if won." +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,help:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_type_id +msgid "" +"If this lead/opportunity is related to a specific event category, indicate " +"it here." +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard____last_update +msgid "Last Modified on" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__write_date +msgid "Last Updated on" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__mode +msgid "Mode" +msgstr "" + +#. module: sale_crm_event_reservation +#: model_terms:ir.ui.view,arch_db:sale_crm_event_reservation.crm_case_form_view_oppor +msgid "New Event Quotation" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__opportunity_id +msgid "Opportunity" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__product_id +msgid "Product" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields.selection,name:sale_crm_event_reservation.selection__crm_lead_event_sale_wizard__mode__register +msgid "Register in scheduled event" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields.selection,name:sale_crm_event_reservation.selection__crm_lead_event_sale_wizard__mode__reserve +msgid "Reserve upcoming event" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_event_type_report__seats_reservation_total +msgid "Reserved seats" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__seats_wanted +msgid "Seats Wanted" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model.fields,field_description:sale_crm_event_reservation.field_crm_lead_event_sale_wizard__event_ticket_id +msgid "Ticket" +msgstr "" + +#. module: sale_crm_event_reservation +#: model:ir.model,name:sale_crm_event_reservation.model_crm_lead_event_sale_wizard +msgid "Wizard to generate event quotation from event opportunity" +msgstr "" diff --git a/sale_crm_event_reservation/pyproject.toml b/sale_crm_event_reservation/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/sale_crm_event_reservation/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/sale_crm_event_reservation/readme/CONFIGURE.md b/sale_crm_event_reservation/readme/CONFIGURE.md new file mode 100644 index 000000000..3e1ff454b --- /dev/null +++ b/sale_crm_event_reservation/readme/CONFIGURE.md @@ -0,0 +1,4 @@ +To make use of this module, a user needs these minimal permissions: + +- Sales / User: Own Documents Only +- Events / User diff --git a/sale_crm_event_reservation/readme/CONTRIBUTORS.md b/sale_crm_event_reservation/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..3541fd95f --- /dev/null +++ b/sale_crm_event_reservation/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Tecnativa](https://www.tecnativa.com): + - Jairo Llopis + - Stefan Ungureanu diff --git a/sale_crm_event_reservation/readme/DESCRIPTION.md b/sale_crm_event_reservation/readme/DESCRIPTION.md new file mode 100644 index 000000000..2e96f6403 --- /dev/null +++ b/sale_crm_event_reservation/readme/DESCRIPTION.md @@ -0,0 +1,4 @@ +This module extends the functionality of *crm_event*, +*event_sale_reservation* and *sale_crm* to support fast generation of +event quotations from opportunities and to allow you to sell events like +a boss. diff --git a/sale_crm_event_reservation/readme/INSTALL.md b/sale_crm_event_reservation/readme/INSTALL.md new file mode 100644 index 000000000..679a3a37d --- /dev/null +++ b/sale_crm_event_reservation/readme/INSTALL.md @@ -0,0 +1,4 @@ +To install this module, you need to: + +1. Install *crm_event* and *event_sale_reservation* from + . diff --git a/sale_crm_event_reservation/readme/USAGE.md b/sale_crm_event_reservation/readme/USAGE.md new file mode 100644 index 000000000..96c4fe599 --- /dev/null +++ b/sale_crm_event_reservation/readme/USAGE.md @@ -0,0 +1,25 @@ +To use this module, you need to: + +1. Go to *CRM \> My Pipeline*. +2. Create one opportunity. +3. Set basic fields. +4. Set *Customer*, *Event type* and *Seats Wanted*. +5. Click on *New Event Quotation*. + +A wizard will open. If you want to register the customer in an scheduled +event: + +1. Select *Mode = Register in scheduled event*. +2. Select *Event* and *Ticket* +3. Click on *Generate quotation* + +Instead, if you want to reserve some seats for the customer in some +upcoming event: + +1. Select *Mode = Reserve upcoming event*. +2. Select *Product*, which must be a reservation product for the chosen + event type. +3. Click on *Generate quotation* + +In either case, you will be presented with a sale order created just for +you. diff --git a/sale_crm_event_reservation/reports/__init__.py b/sale_crm_event_reservation/reports/__init__.py new file mode 100644 index 000000000..1274103c2 --- /dev/null +++ b/sale_crm_event_reservation/reports/__init__.py @@ -0,0 +1 @@ +from . import event_type_report diff --git a/sale_crm_event_reservation/reports/event_type_report.py b/sale_crm_event_reservation/reports/event_type_report.py new file mode 100644 index 000000000..03dfc6ad9 --- /dev/null +++ b/sale_crm_event_reservation/reports/event_type_report.py @@ -0,0 +1,14 @@ +# Copyright 2021 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class EventTypeReport(models.Model): + _inherit = "event.type.report" + + seats_reservation_total = fields.Integer(string="Reserved seats", readonly=True) + + def _select(self, fields_=()): + fields_ += (("seats_reservation_total", "et.seats_reservation_total"),) + return super()._select(fields_) diff --git a/sale_crm_event_reservation/reports/event_type_report_views.xml b/sale_crm_event_reservation/reports/event_type_report_views.xml new file mode 100644 index 000000000..fa184dd77 --- /dev/null +++ b/sale_crm_event_reservation/reports/event_type_report_views.xml @@ -0,0 +1,25 @@ + + + + + Add reservations to event category pivot + event.type.report + + + + + + + + + Add reservations to event category graph + event.type.report + + + + + + + + diff --git a/sale_crm_event_reservation/security/ir.model.access.csv b/sale_crm_event_reservation/security/ir.model.access.csv new file mode 100644 index 000000000..b2b46276c --- /dev/null +++ b/sale_crm_event_reservation/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +sale_crm_event_reservation.access_crm_lead_event_sale_wizard,access_crm_lead_event_sale_wizard,sale_crm_event_reservation.model_crm_lead_event_sale_wizard,event.group_event_user,1,1,1,1 diff --git a/sale_crm_event_reservation/static/description/icon.png b/sale_crm_event_reservation/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/sale_crm_event_reservation/static/description/icon.png differ diff --git a/sale_crm_event_reservation/static/description/index.html b/sale_crm_event_reservation/static/description/index.html new file mode 100644 index 000000000..5540d498c --- /dev/null +++ b/sale_crm_event_reservation/static/description/index.html @@ -0,0 +1,479 @@ + + + + + +Create event quotations from opportunities + + + +
+

Create event quotations from opportunities

+ + +

Mature License: AGPL-3 OCA/event Translate me on Weblate Try me on Runboat

+

This module extends the functionality of crm_event, +event_sale_reservation and sale_crm to support fast generation of +event quotations from opportunities and to allow you to sell events like +a boss.

+

Table of contents

+ +
+

Installation

+

To install this module, you need to:

+
    +
  1. Install crm_event and event_sale_reservation from +https://github.com/OCA/event.
  2. +
+
+
+

Configuration

+

To make use of this module, a user needs these minimal permissions:

+
    +
  • Sales / User: Own Documents Only
  • +
  • Events / User
  • +
+
+
+

Usage

+

To use this module, you need to:

+
    +
  1. Go to CRM > My Pipeline.
  2. +
  3. Create one opportunity.
  4. +
  5. Set basic fields.
  6. +
  7. Set Customer, Event type and Seats Wanted.
  8. +
  9. Click on New Event Quotation.
  10. +
+

A wizard will open. If you want to register the customer in an scheduled +event:

+
    +
  1. Select Mode = Register in scheduled event.
  2. +
  3. Select Event and Ticket
  4. +
  5. Click on Generate quotation
  6. +
+

Instead, if you want to reserve some seats for the customer in some +upcoming event:

+
    +
  1. Select Mode = Reserve upcoming event.
  2. +
  3. Select Product, which must be a reservation product for the chosen +event type.
  4. +
  5. Click on Generate quotation
  6. +
+

In either case, you will be presented with a sale order created just for +you.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa:
      +
    • Jairo Llopis
    • +
    • Stefan Ungureanu
    • +
    +
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainers:

+

chienandalu pilarvargas-tecnativa

+

This module is part of the OCA/event project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/sale_crm_event_reservation/tests/__init__.py b/sale_crm_event_reservation/tests/__init__.py new file mode 100644 index 000000000..d74b9f7a1 --- /dev/null +++ b/sale_crm_event_reservation/tests/__init__.py @@ -0,0 +1 @@ +from . import test_wizard diff --git a/sale_crm_event_reservation/tests/test_wizard.py b/sale_crm_event_reservation/tests/test_wizard.py new file mode 100644 index 000000000..ec2a55ff6 --- /dev/null +++ b/sale_crm_event_reservation/tests/test_wizard.py @@ -0,0 +1,129 @@ +# Copyright 2021 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from datetime import datetime, timedelta + +from odoo.tests.common import Form, TransactionCase + + +class OpportunityCase(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.pricelist = cls.env["product.pricelist"].create( + { + "name": "Test pricelist", + "currency_id": cls.env.company.currency_id.id, + "item_ids": [ + ( + 0, + 0, + { + "applied_on": "3_global", + "compute_price": "formula", + "base": "list_price", + }, + ) + ], + } + ) + cls.partner_1 = cls.env["res.partner"].create( + [{"name": "Fulanito", "property_product_pricelist": cls.pricelist.id}] + ) + cls.event_type_1 = cls.env["event.type"].create({"name": "Ev. Type 1"}) + cls.product_reservation_1 = cls.env["product.product"].create( + { + "sale_ok": True, + "detailed_type": "event_reservation", + "event_reservation_type_id": cls.event_type_1.id, + "lst_price": 11, + "name": "reservation for ev. type 1", + } + ) + cls.product_ticket_1 = cls.env["product.product"].create( + {"name": "events ticket", "detailed_type": "event", "lst_price": 10} + ) + cls.event_1 = cls.env["event.event"].create( + { + "name": "Ev. 1", + "date_begin": datetime.now() + timedelta(days=1), + "date_end": datetime.now() + timedelta(days=2), + "event_ticket_ids": [ + ( + 0, + 0, + { + "name": "ticket 1", + "product_id": cls.product_ticket_1.id, + "price": 2, # Differs from product price + }, + ) + ], + } + ) + cls.opportunity_1 = cls.env["crm.lead"].create( + { + "partner_id": cls.partner_1.id, + "name": "I'm selling an event!", + "event_type_id": cls.event_type_1.id, + "seats_wanted": 3, + } + ) + + def test_register(self): + """Generate event registration quotation.""" + wiz_form = Form( + self.env["crm.lead.event.sale.wizard"].with_context( + default_opportunity_id=self.opportunity_1.id + ) + ) + wiz_form.mode = "register" + wiz_form.event_id = self.event_1 + wiz_form.event_ticket_id = self.event_1.event_ticket_ids[0] + action = wiz_form.save().action_generate() + self.assertEqual(action["res_model"], "sale.order") + so = self.env["sale.order"].browse(action["res_id"]) + self.assertEqual(so.order_line.product_id, self.product_ticket_1) + self.assertEqual(so.order_line.event_id, self.event_1) + self.assertEqual( + so.order_line.event_ticket_id, self.event_1.event_ticket_ids[0] + ) + self.assertTrue(so.order_line.product_id.detailed_type == "event") + self.assertEqual( + so.order_line.product_uom_qty, + 3, + "SO line qty = opportunity.seats_wanted", + ) + self.assertAlmostEqual( + so.amount_untaxed, + 6, + msg="Amount = opportunity.seats_wanted * ticket.price", + ) + self.assertEqual(so.state, "draft") + + def test_reserve(self): + """Generate event reservation quotation.""" + wiz_form = Form( + self.env["crm.lead.event.sale.wizard"].with_context( + default_opportunity_id=self.opportunity_1.id + ) + ) + wiz_form.mode = "reserve" + wiz_form.product_id = self.product_reservation_1 + action = wiz_form.save().action_generate() + self.assertEqual(action["res_model"], "sale.order") + so = self.env["sale.order"].browse(action["res_id"]) + self.assertEqual(so.order_line.product_id, self.product_reservation_1) + self.assertFalse(so.order_line.event_id) + self.assertFalse(so.order_line.event_ticket_id) + self.assertFalse(so.order_line.product_id.detailed_type == "event") + self.assertEqual( + so.order_line.product_uom_qty, + 3, + "SO line qty = opportunity.seats_wanted", + ) + self.assertAlmostEqual( + so.amount_untaxed, + 33, + msg="Amount = opportunity.seats_wanted * reservation.price", + ) + self.assertEqual(so.state, "draft") diff --git a/sale_crm_event_reservation/views/crm_lead_views.xml b/sale_crm_event_reservation/views/crm_lead_views.xml new file mode 100644 index 000000000..38f80e37b --- /dev/null +++ b/sale_crm_event_reservation/views/crm_lead_views.xml @@ -0,0 +1,23 @@ + + + + + Add button to create event quotation + crm.lead + + + + + + diff --git a/sale_crm_event_reservation/wizards/__init__.py b/sale_crm_event_reservation/wizards/__init__.py new file mode 100644 index 000000000..17b6e4f62 --- /dev/null +++ b/sale_crm_event_reservation/wizards/__init__.py @@ -0,0 +1 @@ +from . import crm_lead_event_sale_wizard diff --git a/sale_crm_event_reservation/wizards/crm_lead_event_sale_wizard.py b/sale_crm_event_reservation/wizards/crm_lead_event_sale_wizard.py new file mode 100644 index 000000000..725fed858 --- /dev/null +++ b/sale_crm_event_reservation/wizards/crm_lead_event_sale_wizard.py @@ -0,0 +1,135 @@ +# Copyright 2021 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models +from odoo.tests.common import Form + + +class CRMLeadEventSale(models.TransientModel): + _name = "crm.lead.event.sale.wizard" + _description = "Wizard to generate event quotation from event opportunity" + + opportunity_id = fields.Many2one( + comodel_name="crm.lead", + index=True, + ondelete="cascade", + readonly=True, + required=True, + string="Opportunity", + ) + event_type_id = fields.Many2one( + readonly=True, + related="opportunity_id.event_type_id", + ) + mode = fields.Selection( + required=True, + selection=[ + ("register", "Register in scheduled event"), + ("reserve", "Reserve upcoming event"), + ], + help="How to create the event quotation?", + ) + seats_wanted = fields.Integer( + readonly=True, + related="opportunity_id.seats_wanted", + ) + product_id = fields.Many2one( + comodel_name="product.product", + domain=""" + [ + ("sale_ok", "=", True), + ("event_reservation_type_id", "=", event_type_id), + ] + """, + index=True, + ondelete="cascade", + string="Product", + ) + allowed_event_ids = fields.Many2many( + comodel_name="event.event", + compute="_compute_allowed_event_ids", + readonly=True, + ) + event_id = fields.Many2one( + comodel_name="event.event", + domain="[('id', 'in', allowed_event_ids)]", + index=True, + ondelete="cascade", + string="Event", + ) + allowed_event_ticket_ids = fields.Many2many( + comodel_name="event.event.ticket", + compute="_compute_allowed_event_ticket_ids", + readonly=True, + ) + event_ticket_id = fields.Many2one( + comodel_name="event.event.ticket", + domain="[('id', 'in', allowed_event_ticket_ids)]", + index=True, + ondelete="cascade", + string="Ticket", + ) + + @api.depends("mode") + def _compute_allowed_event_ids(self): + for record in self: + events = self.env["event.event"].search( + [ + ("event_type_id", "=", record.event_type_id.id), + ("date_end", ">=", fields.Date.context_today(self)), + ("is_finished", "=", False), + ] + ) + record.allowed_event_ids = events.filtered( + lambda event: not event.seats_limited + or event.seats_available >= self.seats_wanted + ) + + @api.depends("event_id") + def _compute_allowed_event_ticket_ids(self): + for record in self: + record.allowed_event_ticket_ids = [] + if record.event_id: + tickets = record.event_id.event_ticket_ids.filtered( + lambda ticket, record=record: ( + not ticket.end_sale_datetime + or ticket.end_sale_datetime >= fields.Date.context_today(self) + ) + and ( + not ticket.seats_limited + or ticket.seats_available >= record.seats_wanted + ) + ) + record.allowed_event_ticket_ids = tickets + + def action_generate(self): + """Create an event reservation sales order.""" + # Creating a sale order properly involves lots of onchanges, so here it + # is better to use `Form` to make sure we forget none + so_form = Form(self.env["sale.order"]) + so_form.campaign_id = self.opportunity_id.campaign_id + so_form.medium_id = self.opportunity_id.medium_id + so_form.opportunity_id = self.opportunity_id + so_form.origin = self.opportunity_id.name + so_form.partner_id = self.opportunity_id.partner_id + so_form.source_id = self.opportunity_id.source_id + so_form.team_id = self.opportunity_id.team_id + with so_form.order_line.new() as so_line: + if self.mode == "reserve": + assert self.product_id + so_line.product_id = self.product_id + so_line.product_uom_qty = self.opportunity_id.seats_wanted + elif self.mode == "register": + assert self.event_id + assert self.event_ticket_id + so_line.product_id = self.event_ticket_id.product_id + so_line.product_uom_qty = self.opportunity_id.seats_wanted + so_line.event_id = self.event_id + so_line.event_ticket_id = self.event_ticket_id + so = so_form.save() + return { + "res_id": so.id, + "res_model": "sale.order", + "type": "ir.actions.act_window", + "view_mode": "form", + } diff --git a/sale_crm_event_reservation/wizards/crm_lead_event_sale_wizard_views.xml b/sale_crm_event_reservation/wizards/crm_lead_event_sale_wizard_views.xml new file mode 100644 index 000000000..538b5e787 --- /dev/null +++ b/sale_crm_event_reservation/wizards/crm_lead_event_sale_wizard_views.xml @@ -0,0 +1,62 @@ + + + + + Wizard to generate event quotation from event opportunity + crm.lead.event.sale.wizard + +
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+ + Generate event quotation + crm.lead.event.sale.wizard + form + new + +