Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions my_compassion/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"auth_signup",
"http_routing",
"website",
"website_crm_request", # the /contactus form posts a crm.claim
"auth_signup_verify_email", # OCA/server-auth
"theme_compassion_2025",
"utm",
Expand Down Expand Up @@ -178,6 +179,7 @@
],
"web.assets_tests": [
"my_compassion/static/src/js/tours/donation_tour.js",
"my_compassion/static/tests/tours/contact_us.js",
],
},
"demo": [],
Expand Down
139 changes: 139 additions & 0 deletions my_compassion/static/tests/tours/contact_us.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import {animationFrame, click} from "@odoo/hoot-dom";
import {registry} from "@web/core/registry";
import {stepUtils} from "@web_tour/tour_service/tour_utils";

const TOKEN_KEY = "my_compassion.contact_us_tour_token";
const fromUrl = new URLSearchParams(location.search).get("tour_token");
if (fromUrl) {
sessionStorage.setItem(TOKEN_KEY, fromUrl);
}
const token = sessionStorage.getItem(TOKEN_KEY) || "";

const KNOWN = {
firstname: "Camille",
lastname: "Rochat",
phone: "0041216541288",
email: `camille.rochat+${token}@example.org`,
subject: `Change of payment date - ${token}`,
message: "I would like to change the date my monthly payment is taken.",
};

const UNKNOWN = {
firstname: "Lukas",
lastname: "Baumann",
phone: "0041313017654",
email: `lukas.baumann+${token}@example.org`,
subject: `Sponsoring a child - ${token}`,
message: "I would like to sponsor a child and do not know where to start.",
};

const sendMessage = (contact) => [
{
content: "Choose a title",
trigger: "#contactus_form select[name=title]",
run: "selectByIndex 1",
},
{
content: "Fill in the first name",
trigger: "#contactus_form_firstname",
run: `edit ${contact.firstname}`,
},
{
content: "Fill in the last name",
trigger: "#contactus_form_lastname",
run: `edit ${contact.lastname}`,
},
{
content: "Fill in the phone number",
trigger: "#contactus_form_phone_number",
run: `edit ${contact.phone}`,
},
{
content: "Fill in the e-mail address",
trigger: "#contactus_form_email",
run: `edit ${contact.email}`,
},
{
content: "Fill in the subject of the message",
trigger: "#contactus_subject",
run: `edit ${contact.subject}`,
},
{
content: "Write the message",
trigger: "#contactus_message",
run: `edit ${contact.message}`,
},
{
content: "Send the message",
trigger: "#contactus_form .s_website_form_send",
run: "click",
expectUnloadPage: true,
},
{
content: "The message went through",
trigger: "h5:contains('Your message has been sent successfully')",
},
];

registry.category("web_tour.tours").add("contact_us", {
url: "/contactus",
steps: () => [
{
content: "The MyCompassion contact form is displayed",
trigger: "#contactus_form_top form#contactus_form select[name=title]",
},
...sendMessage(KNOWN),
stepUtils.goToUrl("/contactus"),
...sendMessage(UNKNOWN),
stepUtils.goToUrl("/odoo"),
...stepUtils.goToAppSteps("crm_request.support_root", "Open the Support app"),
{
content: "Drop the default filters, so that every request is listed",
trigger: ".o_control_panel .o_searchview",
async run() {
let facet = document.querySelector(".o_searchview_facet .o_facet_remove");
while (facet) {
await click(facet, {interactive: false});
await animationFrame();
facet = document.querySelector(".o_searchview_facet .o_facet_remove");
}
},
},
{
content: "No search filter is left",
trigger: ".o_searchview:not(:has(.o_searchview_facet))",
},
{
content: "The message of the known contact reached the Support",
trigger: `.o_kanban_record:contains("${KNOWN.subject}")`,
},
{
content: "Open the request of the contact Odoo did not know",
trigger: `.o_kanban_record:contains("${UNKNOWN.subject}") h4 a`,
run: "click",
},
{
content: "The request carries the message that was written",
trigger: `.o_form_view [name=description] textarea:value("${UNKNOWN.message}")`,
},
{
content: "Focus the contact of the request",
trigger: ".o_form_view [name=partner_id] input",
run: "click",
},
{
content: "Open the contact the request is associated with",
trigger: ".o_form_view [name=partner_id] button.o_external_button",
run: "click",
},
{
content: "The contact holds the name that was filled in the form",
trigger:
`.o_form_view [name=lastname]:visible ` + `input:value("${UNKNOWN.lastname}")`,
},
{
content: "The contact holds the e-mail address that was filled in the form",
trigger: `.o_form_view [name=email] input:value("${UNKNOWN.email}")`,
},
],
});
1 change: 1 addition & 0 deletions my_compassion/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from . import (
test_child_timeline,
test_contact_us,
test_digital_fixit,
test_digital_seam,
test_donation_flow,
Expand Down
92 changes: 92 additions & 0 deletions my_compassion/tests/test_contact_us.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
##############################################################################
#
# Copyright (C) 2026 Compassion CH (http://www.compassion.ch)
# Releasing children from poverty in Jesus' name
#
# The licence is in the file __manifest__.py
#
##############################################################################
from uuid import uuid4

from odoo.tests import HttpCase, tagged


@tagged("post_install", "-at_install")
class TestContactUs(HttpCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.admin = cls.env.ref("base.user_admin")
cls.admin.tour_enabled = False
cls.admin.lang = "en_US"

cls.website = cls.env.ref("my_compassion.my2_website")
cls.website.domain = cls.base_url()

cls.title = cls.env["res.partner.title"].search(
[("is_shown_on_public_forms", "=", True)], order="shortcut asc", limit=1
)
assert cls.title, "the database needs a title published on the public forms"

cls.token = uuid4().hex[:12]
cls.known_email = f"camille.rochat+{cls.token}@example.org"
cls.unknown_email = f"lukas.baumann+{cls.token}@example.org"

cls.known_partner = cls.env["res.partner"].create(
{
"firstname": "Camille",
"lastname": "Rochat",
"email": cls.known_email,
}
)

def test_contact_us(self):
claim_obj = self.env["crm.claim"]
last_id = claim_obj.search([], order="id desc", limit=1).id

self.start_tour(
f"/contactus?tour_token={self.token}",
"contact_us",
login="admin",
timeout=180,
)

requests = claim_obj.search([("id", ">", last_id)], order="id")
self.assertEqual(
len(requests), 2, "The tour should have sent two messages to the Support"
)
known_request, unknown_request = requests

# The message of the contact Odoo already had.
self.assertEqual(known_request.name, f"Change of payment date - {self.token}")
self.assertEqual(known_request.email_from, self.known_email)
self.assertEqual(known_request.partner_phone, "0041216541288")
self.assertIn(
"I would like to change the date my monthly payment is taken.",
known_request.description,
)
self.assertEqual(
known_request.partner_id,
self.known_partner,
"The request should be attached to the contact that already existed",
)

# The message of the contact Odoo had to create.
self.assertEqual(unknown_request.name, f"Sponsoring a child - {self.token}")
self.assertEqual(unknown_request.email_from, self.unknown_email)
self.assertEqual(unknown_request.partner_phone, "0041313017654")
self.assertIn(
"I would like to sponsor a child and do not know where to start.",
unknown_request.description,
)

new_partner = unknown_request.partner_id
self.assertTrue(
new_partner, "The second request should have created a new contact"
)
# The contact holds what the form was filled with.
self.assertEqual(new_partner.firstname, "Lukas")
self.assertEqual(new_partner.lastname, "Baumann")
self.assertEqual(new_partner.email, self.unknown_email)
self.assertEqual(new_partner.title, self.title)
self.assertEqual(new_partner.phone, "0041313017654")
1 change: 1 addition & 0 deletions website_crm_request/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
2 changes: 1 addition & 1 deletion website_crm_request/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
# pylint: disable=C8101
{
"name": "Website CRM Request",
"version": "18.0.1.0.0",
"version": "18.0.1.1.0",
"category": "Website",
"author": "Compassion CH",
"license": "AGPL-3",
Expand Down
1 change: 1 addition & 0 deletions website_crm_request/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import crm_claim
43 changes: 43 additions & 0 deletions website_crm_request/models/crm_claim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from odoo import models
from odoo.tools.mail import email_normalize


class CrmClaim(models.Model):
_inherit = "crm.claim"

def website_form_input_filter(self, request, values):
"""Attach the request to the contact that wrote it, creating one when
no contact holds the address.
"""
email = email_normalize(values.get("email_from") or "")
Comment thread
AlexandrePhilibert marked this conversation as resolved.
if not email:
return values

params = request.params
firstname = (params.get("firstname") or "").strip()
lastname = (params.get("lastname") or "").strip()
partner_obj = self.env["res.partner"].sudo()
partner = partner_obj.search([("email", "=ilike", email)], limit=1)
if not partner and (firstname or lastname):
partner = (
self.env["res.partner.match"]
.sudo()
._create_partner(
{
"firstname": firstname,
"lastname": lastname,
"email": email,
"phone": values.get("partner_phone") or False,
"title": self._website_form_title(params.get("title")),
}
)
)

if partner:
values["partner_id"] = partner.id
values["language"] = partner.lang
return values

def _website_form_title(self, shortcut):
title_obj = self.env["res.partner.title"].sudo()
return shortcut and title_obj.search([("shortcut", "=", shortcut)], limit=1).id
1 change: 1 addition & 0 deletions website_crm_request/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_website_form_partner
Loading
Loading