diff --git a/loko/assets/tests.py b/loko/assets/tests.py index c144ae9..0ef671f 100644 --- a/loko/assets/tests.py +++ b/loko/assets/tests.py @@ -4077,6 +4077,8 @@ class ExportAssetsTest(TestCase): content = response.content.decode('utf-8') self.assertIn("EXP01A-000001", content) self.assertIn("Asset Pour Export", content) + from django.utils.translation import gettext as _ + self.assertNotIn(_("Type de panneau"), content) def test_export_assets_with_duplicate_content_types(self): from django.urls import reverse @@ -4098,6 +4100,41 @@ class ExportAssetsTest(TestCase): content = response.content.decode('utf-8') self.assertIn("EXP01A-000001", content) + def test_export_signpanel_with_type(self): + from django.urls import reverse + from assets.models import SignPanel, SignPanelType, SignPole, SignStreet + + thematic_sign = Thematic.objects.get_or_create(code="sign", defaults={"name_fr": "Signalisation"})[0] + UserThematics.objects.create( + user_config=self.user_config, + thematic=thematic_sign, + can_view_assets=True, + can_edit_assets=True, + ) + + street = SignStreet.objects.create(name_fr="Rue du Test", code="STR01") + pole = SignPole.objects.create(code="POL01", street=street) + panel_type = SignPanelType.objects.create(code="C15", name_fr="Accès interdit", name_nl="Verboden toegang") + panel = SignPanel.objects.create( + code="PAN01", + pole=pole, + street=street, + signpanel_type=panel_type, + status="active", + ) + + self.client.force_login(self.user) + url = reverse('assets:export_assets') + ids_json = json.dumps([f"signpanel:{panel.id}"]) + + response = self.client.post(url, {'ids': ids_json, 'format': 'csv'}) + self.assertEqual(response.status_code, 200) + content = response.content.decode('utf-8') + from django.utils.translation import gettext as _ + self.assertIn(_("Type de panneau"), content) + self.assertIn("C15 - Accès interdit", content) + self.assertIn("PAN01", content) + diff --git a/loko/assets/views/export.py b/loko/assets/views/export.py index 6a04a41..3f152c6 100644 --- a/loko/assets/views/export.py +++ b/loko/assets/views/export.py @@ -47,6 +47,21 @@ def _get_asset_model_display(asset): return '' +def _get_asset_signpanel_type_display(asset): + """Return the signpanel type code and/or name (e.g. 'C15' or 'C15 - Accès interdit...') if applicable.""" + try: + spt = getattr(asset, 'signpanel_type', None) + if spt: + code = (getattr(spt, 'code', '') or '').strip() + name = (spt.get_name() if hasattr(spt, 'get_name') else getattr(spt, 'name_fr', '')) or '' + if code and name: + return f"{code} - {name}" + return code or name or '' + except Exception: + pass + return '' + + def _fmt_date(dt): if dt is None: return '' @@ -56,7 +71,7 @@ def _fmt_date(dt): return str(dt) -def _get_row(model_name, asset): +def _get_row(model_name, asset, include_signpanel_type=False): location = _get_asset_location(asset) loc_code = location.code if location else '' loc_name = location.get_name() if location else '' @@ -71,13 +86,17 @@ def _get_row(model_name, asset): else (getattr(asset, 'obsolescence', '') or '') ) warranty = getattr(asset, 'warranty_duration', None) - return [ + row = [ model_name, asset.id, asset.code or '', asset.get_name() if hasattr(asset, 'get_name') else '', asset.category.get_name() if getattr(asset, 'category', None) else '', _get_asset_model_display(asset), + ] + if include_signpanel_type: + row.append(_get_asset_signpanel_type_display(asset)) + row.extend([ status_display, obsolescence_display, loc_code, @@ -90,29 +109,36 @@ def _get_row(model_name, asset): getattr(asset, 'note', '') or '', getattr(asset, 'lon', '') if getattr(asset, 'lon', None) is not None else '', getattr(asset, 'lat', '') if getattr(asset, 'lat', None) is not None else '', + ]) + return row + + +def _get_export_headers(include_signpanel_type=False): + headers = [ + _("Type"), + _("ID"), + _("Code"), + _("Nom"), + _("Catégorie"), + _("Modèle"), ] - - -EXPORT_HEADERS = [ - _("Type"), - _("ID"), - _("Code"), - _("Nom"), - _("Catégorie"), - _("Modèle"), - _("Statut"), - _("Obsolescence"), - _("Code localisation"), - _("Nom localisation"), - _("Date d'installation"), - _("Date de déinstallation"), - _("Numéro de série"), - _("Garantie (mois)"), - _("Marque"), - _("Note"), - _("Longitude"), - _("Latitude"), -] + if include_signpanel_type: + headers.append(_("Type de panneau")) + headers.extend([ + _("Statut"), + _("Obsolescence"), + _("Code localisation"), + _("Nom localisation"), + _("Date d'installation"), + _("Date de déinstallation"), + _("Numéro de série"), + _("Garantie (mois)"), + _("Marque"), + _("Note"), + _("Longitude"), + _("Latitude"), + ]) + return [str(h) for h in headers] @login_required @@ -164,14 +190,25 @@ def export_assets(request): break if model_class is None: continue - for asset in model_class.objects.filter(pk__in=asset_ids): + qs = model_class.objects.filter(pk__in=asset_ids) + for fk in ('category', 'model', 'signpanel_type'): + if any(f.name == fk for f in model_class._meta.fields): + try: + qs = qs.select_related(fk) + except Exception: + pass + for asset in qs: if can_view_asset(request.user, asset): items.append((model_name, asset)) except Exception: continue + has_signpanels = any( + model_name == 'signpanel' or hasattr(asset, 'signpanel_type') + for model_name, asset in items + ) timestamp = localtime(now()).strftime('%Y%m%d_%H%M%S') - headers = [str(h) for h in EXPORT_HEADERS] + headers = _get_export_headers(include_signpanel_type=has_signpanels) if fmt == 'xlsx': try: @@ -189,7 +226,7 @@ def export_assets(request): ws.title = 'Assets' ws.append(headers) for model_name, asset in items: - ws.append([_sanitize(v) for v in _get_row(model_name, asset)]) + ws.append([_sanitize(v) for v in _get_row(model_name, asset, include_signpanel_type=has_signpanels)]) output = BytesIO() wb.save(output) @@ -211,6 +248,6 @@ def export_assets(request): writer = csv.writer(resp, delimiter=';') writer.writerow(headers) for model_name, asset in items: - writer.writerow(_get_row(model_name, asset)) + writer.writerow(_get_row(model_name, asset, include_signpanel_type=has_signpanels)) return resp