Exoscale offboarding MVP #282
5 changed files with 70 additions and 46 deletions
|
|
@ -21,7 +21,7 @@ from servala.core.models import (
|
||||||
User,
|
User,
|
||||||
)
|
)
|
||||||
from servala.core.models.service import Service, ServiceInstance, ServiceOffering
|
from servala.core.models.service import Service, ServiceInstance, ServiceOffering
|
||||||
from servala.core.odoo import CLIENT
|
from servala.core.odoo import create_helpdesk_ticket
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -269,9 +269,7 @@ The Servala Team"""
|
||||||
organization = None
|
organization = None
|
||||||
try:
|
try:
|
||||||
# Look for instances with this name in the service offering's context
|
# Look for instances with this name in the service offering's context
|
||||||
# TODO: we do not currently match instance IDs from exoscale yet, this
|
service_instance = (
|
||||||
# will likely not work at all yet
|
|
||||||
instances = (
|
|
||||||
ServiceInstance.objects.filter(
|
ServiceInstance.objects.filter(
|
||||||
name=instance_id,
|
name=instance_id,
|
||||||
context__service_offering=service_offering,
|
context__service_offering=service_offering,
|
||||||
|
|
@ -280,7 +278,7 @@ The Servala Team"""
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
|
|
||||||
if instances:
|
if service_instance:
|
||||||
organization = service_instance.organization
|
organization = service_instance.organization
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
@ -327,13 +325,11 @@ The Servala Team"""
|
||||||
description_parts.append(f" - {full_name} ({user_link}) - {role}")
|
description_parts.append(f" - {full_name} ({user_link}) - {role}")
|
||||||
|
|
||||||
description = "\n".join(description_parts)
|
description = "\n".join(description_parts)
|
||||||
ticket_data = {
|
|
||||||
"name": f"Exoscale OSB {action} - {service.name} - {instance_id}",
|
|
||||||
"team_id": settings.ODOO["HELPDESK_TEAM_ID"],
|
|
||||||
"description": description,
|
|
||||||
}
|
|
||||||
|
|
||||||
CLIENT.execute("helpdesk.ticket", "create", [ticket_data])
|
create_helpdesk_ticket(
|
||||||
|
title=f"Exoscale OSB {action} - {service.name} - {instance_id}",
|
||||||
|
description=description,
|
||||||
|
)
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Created {action} helpdesk ticket for instance {instance_id}, service {service.name}"
|
f"Created {action} helpdesk ticket for instance {instance_id}, service {service.name}"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -207,3 +207,19 @@ def get_invoice_addresses(user):
|
||||||
return invoice_addresses or []
|
return invoice_addresses or []
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def create_helpdesk_ticket(title, description, partner_id=None, sale_order_id=None):
|
||||||
|
ticket_data = {
|
||||||
|
"name": title,
|
||||||
|
"team_id": settings.ODOO["HELPDESK_TEAM_ID"],
|
||||||
|
"description": description,
|
||||||
|
}
|
||||||
|
|
||||||
|
if partner_id:
|
||||||
|
ticket_data["partner_id"] = partner_id
|
||||||
|
|
||||||
|
if sale_order_id:
|
||||||
|
ticket_data["sale_order_id"] = sale_order_id
|
||||||
|
|
||||||
|
return CLIENT.execute("helpdesk.ticket", "create", [ticket_data])
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import FormView
|
from django.views.generic import FormView
|
||||||
|
|
||||||
from servala.core.odoo import CLIENT
|
from servala.core.odoo import create_helpdesk_ticket
|
||||||
from servala.frontend.forms.support import SupportForm
|
from servala.frontend.forms.support import SupportForm
|
||||||
from servala.frontend.views.mixins import OrganizationViewMixin
|
from servala.frontend.views.mixins import OrganizationViewMixin
|
||||||
|
|
||||||
|
|
@ -24,21 +23,16 @@ class SupportView(OrganizationViewMixin, FormView):
|
||||||
if not partner_id:
|
if not partner_id:
|
||||||
raise Exception("Could not get or create Odoo contact for user")
|
raise Exception("Could not get or create Odoo contact for user")
|
||||||
|
|
||||||
ticket_data = {
|
|
||||||
"name": f"Servala Support - Organization {organization.name}",
|
|
||||||
"team_id": settings.ODOO["HELPDESK_TEAM_ID"],
|
|
||||||
"partner_id": partner_id,
|
|
||||||
"description": message,
|
|
||||||
}
|
|
||||||
|
|
||||||
# All orgs should have a sale order ID, but legacy ones might not have it.
|
# All orgs should have a sale order ID, but legacy ones might not have it.
|
||||||
# Also, we want to be very sure that support requests work, especially for
|
# Also, we want to be very sure that support requests work, especially for
|
||||||
# organizations where something in the creation process may have gone wrong,
|
# organizations where something in the creation process may have gone wrong,
|
||||||
# so if the ID does not exist, we omit it entirely.
|
# so if the ID does not exist, we omit it entirely.
|
||||||
if organization.odoo_sale_order_id:
|
create_helpdesk_ticket(
|
||||||
ticket_data["sale_order_id"] = organization.odoo_sale_order_id
|
title=f"Servala Support - Organization {organization.name}",
|
||||||
|
description=message,
|
||||||
CLIENT.execute("helpdesk.ticket", "create", [ticket_data])
|
partner_id=partner_id,
|
||||||
|
sale_order_id=organization.odoo_sale_order_id or None,
|
||||||
|
)
|
||||||
messages.success(
|
messages.success(
|
||||||
self.request,
|
self.request,
|
||||||
_(
|
_(
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ overrides/adds settings specific to testing.
|
||||||
from servala.settings import * # noqa: F403, F401
|
from servala.settings import * # noqa: F403, F401
|
||||||
|
|
||||||
SECRET_KEY = "test-secret-key-for-testing-only-do-not-use-in-production"
|
SECRET_KEY = "test-secret-key-for-testing-only-do-not-use-in-production"
|
||||||
|
SALT_KEY = SECRET_KEY
|
||||||
PASSWORD_HASHERS = [
|
PASSWORD_HASHERS = [
|
||||||
"django.contrib.auth.hashers.MD5PasswordHasher",
|
"django.contrib.auth.hashers.MD5PasswordHasher",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -614,7 +614,8 @@ def test_delete_creates_ticket_with_admin_links(
|
||||||
test_service_offering,
|
test_service_offering,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
mock_api_client = mocker.patch("servala.api.views.CLIENT")
|
# Mock the create_helpdesk_ticket function
|
||||||
|
mock_create_ticket = mocker.patch("servala.api.views.create_helpdesk_ticket")
|
||||||
|
|
||||||
response = osb_client.delete(
|
response = osb_client.delete(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}"
|
f"/api/osb/v2/service_instances/{instance_id}"
|
||||||
|
|
@ -623,13 +624,15 @@ def test_delete_creates_ticket_with_admin_links(
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
ticket_call = mock_api_client.execute.call_args_list[-1]
|
# Verify the ticket was created with admin URL
|
||||||
ticket_data = ticket_call[0][2][0]
|
mock_create_ticket.assert_called_once()
|
||||||
|
call_kwargs = mock_create_ticket.call_args[1]
|
||||||
|
|
||||||
assert "admin/core/serviceoffering" in ticket_data["description"]
|
# Check that the description contains an admin URL
|
||||||
assert f"/{test_service_offering.pk}/" in ticket_data["description"]
|
assert "admin/core/serviceoffering" in call_kwargs["description"]
|
||||||
|
assert f"/{test_service_offering.pk}/" in call_kwargs["description"]
|
||||||
assert (
|
assert (
|
||||||
ticket_data["name"]
|
call_kwargs["title"]
|
||||||
== f"Exoscale OSB Offboard - {test_service.name} - {instance_id}"
|
== f"Exoscale OSB Offboard - {test_service.name} - {instance_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -644,7 +647,9 @@ def test_patch_creates_ticket_with_user_admin_links(
|
||||||
instance_id,
|
instance_id,
|
||||||
org_owner,
|
org_owner,
|
||||||
):
|
):
|
||||||
mock_api_client = mocker.patch("servala.api.views.CLIENT")
|
# Mock the create_helpdesk_ticket function
|
||||||
|
mock_create_ticket = mocker.patch("servala.api.views.create_helpdesk_ticket")
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"service_id": test_service.osb_service_id,
|
"service_id": test_service.osb_service_id,
|
||||||
"plan_id": test_service_offering.osb_plan_id,
|
"plan_id": test_service_offering.osb_plan_id,
|
||||||
|
|
@ -666,13 +671,17 @@ def test_patch_creates_ticket_with_user_admin_links(
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
ticket_call = mock_api_client.execute.call_args_list[-1]
|
|
||||||
ticket_data = ticket_call[0][2][0]
|
# Verify the ticket was created with admin URLs
|
||||||
assert "admin/core/serviceoffering" in ticket_data["description"]
|
mock_create_ticket.assert_called_once()
|
||||||
assert "admin/core/user" in ticket_data["description"]
|
call_kwargs = mock_create_ticket.call_args[1]
|
||||||
assert f"/{org_owner.pk}/" in ticket_data["description"]
|
|
||||||
|
# Check that the description contains admin URLs
|
||||||
|
assert "admin/core/serviceoffering" in call_kwargs["description"]
|
||||||
|
assert "admin/core/user" in call_kwargs["description"]
|
||||||
|
assert f"/{org_owner.pk}/" in call_kwargs["description"]
|
||||||
assert (
|
assert (
|
||||||
ticket_data["name"]
|
call_kwargs["title"]
|
||||||
== f"Exoscale OSB Suspend - {test_service.name} - {instance_id}"
|
== f"Exoscale OSB Suspend - {test_service.name} - {instance_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -686,7 +695,9 @@ def test_ticket_includes_organization_and_instance_when_found(
|
||||||
test_service_offering,
|
test_service_offering,
|
||||||
organization,
|
organization,
|
||||||
):
|
):
|
||||||
mock_api_client = mocker.patch("servala.api.views.CLIENT")
|
# Mock the create_helpdesk_ticket function
|
||||||
|
mock_create_ticket = mocker.patch("servala.api.views.create_helpdesk_ticket")
|
||||||
|
|
||||||
service_definition = ServiceDefinition.objects.create(
|
service_definition = ServiceDefinition.objects.create(
|
||||||
name="Test Definition",
|
name="Test Definition",
|
||||||
service=test_service,
|
service=test_service,
|
||||||
|
|
@ -719,11 +730,17 @@ def test_ticket_includes_organization_and_instance_when_found(
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
ticket_call = mock_api_client.execute.call_args_list[-1]
|
|
||||||
ticket_data = ticket_call[0][2][0]
|
# Verify the ticket was created with all admin URLs
|
||||||
assert f"Organization: {organization.name}" in ticket_data["description"]
|
mock_create_ticket.assert_called_once()
|
||||||
assert "admin/core/organization" in ticket_data["description"]
|
call_kwargs = mock_create_ticket.call_args[1]
|
||||||
assert f"/{organization.pk}/" in ticket_data["description"]
|
|
||||||
assert f"Instance: {service_instance.name}" in ticket_data["description"]
|
# Check organization is included
|
||||||
assert "admin/core/serviceinstance" in ticket_data["description"]
|
assert f"Organization: {organization.name}" in call_kwargs["description"]
|
||||||
assert f"/{service_instance.pk}/" in ticket_data["description"]
|
assert "admin/core/organization" in call_kwargs["description"]
|
||||||
|
assert f"/{organization.pk}/" in call_kwargs["description"]
|
||||||
|
|
||||||
|
# Check instance is included
|
||||||
|
assert f"Instance: {service_instance.name}" in call_kwargs["description"]
|
||||||
|
assert "admin/core/serviceinstance" in call_kwargs["description"]
|
||||||
|
assert f"/{service_instance.pk}/" in call_kwargs["description"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue