feat: implement preventive intervention templates and operation grouping system
This commit is contained in:
parent
ca6d09c6b1
commit
b15326602b
11 changed files with 430 additions and 5 deletions
|
|
@ -639,6 +639,10 @@ class OperationTemplateItemInline(admin.TabularInline):
|
|||
ordering = ('order',)
|
||||
|
||||
|
||||
from django.db.models import Q
|
||||
from contracts.models import CompanyTeam
|
||||
|
||||
|
||||
class OperationTemplateAdminForm(forms.ModelForm):
|
||||
"""Form for OperationTemplate with category filtering based on thematic."""
|
||||
|
||||
|
|
@ -655,7 +659,7 @@ class OperationTemplateAdminForm(forms.ModelForm):
|
|||
|
||||
class Meta:
|
||||
model = OperationTemplate
|
||||
fields = ['code', 'name', 'description', 'thematic', 'categories']
|
||||
fields = ['code', 'name', 'description', 'thematic', 'team', 'guided_template', 'categories']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
|
@ -686,6 +690,15 @@ class OperationTemplateAdminForm(forms.ModelForm):
|
|||
self.fields['categories'].queryset = AssetCategory.objects.filter(thematic=thematic)
|
||||
elif 'categories' in self.fields:
|
||||
self.fields['categories'].queryset = AssetCategory.objects.none()
|
||||
|
||||
# Filter teams by thematic
|
||||
if 'team' in self.fields:
|
||||
if thematic:
|
||||
self.fields['team'].queryset = CompanyTeam.objects.filter(
|
||||
Q(thematics=thematic) | Q(thematics__isnull=True)
|
||||
).distinct().select_related('company').order_by('name')
|
||||
else:
|
||||
self.fields['team'].queryset = CompanyTeam.objects.select_related('company').order_by('name')
|
||||
|
||||
# Build choices for asset models
|
||||
choices = []
|
||||
|
|
@ -767,13 +780,13 @@ class OperationTemplateAdminForm(forms.ModelForm):
|
|||
@admin.register(OperationTemplate)
|
||||
class OperationTemplateAdmin(admin.ModelAdmin):
|
||||
form = OperationTemplateAdminForm
|
||||
list_display = ('code', 'name', 'description', 'thematic', 'categories_list', 'models_list')
|
||||
list_filter = ('thematic', 'categories')
|
||||
list_display = ('code', 'name', 'description', 'thematic', 'team', 'categories_list', 'models_list')
|
||||
list_filter = ('thematic', 'team', 'categories')
|
||||
filter_horizontal = ('categories',)
|
||||
inlines = [OperationTemplateItemInline]
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('code', 'name', 'description', 'thematic', 'guided_template')
|
||||
'fields': ('code', 'name', 'description', 'thematic', 'team', 'guided_template')
|
||||
}),
|
||||
('Catégories d\'équipements concernées (optionnel)', {
|
||||
'fields': ('categories',),
|
||||
|
|
|
|||
20
loko/interventions/migrations/0003_operationtemplate_team.py
Normal file
20
loko/interventions/migrations/0003_operationtemplate_team.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 6.0.7 on 2026-08-19 05:28
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contracts', '0002_initial'),
|
||||
('interventions', '0002_remove_intervention_origin_fms_nbr_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='operationtemplate',
|
||||
name='team',
|
||||
field=models.ForeignKey(blank=True, help_text="Si définie, cette équipe sera automatiquement assignée lors de la création d'interventions préventives utilisant cette gamme.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operation_templates', to='contracts.companyteam', verbose_name='Équipe associée'),
|
||||
),
|
||||
]
|
||||
|
|
@ -1372,6 +1372,15 @@ class OperationTemplate(models.Model):
|
|||
name = models.CharField(max_length=255, unique=True)
|
||||
description = models.TextField(blank=True)
|
||||
thematic = models.ForeignKey(Thematic, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
team = models.ForeignKey(
|
||||
CompanyTeam,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='operation_templates',
|
||||
verbose_name=_("Équipe associée"),
|
||||
help_text=_("Si définie, cette équipe sera automatiquement assignée lors de la création d'interventions préventives utilisant cette gamme.")
|
||||
)
|
||||
guided_template = models.ForeignKey(
|
||||
GuidedOperationTemplate,
|
||||
on_delete=models.SET_NULL,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
$(document).ready(function() {
|
||||
var $thematic = $('#id_thematic');
|
||||
var $team = $('#id_team');
|
||||
var $categoriesFrom = $('#id_categories_from');
|
||||
var $categoriesTo = $('#id_categories_to');
|
||||
var $assetModelsFrom = $('#id_asset_models_from');
|
||||
|
|
@ -24,6 +25,41 @@
|
|||
|
||||
if (!$thematic.length) return;
|
||||
|
||||
/**
|
||||
* Update teams based on selected thematic
|
||||
*/
|
||||
function updateTeams() {
|
||||
if (!$team.length) return;
|
||||
var thematicId = $thematic.val();
|
||||
var currentTeamVal = $team.val();
|
||||
|
||||
$.ajax({
|
||||
url: '/interventions/ajax/get-teams-by-thematic/',
|
||||
data: { thematic_id: thematicId || '' },
|
||||
success: function(data) {
|
||||
$team.empty();
|
||||
$team.append($('<option></option>').val('').text('---------'));
|
||||
var hasCurrentVal = false;
|
||||
data.teams.forEach(function(team) {
|
||||
var option = $('<option></option>')
|
||||
.val(team.id)
|
||||
.text(team.name);
|
||||
if (String(team.id) === String(currentTeamVal)) {
|
||||
option.prop('selected', true);
|
||||
hasCurrentVal = true;
|
||||
}
|
||||
$team.append(option);
|
||||
});
|
||||
if (!hasCurrentVal && currentTeamVal) {
|
||||
$team.val('');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
console.error('Error fetching teams');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update categories based on selected thematic
|
||||
*/
|
||||
|
|
@ -131,6 +167,7 @@
|
|||
// Listen to thematic changes
|
||||
$thematic.on('change', function() {
|
||||
updateCategories();
|
||||
updateTeams();
|
||||
});
|
||||
|
||||
// Listen to categories changes using MutationObserver
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import json
|
||||
import time
|
||||
from datetime import timedelta
|
||||
from unittest import mock
|
||||
|
||||
|
|
@ -603,6 +604,286 @@ class ExternalManagerPreventivePermissionsTests(TestCase):
|
|||
self.assertTrue(should_show_created_by_provider_badge(self.internal_manager, intervention))
|
||||
|
||||
|
||||
class PreventiveTemplateTeamAssignmentTests(TestCase):
|
||||
"""Test automatic team assignment from OperationTemplate in preventive interventions."""
|
||||
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.thematic = Thematic.objects.create(code='trafficlights', name_fr='Signalisation', name_nl='Signalisatie')
|
||||
self.company = Company.objects.create(name='Provider Corp')
|
||||
self.team_a = CompanyTeam.objects.create(name='Equipe Alpha', company=self.company)
|
||||
self.team_a.thematics.add(self.thematic)
|
||||
self.team_b = CompanyTeam.objects.create(name='Equipe Beta', company=self.company)
|
||||
self.team_b.thematics.add(self.thematic)
|
||||
|
||||
from datetime import date, timedelta
|
||||
today = date.today()
|
||||
self.contract = Contract.objects.create(
|
||||
contract_number='C-TEST-001',
|
||||
company=self.company,
|
||||
is_active=True,
|
||||
start_date=today - timedelta(days=30),
|
||||
end_date=today + timedelta(days=365)
|
||||
)
|
||||
self.contract.thematics.add(self.thematic)
|
||||
|
||||
self.user = User.objects.create_user(username='manager_user', password='pwd')
|
||||
self.role_manager = Role.objects.create(name='manager')
|
||||
self.config = UserConfig.objects.create(user=self.user, is_intern=True)
|
||||
self.config.roles.add(self.role_manager)
|
||||
self.config.contracts.add(self.contract)
|
||||
UserThematics.objects.create(user_config=self.config, thematic=self.thematic, can_edit_interventions=True)
|
||||
|
||||
self.status_set = OperationStatusSet.objects.create(name='Standard Status Set')
|
||||
|
||||
# Template with team A
|
||||
self.template_with_team = OperationTemplate.objects.create(
|
||||
name='Gamme Entretien A',
|
||||
description='Gamme avec équipe A',
|
||||
thematic=self.thematic,
|
||||
team=self.team_a,
|
||||
)
|
||||
OperationTemplateItem.objects.create(
|
||||
template=self.template_with_team,
|
||||
name_fr='Vérification A',
|
||||
name_nl='Controle A',
|
||||
status_set=self.status_set,
|
||||
is_generic=True,
|
||||
order=1,
|
||||
)
|
||||
|
||||
# Template with team B
|
||||
self.template_with_team_b = OperationTemplate.objects.create(
|
||||
name='Gamme Entretien B',
|
||||
description='Gamme avec équipe B',
|
||||
thematic=self.thematic,
|
||||
team=self.team_b,
|
||||
)
|
||||
OperationTemplateItem.objects.create(
|
||||
template=self.template_with_team_b,
|
||||
name_fr='Vérification B',
|
||||
name_nl='Controle B',
|
||||
status_set=self.status_set,
|
||||
is_generic=True,
|
||||
order=1,
|
||||
)
|
||||
|
||||
# Template without team
|
||||
self.template_without_team = OperationTemplate.objects.create(
|
||||
name='Gamme Sans Equipe',
|
||||
description='Gamme sans équipe',
|
||||
thematic=self.thematic,
|
||||
team=None,
|
||||
)
|
||||
OperationTemplateItem.objects.create(
|
||||
template=self.template_without_team,
|
||||
name_fr='Vérification C',
|
||||
name_nl='Controle C',
|
||||
status_set=self.status_set,
|
||||
is_generic=True,
|
||||
order=1,
|
||||
)
|
||||
|
||||
def test_assign_team_from_templates_helper(self):
|
||||
"""Test _assign_team_from_templates helper function directly."""
|
||||
from interventions.views.helpers import _assign_team_from_templates
|
||||
|
||||
itv = Intervention.objects.create(
|
||||
title='Test ITV',
|
||||
status='in_preparation',
|
||||
maintain_type='preventive',
|
||||
thematic=self.thematic,
|
||||
)
|
||||
|
||||
# No templates -> no change
|
||||
_assign_team_from_templates(itv, [])
|
||||
self.assertIsNone(itv.assigned_team)
|
||||
|
||||
# Template without team -> no change
|
||||
_assign_team_from_templates(itv, [self.template_without_team])
|
||||
self.assertIsNone(itv.assigned_team)
|
||||
|
||||
# Template with team -> assigned
|
||||
_assign_team_from_templates(itv, [self.template_with_team])
|
||||
itv.refresh_from_db()
|
||||
self.assertEqual(itv.assigned_team, self.team_a)
|
||||
self.assertEqual(itv.assigned_provider, self.company)
|
||||
|
||||
def test_preventive_creation_auto_assigns_team_single_mode(self):
|
||||
"""Test preventive intervention creation assigns team from template in single_for_all mode."""
|
||||
self.client.login(username='manager_user', password='pwd')
|
||||
url = reverse('interventions:intervention_add_preventive', kwargs={'thematic_code': 'trafficlights'})
|
||||
|
||||
session = self.client.session
|
||||
session['intervention_drafts'] = {
|
||||
'draft-team': {
|
||||
'locations': [],
|
||||
'assets': [],
|
||||
'form_data': {},
|
||||
'timestamp': time.time(),
|
||||
}
|
||||
}
|
||||
session.save()
|
||||
|
||||
post_data = {
|
||||
'title': 'Preventive with team',
|
||||
'status': 'in_preparation',
|
||||
'type': 'care',
|
||||
'contract': self.contract.id,
|
||||
'operation_templates': [str(self.template_with_team.id)],
|
||||
'expected_begin_time': '2026-08-20T08:00',
|
||||
'expected_end_time': '2026-08-20T17:00',
|
||||
'recurrence_count': 0,
|
||||
'type_of_selected_elements': 'locations',
|
||||
'intervention_creation_mode': 'single_for_all',
|
||||
'draft_id': 'draft-team',
|
||||
}
|
||||
response = self.client.post(url, post_data)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
intervention = Intervention.objects.filter(title='Preventive with team').first()
|
||||
self.assertIsNotNone(intervention)
|
||||
self.assertEqual(intervention.assigned_team, self.team_a)
|
||||
self.assertEqual(intervention.assigned_provider, self.company)
|
||||
self.assertIn(self.template_with_team, intervention.equipment_operation_templates.all())
|
||||
|
||||
def test_preventive_creation_multiple_templates_first_team_assigned(self):
|
||||
"""When multiple templates are selected, the first one with a team sets the assigned_team."""
|
||||
self.client.login(username='manager_user', password='pwd')
|
||||
url = reverse('interventions:intervention_add_preventive', kwargs={'thematic_code': 'trafficlights'})
|
||||
|
||||
session = self.client.session
|
||||
session['intervention_drafts'] = {
|
||||
'draft-multi': {
|
||||
'locations': [],
|
||||
'assets': [],
|
||||
'form_data': {},
|
||||
'timestamp': time.time(),
|
||||
}
|
||||
}
|
||||
session.save()
|
||||
|
||||
# template_without_team first, then template_with_team_b
|
||||
post_data = {
|
||||
'title': 'Preventive multi templates',
|
||||
'status': 'in_preparation',
|
||||
'type': 'care',
|
||||
'contract': self.contract.id,
|
||||
'operation_templates': [str(self.template_without_team.id), str(self.template_with_team_b.id)],
|
||||
'expected_begin_time': '2026-08-20T08:00',
|
||||
'expected_end_time': '2026-08-20T17:00',
|
||||
'recurrence_count': 0,
|
||||
'type_of_selected_elements': 'locations',
|
||||
'intervention_creation_mode': 'single_for_all',
|
||||
'draft_id': 'draft-multi',
|
||||
}
|
||||
response = self.client.post(url, post_data)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
intervention = Intervention.objects.filter(title='Preventive multi templates').first()
|
||||
self.assertIsNotNone(intervention)
|
||||
self.assertEqual(intervention.assigned_team, self.team_b)
|
||||
|
||||
def test_preventive_creation_without_team_template(self):
|
||||
"""When template has no team, assigned_team remains None."""
|
||||
self.client.login(username='manager_user', password='pwd')
|
||||
url = reverse('interventions:intervention_add_preventive', kwargs={'thematic_code': 'trafficlights'})
|
||||
|
||||
session = self.client.session
|
||||
session['intervention_drafts'] = {
|
||||
'draft-noteam': {
|
||||
'locations': [],
|
||||
'assets': [],
|
||||
'form_data': {},
|
||||
'timestamp': time.time(),
|
||||
}
|
||||
}
|
||||
session.save()
|
||||
|
||||
post_data = {
|
||||
'title': 'Preventive without team',
|
||||
'status': 'in_preparation',
|
||||
'type': 'care',
|
||||
'contract': self.contract.id,
|
||||
'operation_templates': [str(self.template_without_team.id)],
|
||||
'expected_begin_time': '2026-08-20T08:00',
|
||||
'expected_end_time': '2026-08-20T17:00',
|
||||
'recurrence_count': 0,
|
||||
'type_of_selected_elements': 'locations',
|
||||
'intervention_creation_mode': 'single_for_all',
|
||||
'draft_id': 'draft-noteam',
|
||||
}
|
||||
response = self.client.post(url, post_data)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
intervention = Intervention.objects.filter(title='Preventive without team').first()
|
||||
self.assertIsNotNone(intervention)
|
||||
self.assertIsNone(intervention.assigned_team)
|
||||
|
||||
def test_preventive_creation_auto_assigns_team_one_per_element_locations(self):
|
||||
"""Test preventive creation in one_per_element mode auto-assigns team to each intervention."""
|
||||
from assets.models import TrafficLightIntersection
|
||||
loc = TrafficLightIntersection.objects.create(code='TL-001', name_fr='Carrefour 1')
|
||||
|
||||
self.client.login(username='manager_user', password='pwd')
|
||||
url = reverse('interventions:intervention_add_preventive', kwargs={'thematic_code': 'trafficlights'})
|
||||
|
||||
session = self.client.session
|
||||
session['intervention_drafts'] = {
|
||||
'draft-loc': {
|
||||
'locations': [loc.id],
|
||||
'assets': [],
|
||||
'form_data': {},
|
||||
'timestamp': time.time(),
|
||||
}
|
||||
}
|
||||
session.save()
|
||||
|
||||
post_data = {
|
||||
'title': 'Preventive Location',
|
||||
'status': 'in_preparation',
|
||||
'type': 'care',
|
||||
'contract': self.contract.id,
|
||||
'operation_templates': [str(self.template_with_team.id)],
|
||||
'expected_begin_time': '2026-08-20T08:00',
|
||||
'expected_end_time': '2026-08-20T17:00',
|
||||
'recurrence_count': 0,
|
||||
'type_of_selected_elements': 'locations',
|
||||
'intervention_creation_mode': 'one_per_element',
|
||||
'draft_id': 'draft-loc',
|
||||
}
|
||||
response = self.client.post(url, post_data)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
intervention = Intervention.objects.filter(location_code='TL-001').first()
|
||||
self.assertIsNotNone(intervention)
|
||||
self.assertEqual(intervention.assigned_team, self.team_a)
|
||||
self.assertEqual(intervention.assigned_provider, self.company)
|
||||
|
||||
def test_ajax_get_teams_by_thematic(self):
|
||||
"""Test the AJAX endpoint ajax_get_teams_by_thematic."""
|
||||
self.client.login(username='manager_user', password='pwd')
|
||||
url = reverse('interventions:ajax_get_teams_by_thematic')
|
||||
|
||||
# Filter by thematic
|
||||
response = self.client.get(f"{url}?thematic_id={self.thematic.id}")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = response.json()
|
||||
self.assertIn('teams', data)
|
||||
team_ids = [t['id'] for t in data['teams']]
|
||||
self.assertIn(self.team_a.id, team_ids)
|
||||
self.assertIn(self.team_b.id, team_ids)
|
||||
|
||||
# Without thematic -> all teams
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = response.json()
|
||||
self.assertIn('teams', data)
|
||||
self.assertGreaterEqual(len(data['teams']), 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ urlpatterns = [
|
|||
path('<int:intervention_id>/mobile/transfer/', views.transfer_intervention, name='transfer_intervention'),
|
||||
# Admin AJAX endpoints
|
||||
path('ajax/get-categories-by-thematic/', views.ajax_get_categories_by_thematic, name='ajax_get_categories_by_thematic'),
|
||||
path('ajax/get-teams-by-thematic/', views.ajax_get_teams_by_thematic, name='ajax_get_teams_by_thematic'),
|
||||
path('ajax/get-subcategories/', views.ajax_get_subcategories, name='ajax_get_subcategories'),
|
||||
path('ajax/get-asset-models/', views.ajax_get_asset_models, name='ajax_get_asset_models'),
|
||||
path('ajax/get-replacement-models-by-category/', views.ajax_get_replacement_models_by_category, name='ajax_get_replacement_models_by_category'),
|
||||
|
|
|
|||
|
|
@ -1677,6 +1677,7 @@ def interventions_add(request, thematic_code):
|
|||
if templates:
|
||||
intervention.equipment_operation_templates.add(*templates)
|
||||
_assign_guided_template(intervention, templates)
|
||||
_assign_team_from_templates(intervention, templates)
|
||||
_add_operations_from_templates(intervention, templates, only_generic=True)
|
||||
if asset_pairs:
|
||||
resolved_assets = _resolve_assets_from_pairs(asset_pairs)
|
||||
|
|
|
|||
|
|
@ -1145,6 +1145,32 @@ def ajax_get_categories_by_thematic(request):
|
|||
return JsonResponse({'error': str(e)}, status=400)
|
||||
|
||||
|
||||
def ajax_get_teams_by_thematic(request):
|
||||
"""Get teams filtered by thematic for OperationTemplate admin."""
|
||||
thematic_id = request.GET.get('thematic_id')
|
||||
|
||||
try:
|
||||
from contracts.models import CompanyTeam
|
||||
if thematic_id:
|
||||
teams = CompanyTeam.objects.filter(
|
||||
Q(thematics__id=thematic_id) | Q(thematics__isnull=True)
|
||||
).distinct().select_related('company').order_by('name')
|
||||
else:
|
||||
teams = CompanyTeam.objects.select_related('company').order_by('name')
|
||||
|
||||
teams_data = [
|
||||
{
|
||||
'id': t.id,
|
||||
'name': str(t),
|
||||
}
|
||||
for t in teams
|
||||
]
|
||||
|
||||
return JsonResponse({'teams': teams_data})
|
||||
except Exception as e:
|
||||
return JsonResponse({'error': str(e)}, status=400)
|
||||
|
||||
|
||||
def ajax_get_subcategories(request):
|
||||
"""AJAX endpoint to get subcategories (children) of a given category.
|
||||
Used by intervention add/edit forms to populate the sub-category select.
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ __all__ = [
|
|||
'_asset_matches_filters',
|
||||
'_asset_matches_template_filters',
|
||||
'_assign_guided_template',
|
||||
'_assign_team_from_templates',
|
||||
'_attach_equipment_templates',
|
||||
'_build_guided_media_json',
|
||||
'_build_link_groups',
|
||||
|
|
@ -1102,6 +1103,26 @@ def _assign_guided_template(intervention, templates):
|
|||
|
||||
|
||||
|
||||
def _assign_team_from_templates(intervention, templates):
|
||||
"""
|
||||
If any selected OperationTemplate has a team FK set,
|
||||
auto-assign the first one found to the intervention.
|
||||
"""
|
||||
if not templates:
|
||||
return
|
||||
for tmpl in templates:
|
||||
if tmpl.team_id:
|
||||
intervention.assigned_team = tmpl.team
|
||||
fields_to_update = ['assigned_team']
|
||||
if not intervention.assigned_provider_id and tmpl.team.company_id:
|
||||
intervention.assigned_provider = tmpl.team.company
|
||||
fields_to_update.append('assigned_provider')
|
||||
intervention.save(update_fields=fields_to_update)
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
def _get_equipment_templates_for_intervention(intervention):
|
||||
templates = list(intervention.equipment_operation_templates.all())
|
||||
if templates:
|
||||
|
|
|
|||
|
|
@ -319,17 +319,28 @@ def intervention_add_preventive(request, thematic_code):
|
|||
# Utiliser la même commande pour toutes les répétitions
|
||||
orders_list = [order] * recurrence_count
|
||||
|
||||
# --- Pré-déterminer l'équipe associée aux templates d'opérations
|
||||
template_assigned_team = None
|
||||
for tmpl in operation_templates:
|
||||
if tmpl.team_id:
|
||||
template_assigned_team = tmpl.team
|
||||
break
|
||||
|
||||
# --- Fonction utilitaire pour créer une intervention
|
||||
def create_base_intervention(i: int, order_for_intervention):
|
||||
start_date = expected_start + i * recurrence_delta
|
||||
end_date = expected_end + i * recurrence_delta
|
||||
assigned_provider = contract.company if contract else None
|
||||
if not assigned_provider and template_assigned_team and template_assigned_team.company_id:
|
||||
assigned_provider = template_assigned_team.company
|
||||
intervention = Intervention.objects.create(
|
||||
title=title,
|
||||
status=status,
|
||||
status_order=STATUS_ORDERS[status],
|
||||
contract=contract,
|
||||
order=order_for_intervention,
|
||||
assigned_provider=contract.company if contract else None,
|
||||
assigned_provider=assigned_provider,
|
||||
assigned_team=template_assigned_team,
|
||||
expected_begin_time=start_date,
|
||||
expected_end_time=end_date,
|
||||
maintain_type="preventive",
|
||||
|
|
@ -437,6 +448,7 @@ def intervention_add_preventive(request, thematic_code):
|
|||
intervention = create_base_intervention(i, order_for_intervention)
|
||||
_attach_equipment_templates(intervention, operation_templates)
|
||||
_assign_guided_template(intervention, operation_templates)
|
||||
_assign_team_from_templates(intervention, operation_templates)
|
||||
|
||||
# 1) Lien générique intervention ↔ localisation
|
||||
ct = ContentType.objects.get_for_model(loc.__class__)
|
||||
|
|
@ -563,6 +575,7 @@ def intervention_add_preventive(request, thematic_code):
|
|||
intervention = create_base_intervention(i, order_for_intervention)
|
||||
_attach_equipment_templates(intervention, operation_templates)
|
||||
_assign_guided_template(intervention, operation_templates)
|
||||
_assign_team_from_templates(intervention, operation_templates)
|
||||
|
||||
# 1) Lien générique Asset ↔ Intervention
|
||||
InterventionAsset.objects.get_or_create(
|
||||
|
|
@ -633,6 +646,7 @@ def intervention_add_preventive(request, thematic_code):
|
|||
intervention = create_base_intervention(i, order_for_intervention)
|
||||
_attach_equipment_templates(intervention, operation_templates)
|
||||
_assign_guided_template(intervention, operation_templates)
|
||||
_assign_team_from_templates(intervention, operation_templates)
|
||||
|
||||
# Utiliser le titre de base
|
||||
intervention.title = title
|
||||
|
|
|
|||
|
|
@ -486,6 +486,8 @@ def process_worksheet(
|
|||
|
||||
# Lien template d'opérations
|
||||
intervention.equipment_operation_templates.add(template)
|
||||
from interventions.views.helpers import _assign_team_from_templates
|
||||
_assign_team_from_templates(intervention, [template])
|
||||
|
||||
# Timelines
|
||||
InterventionTimeLine.objects.create(
|
||||
|
|
|
|||
Loading…
Reference in a new issue