diff --git a/smile_event_refund_registration/__init__.py b/smile_event_refund_registration/__init__.py new file mode 100644 index 000000000..e8d968b06 --- /dev/null +++ b/smile_event_refund_registration/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# (C) 2019 Smile () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from . import models +from . import wizard +from . import tests diff --git a/smile_event_refund_registration/__manifest__.py b/smile_event_refund_registration/__manifest__.py new file mode 100644 index 000000000..0f043f66c --- /dev/null +++ b/smile_event_refund_registration/__manifest__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# (C) 2019 Smile () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). +{ + 'name': "Smile Event Refund Registration", + + 'description': """ + Cancel and Refund event + """, + 'author': "Smile", + "license": 'LGPL-3', + 'website': "http://www.smile.eu", + 'category': 'tools', + 'version': '0.1', + + 'depends': [ + 'base', + 'website_event', + 'event_sale', + ], + + 'data': [ + 'data/email_template.xml', + 'wizard/event_refund_view.xml', + 'views/event_registration.xml', + ], +} diff --git a/smile_event_refund_registration/data/email_template.xml b/smile_event_refund_registration/data/email_template.xml new file mode 100644 index 000000000..3847da825 --- /dev/null +++ b/smile_event_refund_registration/data/email_template.xml @@ -0,0 +1,76 @@ + + + + + Event: Refund Registration + + Refund ${object.event_id.name}: ${object.get_date_range_str()} + ${(object.event_id.organizer_id.email or object.event_id.user_id.email or '')|safe} + ${('"%s" <%s>' % (object.partner_id.name or object.name, object.partner_id.email or object.email)) | safe} + + + + + + + + + + + + + +
+ + + +
+ Your registration(Refunded)
+ + ${object.name} + +
+ ${'%s' % object.company_id.name} +
+
+
+
+ + + +
+
+ Hello ${object.name},
+ We're sorry to inform you that this event + % if 'website_url' in object.event_id and object.event_id.website_url: + ${object.event_id.name} + % else: + ${object.event_id.name} + % endif + on ${object.get_date_range_str()} has been Refund. +
+ % if 'website_url' in object.event_id and object.event_id.website_url: + + % endif +
+ Do not hesitate to contact us if you have any question. ,
+ + --
+ % if object.event_id.organizer_id: + ${object.event_id.organizer_id.name} + % else: + The organizers. + % endif +
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/smile_event_refund_registration/i18n/fr.po b/smile_event_refund_registration/i18n/fr.po new file mode 100644 index 000000000..3b13a0636 --- /dev/null +++ b/smile_event_refund_registration/i18n/fr.po @@ -0,0 +1,275 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * smile_refund_event_registration +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-05-23 14:29+0000\n" +"PO-Revision-Date: 2019-05-23 14:29+0000\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: smile_refund_event_registration +#: model_terms:ir.ui.view,arch_db:smile_refund_event_registration.view_event_refund +msgid "Are you sure you want to cancel this event? All the linked attendees will be cancelled as well." +msgstr "Etes-vous sûr que vous voulez annuler cet événement? Tous les participants liés seront également annulés." + +#. module: smile_refund_event_registration +#: model:mail.template,body_html:smile_refund_event_registration.refund_event_registration +msgid "\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" Your registration(Refunded)
\n" +" \n" +" ${object.name}\n" +" \n" +"
\n" +" \"${'%s'\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" Hello ${object.name},
\n" +" We're sorry to inform you that this event\n" +" % if 'website_url' in object.event_id and object.event_id.website_url:\n" +" ${object.event_id.name}\n" +" % else:\n" +" ${object.event_id.name}\n" +" % endif\n" +" on ${object.get_date_range_str()} has been Refund.\n" +"
\n" +" % if 'website_url' in object.event_id and object.event_id.website_url:\n" +"
\n" +" View Event
\n" +"
\n" +" % endif\n" +"
\n" +" Do not hesitate to contact us if you have any question. ,
\n" +" \n" +" --
\n" +" % if object.event_id.organizer_id:\n" +" ${object.event_id.organizer_id.name}\n" +" % else:\n" +" The organizers.\n" +" % endif\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" " +msgstr "\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +" Votre inscription(Remboursé)
\n" +" \n" +" ${object.name}\n" +" \n" +"
\n" +" \"${'%s'\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +" \n" +"
\n" +"
\n" +" Bonjour ${object.name},
\n" +" Nous sommes désolés de vous informer que cet événement\n" +" % if 'website_url' in object.event_id and object.event_id.website_url:\n" +" ${object.event_id.name}\n" +" % else:\n" +" ${object.event_id.name}\n" +" % endif\n" +" on ${object.get_date_range_str()} a été remboursé.\n" +"
\n" +" % if 'website_url' in object.event_id and object.event_id.website_url:\n" +"
\n" +" View Event
\n" +"
\n" +" % endif\n" +"
\n" +" N'hésitez pas à nous contacter si vous avez la moindre question.,
\n" +" \n" +" --
\n" +" % if object.event_id.organizer_id:\n" +" ${object.event_id.organizer_id.name}\n" +" % else:\n" +" Les organisateurs.\n" +" % endif\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" " + +#. module: smile_refund_event_registration +#: selection:event.registration,state:0 +msgid "Attended" +msgstr "Présent" + +#. module: smile_refund_event_registration +#: model_terms:ir.ui.view,arch_db:smile_refund_event_registration.view_event_refund +msgid "Cancel" +msgstr "Annuler" + +#. module: smile_refund_event_registration +#: model_terms:ir.ui.view,arch_db:smile_refund_event_registration.registration_view_id +msgid "Cancel and Refund" +msgstr "Annuler et rembourser" + +#. module: smile_refund_event_registration +#: model_terms:ir.ui.view,arch_db:smile_refund_event_registration.view_event_form +msgid "Cancel and Refund Event" +msgstr "Annuler et rembourser l'évenement" + +#. module: smile_refund_event_registration +#: selection:event.registration,state:0 +msgid "Cancelled" +msgstr "Annulé" + +#. module: smile_refund_event_registration +#: model:ir.actions.act_window,name:smile_refund_event_registration.action_event_refund +msgid "Confirmation" +msgstr "Confirmation" + +#. module: smile_refund_event_registration +#: selection:event.registration,state:0 +msgid "Confirmed" +msgstr "Confirmé" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_refund__create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_refund__create_date +msgid "Created on" +msgstr "Nom affiché" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_refund__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_refund__event_id +msgid "Event" +msgstr "Evènement" + +#. module: smile_refund_event_registration +#: model_terms:ir.ui.view,arch_db:smile_refund_event_registration.view_event_refund +msgid "Event Refund" +msgstr "Evènement remboursé" + +#. module: smile_refund_event_registration +#: model:ir.model,name:smile_refund_event_registration.model_event_registration +msgid "Event Registration" +msgstr "Inscription à l'évènement" + +#. module: smile_refund_event_registration +#: code:addons/smile_refund_event_registration/models/event_registration.py:27 +#: model:ir.model,name:smile_refund_event_registration.model_event_refund +#, python-format +msgid "Event refund" +msgstr "Remboursement" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_refund__id +msgid "ID" +msgstr "ID" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_refund____last_update +msgid "Last Modified on" +msgstr "Dernière Modification le" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_refund__write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_refund__write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: smile_refund_event_registration +#: model_terms:ir.ui.view,arch_db:smile_refund_event_registration.view_event_refund +msgid "Ok" +msgstr "Ok" + +#. module: smile_refund_event_registration +#: model_terms:ir.ui.view,arch_db:smile_refund_event_registration.view_event_refund +msgid "Ok and Refund" +msgstr "Ok et rembourser" + +#. module: smile_refund_event_registration +#: selection:event.registration,state:0 +msgid "Refund" +msgstr "Remboursé" + +#. module: smile_refund_event_registration +#: model:mail.template,subject:smile_refund_event_registration.refund_event_registration +msgid "Refund ${object.event_id.name}: ${object.get_date_range_str()}" +msgstr "Remboursement ${object.event_id.name}: ${object.get_date_range_str()}" + +#. module: smile_refund_event_registration +#: model:ir.model.fields,field_description:smile_refund_event_registration.field_event_registration__state +msgid "Status" +msgstr "Statuts" + +#. module: smile_refund_event_registration +#: code:addons/smile_refund_event_registration/wizard/event_refund.py:31 +#, python-format +msgid "There are already attendees who attended this event. Please reset it to draft if you want to cancel this event." +msgstr "Il y a déjà des participants qui ont assisté à cet événement. S'il vous plaît réinitialiser le brouillon si vous voulez annuler cet événement" + +#. module: smile_refund_event_registration +#: selection:event.registration,state:0 +msgid "Unconfirmed" +msgstr "Non confirmé" + diff --git a/smile_event_refund_registration/models/__init__.py b/smile_event_refund_registration/models/__init__.py new file mode 100644 index 000000000..2a56e2e86 --- /dev/null +++ b/smile_event_refund_registration/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# (C) 2019 Smile () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from . import event_registration diff --git a/smile_event_refund_registration/models/event_registration.py b/smile_event_refund_registration/models/event_registration.py new file mode 100644 index 000000000..57ed70dab --- /dev/null +++ b/smile_event_refund_registration/models/event_registration.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# (C) 2019 Smile () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + + +from odoo import models, fields, api, _ + + +class EventRegistration(models.Model): + _inherit = 'event.registration' + + state = fields.Selection(selection_add=[('refund', 'Refund')]) + + @api.multi + def _send_mail(self): + self.ensure_one() + template = self.env.ref( + 'smile_event_refund_registration.refund_event_registration', False) + template.send_mail(self.id, force_send=True) + + @api.model + def prepare_account_invoice(self, invoice_id): + """ + Prepare values + """ + values = invoice_id.copy_data()[0] + values.update({'type': 'out_refund', 'name': _('Event refund')}) + return values + + @api.multi + def button_cancel_refund(self): + """ + Cancel and refund registration + """ + self.ensure_one() + return self._process_event_refund() + + @api.multi + def _process_event_refund(self): + """ + Process event refund + """ + self.ensure_one() + # create refund + state = 'cancel' + order = self.sale_order_id + if order: + if order.state in ('draft', 'sent'): + order.action_cancel() + # when invoicing + for invoice in order.invoice_ids: + if invoice.state == 'draft': + invoice.action_invoice_cancel() + elif invoice.state in ('open', 'paid'): + # Create refund + values = self.prepare_account_invoice(invoice) + self.env['account.invoice'].create(values) + state = 'refund' + # Send mail + self._send_mail() + # Update event + self.state = state diff --git a/smile_event_refund_registration/static/description/icon.png b/smile_event_refund_registration/static/description/icon.png new file mode 100644 index 000000000..17984e2d0 Binary files /dev/null and b/smile_event_refund_registration/static/description/icon.png differ diff --git a/smile_event_refund_registration/tests/__init__.py b/smile_event_refund_registration/tests/__init__.py new file mode 100644 index 000000000..45b582c36 --- /dev/null +++ b/smile_event_refund_registration/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# (C) 2019 Smile () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from . import test_event_registration diff --git a/smile_event_refund_registration/tests/test_event_registration.py b/smile_event_refund_registration/tests/test_event_registration.py new file mode 100644 index 000000000..12b6bc998 --- /dev/null +++ b/smile_event_refund_registration/tests/test_event_registration.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- +# (C) 2019 Smile () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo.tests.common import TransactionCase + + +class TestEventRegistration(TransactionCase): + + def setUp(self): + super(TestEventRegistration, self).setUp() + + self.EventRegistration = self.env['event.registration'] + + # First I create an event product + product = self.env['product.product'].create({ + 'name': 'test_formation', + 'type': 'service', + 'event_ok': True, + }) + + # I create an event from the same type than my product + event = self.env['event.event'].create({ + 'name': 'test_event', + 'event_type_id': 1, + 'date_end': '2012-01-01 19:05:15', + 'date_begin': '2012-01-01 18:05:15' + }) + + ticket = self.env['event.event.ticket'].create({ + 'name': 'test_ticket', + 'product_id': product.id, + 'event_id': event.id, + }) + + # I create a sales order + self.sale_order = self.env['sale.order'].create({ + 'partner_id': self.env.ref('base.res_partner_2').id, + 'note': 'Invoice after delivery', + 'payment_term_id': self.env.ref('account.account_payment_term').id + }) + + # In the sales order I add some sales order lines. i choose + # event product + self.env['sale.order.line'].create({ + 'product_id': product.id, + 'price_unit': 190.50, + 'product_uom': self.env.ref('uom.product_uom_unit').id, + 'product_uom_qty': 8.0, + 'order_id': self.sale_order.id, + 'name': 'sales order line', + 'event_id': event.id, + 'event_ticket_id': ticket.id, + }) + + # In the event registration I add some attendee detail lines. i choose + # event product + self.register_person = self.env['registration.editor'].create({ + 'sale_order_id': self.sale_order.id, + 'event_registration_ids': [(0, 0, { + 'event_id': event.id, + 'name': 'Administrator', + 'email': 'abc@example.com' + })], + }) + self.register_person.action_make_registration() + self.registration = self.EventRegistration.search( + [('origin', '=', self.sale_order.name)]) + self.sale_order.action_confirm() + context = { + 'active_model': 'sale.order', + 'active_ids': [self.sale_order.id], + 'active_id': self.sale_order.id, + } + payment = self.env['sale.advance.payment.inv'].with_context( + context).create({}) + # Create draft invoice to sale order + payment.create_invoices() + self.invoice = self.sale_order.invoice_ids + + def test_01_cancel_and_refund_event_registration_to_cancel(self): + """ + Check cancel & refund event registration + """ + self.registration.button_cancel_refund() + self.assertEqual( + self.registration.state, 'cancel', 'Registration should be cancel') + + def test_02_cancel_and_refund_event_registration_to_refund(self): + """ + Check cancel & refund event registration + """ + self.invoice.action_invoice_open() + self.registration.button_cancel_refund() + self.assertEqual( + self.registration.state, 'refund', 'Registration should be Refund') + + def test_03_cancel_and_refund_event_to_cancel(self): + """ + Check cancel & refund event to cancel + """ + event_refund = self.env['event.refund'].create({'event_id': '1'}) + event_refund.button_cancel_without_refund() + self.assertEqual( + event_refund.event_id.state, 'cancel', 'Event should be Cancel') diff --git a/smile_event_refund_registration/views/event_registration.xml b/smile_event_refund_registration/views/event_registration.xml new file mode 100644 index 000000000..de3e1dbd8 --- /dev/null +++ b/smile_event_refund_registration/views/event_registration.xml @@ -0,0 +1,43 @@ + + + + + + event.registration.form.view + event.registration + + + +