from datetime import date, timedelta from uuid import uuid4 from app_new.extensions import db from app_new.contracts.models import Contract, ContractVisit from app_new.core.models.company import Part, PartStockMovement from app_new.core.models.college import Building, Room from app_new.core.models.equipment import Equipment, EquipmentCategory from app_new.core.models.planning import Meter, MeterReading, Training, TrainingParticipant from app_new.outlook.models import OutlookAccount, OutlookMail, OutlookMailInterpretation def test_outlook_training_import_blocks_maintenance(authenticated_client, app, admin_user): with app.app_context(): account = OutlookAccount(user_id=admin_user['id'], email='formation@example.test', tenant_id='test') mail = OutlookMail(id=f'mail-{uuid4().hex}', account=account, subject='Formation habilitation', sender='Rectorat') interpretation = OutlookMailInterpretation( mail=mail, user_id=admin_user['id'], interpretation='Formation détectée', analysis_type='formation', suggested_title='Habilitation électrique', ) db.session.add_all([account, mail, interpretation]); db.session.commit() interpretation_id = interpretation.id day = date.today() + timedelta(days=10) with app.app_context(): response = authenticated_client.post(f'/training/import/outlook/{interpretation_id}', data={ 'title': 'Habilitation électrique', 'start_date': day.isoformat(), 'end_date': day.isoformat(), 'start_time': '09:00', 'end_time': '16:00', }) assert response.status_code == 302 with app.app_context(): training = Training.query.filter_by(source_type='outlook', source_id=str(interpretation_id)).one() assert training.start_time.hour == 9 assert TrainingParticipant.query.filter_by(training_id=training.id, user_id=admin_user['id'], is_confirmed=True).count() == 1 db.session.delete(training) OutlookMailInterpretation.query.filter_by(id=interpretation_id).delete() OutlookMail.query.filter(OutlookMail.id.like('mail-%')).delete(synchronize_session=False) OutlookAccount.query.filter_by(user_id=admin_user['id']).delete(synchronize_session=False) db.session.commit() def test_part_stock_movements_are_traced(authenticated_client, app): with app.app_context(): part = Part(name=f'Lampe {uuid4().hex[:6]}', quantity=5, unit='unité') db.session.add(part); db.session.commit(); part_id = part.id with app.app_context(): response = authenticated_client.post(f'/parts/{part_id}/movement', data={ 'movement_type': 'sortie', 'quantity': '2', 'reason': 'Intervention test', }) assert response.status_code == 302 with app.app_context(): assert db.session.get(Part, part_id).quantity == 3 movement = PartStockMovement.query.filter_by(part_id=part_id).one() assert (movement.quantity_before, movement.quantity_after) == (5, 3) def test_contract_visits_are_generated_without_duplicates(authenticated_client, app): with app.app_context(): contract = Contract(name=f'Contrat {uuid4().hex[:6]}', start_date=date.today(), visit_interval_days=30, next_visit_date=date.today()) db.session.add(contract); db.session.commit(); contract_id = contract.id with app.app_context(): assert authenticated_client.post(f'/contracts/{contract_id}/visits/generate').status_code == 302 assert authenticated_client.post(f'/contracts/{contract_id}/visits/generate').status_code == 302 with app.app_context(): visits = ContractVisit.query.filter_by(contract_id=contract_id).all() assert len(visits) >= 12 assert len({visit.scheduled_date for visit in visits}) == len(visits) def test_meter_decrease_requires_a_documented_reset(authenticated_client, app): with app.app_context(): building = Building(name=f'Bâtiment {uuid4().hex[:6]}') room = Room(name='Local', building=building) category = EquipmentCategory(name=f'Catégorie {uuid4().hex[:6]}') equipment = Equipment(name='Compteur test', category=category, room=room) meter = Meter(name='Heures', equipment=equipment, current_value=100, initial_value=0) db.session.add_all([building, room, category, equipment, meter]); db.session.commit(); meter_id = meter.id with app.app_context(): response = authenticated_client.post(f'/meters/{meter_id}/reading', data={'value': '10'}) assert response.status_code == 302 with app.app_context(): assert db.session.get(Meter, meter_id).current_value == 100 with app.app_context(): authenticated_client.post(f'/meters/{meter_id}/reading', data={ 'value': '10', 'is_reset': '1', 'reset_reason': 'Compteur remplacé', }) with app.app_context(): assert db.session.get(Meter, meter_id).current_value == 10 assert MeterReading.query.filter_by(meter_id=meter_id, is_reset=True).count() == 1 MeterReading.query.filter_by(meter_id=meter_id).delete() db.session.commit()