diff --git a/application/gia_practice_app/Practice/models.py b/application/gia_practice_app/Practice/models.py index 02c587e37..9dc8b50b7 100644 --- a/application/gia_practice_app/Practice/models.py +++ b/application/gia_practice_app/Practice/models.py @@ -158,6 +158,8 @@ class Practice(models.Model): evaluation_tools_v_sem = models.CharField(max_length=1024, blank=True, null=True, verbose_name="Оценочные средства по семестрам в Практике") number_of_semesters = models.IntegerField(blank=True, null=True, verbose_name="Количество семестров в практике") + weeks_start = models.CharField(max_length=1024, blank=True, null=True, + verbose_name="Недели начала практики") class PrerequisitesOfPractice(models.Model): diff --git a/application/static-backend/export_template/calendar_2023.xlsx b/application/static-backend/export_template/calendar_2023.xlsx new file mode 100644 index 000000000..7a4503ddc Binary files /dev/null and b/application/static-backend/export_template/calendar_2023.xlsx differ diff --git a/application/workprogramsapp/files_export/calendar_export.py b/application/workprogramsapp/files_export/calendar_export.py new file mode 100644 index 000000000..5e301be26 --- /dev/null +++ b/application/workprogramsapp/files_export/calendar_export.py @@ -0,0 +1,133 @@ +import openpyxl +from openpyxl.styles import Alignment, PatternFill, Side, Border, Font +from sentry_sdk import capture_exception + +from analytics_project.settings import AP_FILE_ROUTE +from gia_practice_app.Practice.models import Practice +from workprogramsapp.disciplineblockmodules.ze_module_logic import recursion_module, generate_full_ze_list, \ + recursion_module_per_ze, sum_lists +from workprogramsapp.models import DisciplineBlock, DisciplineBlockModule, WorkProgramChangeInDisciplineBlockModule, \ + СertificationEvaluationTool, ImplementationAcademicPlan, FieldOfStudy +from workprogramsapp.serializers import AcademicPlanSerializer + + +def fill_calendar(ws, sems_of_practice, type_practice, weeks=None, length=None): + semester_grid = {1: {"start": [12, 3], "end": [12, 19]}, + 2: {"start": [12, 25], "end": [12, 42]}, + 3: {"start": [19, 3], "end": [19, 19]}, + 4: {"start": [19, 25], "end": [20, 42]}, + 5: {"start": [26, 3], "end": [26, 19]}, + 6: {"start": [26, 25], "end": [30, 41]}, + 7: {"start": [33, 3], "end": [35, 19]}, + 8: {"start": [33, 25], "end": [37, 37]}, + } + holidays_grid = [[13, 12], [12, 28], [16, 37], [17, 38], + [20, 12], [19, 28], [23, 37], [24, 38], + [27, 12], [26, 28], [30, 37], [31, 38], + [34, 12], [33, 28], [37, 37], [38, 38]] + for i, sem in enumerate(sems_of_practice): + grid = semester_grid[sem] + if length: + if length[i] == 0: + continue + column = grid["start"][1] + weeks[i] - 1 + column_end = grid["start"][1] + length[i] + weeks[i] + row_end = grid["start"][0] + else: + column = grid["start"][1] + row_end, column_end = grid["end"] + + while True: + row = grid["start"][0] + for i in range(1, 7): + if row == row_end and column == column_end: + break + cell = ws.cell(row=row, column=column) + # print(cell.fill.start_color.index) + if [row, column] not in holidays_grid: + if type_practice == "educational": + cell.fill = PatternFill(start_color="d6dce4", fill_type="solid") + if cell.fill.start_color.index == "99ccff": + cell.value = "п,уп" + elif type_practice == "production": + cell.fill = PatternFill(start_color="99ccff", fill_type="solid") + if cell.fill.start_color.index == "d6dce4": + cell.value = "п,уп" + row += 1 + if row == row_end and column == column_end: + break + column += 1 + + +""" +from workprogramsapp.files_export.calendar_export import * +from workprogramsapp.models import * +ap = AcademicPlan.objects.get(id=7302) +process_excel(ap) + +""" + + +def process_practice(ws, practice_cb): + try: + practice_obj = Practice.objects.get( + zuns_for_pr__work_program_change_in_discipline_block_module=practice_cb) + except Practice.DoesNotExist: + return + if "преддипломная" in practice_obj.title.lower(): + return + semester_start = practice_cb.semester_start[0] + number_of_semesters = practice_obj.number_of_semesters + semester_list = [i for i in range(semester_start, semester_start + number_of_semesters)] + if practice_obj.format_practice == "dispersed": + fill_calendar(ws, semester_list, practice_obj.kind_of_practice) + elif practice_obj.format_practice == "dedicated": + weeks_start = [int(week) for week in practice_obj.weeks_start.split(", ")] + if not weeks_start: + weeks_start = [1 for _ in range(number_of_semesters)] + + length = [float(ze) / 1.5 for ze in practice_obj.ze_v_sem.split(", ")] + print(weeks_start, length) + fill_calendar(ws, semester_list, practice_obj.kind_of_practice, weeks_start, length) + + +def process_excel_calendar(academic_plan): + """wb_obj = openpyxl.load_workbook( + "C:\\Users\\s4\\Desktop\\analytics_backend\\application\\static-backend\\export_template\\calendar_2023.xlsx")""" + wb_obj = openpyxl.load_workbook("/application/static-backend/export_template/calendar_2023.xlsx") + ws = wb_obj["КУГ"] + + practice_cbs = academic_plan.get_all_changeblocks_from_ap(block_to_filter="Блок 2. Практика") + modules_practice = DisciplineBlockModule.objects.filter(change_blocks_of_work_programs_in_modules__in=practice_cbs) + for module in modules_practice: + cbs = WorkProgramChangeInDisciplineBlockModule.objects.filter(discipline_block_module=module) + if module.selection_rule == "choose_n_from_m": + for i in range(int(module.selection_parametr)): + practice_cb = cbs[i] + process_practice(ws, practice_cb) + if module.selection_rule == "by_credit_units": + credit_units_counter = 0 + for practice_cb in cbs: + try: + practice_obj = Practice.objects.get( + zuns_for_pr__work_program_change_in_discipline_block_module=practice_cb) + except Practice.DoesNotExist: + continue + credit_units_counter += sum([int(ze) for ze in practice_obj.ze_v_sem.split(", ")]) + if credit_units_counter <= int(module.selection_parametr): + process_practice(ws, practice_cb) + else: + break + if module.selection_rule == "all": + for practice_cb in cbs: + process_practice(ws, practice_cb) + + return wb_obj + + +"""def find_ze_modules_prac(modules=DisciplineBlockModule.objects.filter(descipline_block__name="Блок 2. Практика")): + for module in modules: + if module.selection_rule == "by_credit_units": + print(module.id, module.name, module.selection_parametr) + find_ze_modules_prac(module.childs.all()) +""" diff --git a/application/workprogramsapp/files_export/views.py b/application/workprogramsapp/files_export/views.py index d3b6f32e6..1713efa34 100644 --- a/application/workprogramsapp/files_export/views.py +++ b/application/workprogramsapp/files_export/views.py @@ -21,6 +21,7 @@ from dataprocessing.serializers import FileUploadSerializer from .academic_plan_export import process_excel +from .calendar_export import process_excel_calendar from .competence_matrix_export import process_excel_competence_matrix from .general_characteristic_export import generate_context from .plan_logic import plans_processor @@ -561,6 +562,28 @@ def get(self, request, *args, **kwargs): return response +class CalendarGenerateExcel(generics.ListAPIView): + """Возвращает КУГ в формате excel в браузере + Принимает в адерссной строке id ОХ""" + queryset = WorkProgram.objects.all() + serializer = WorkProgramSerializer + #permission_classes = [IsAuthenticated, ] + permission_classes = [AllowAny] + + def get(self, request, *args, **kwargs): + gen_characteristic = GeneralCharacteristics.objects.get(pk=kwargs['pk']) + filename = gen_characteristic.educational_program.all()[0].title + " " + str( + gen_characteristic.educational_program.all()[0].year) + ap = AcademicPlan.objects.filter(academic_plan_in_field_of_study__general_characteristics_in_educational_program=gen_characteristic).first() + wb_obj = process_excel_calendar(ap) + response = HttpResponse(content=save_virtual_workbook(wb_obj), + content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + response['Content-Disposition'] = 'inline; filename="%s"' % str(filename) + + + # wb_obj.save(response) + return response + @api_view(['POST']) @permission_classes((IsAdminUser,)) def UploadPlans(request): diff --git a/application/workprogramsapp/urls.py b/application/workprogramsapp/urls.py index b034f3372..e7004fbbd 100644 --- a/application/workprogramsapp/urls.py +++ b/application/workprogramsapp/urls.py @@ -9,7 +9,7 @@ ChangeExpertiseView, ExpertiseCreateView, ExpertiseWorkProgramView, ExpertiseListView, ExpertiseViewById, \ DeleteUserExpertise from .files_export.views import DocxFileExportView, SyllabusExportView, UploadPlans, UploadPlansAPIView, \ - AcademicPlanGenerateXlsx, GeneralCharacteristicGenerateDocx, CompetenceMatrixGenerateExcel + AcademicPlanGenerateXlsx, GeneralCharacteristicGenerateDocx, CompetenceMatrixGenerateExcel, CalendarGenerateExcel from .folders_ans_statistic.views import FoldersListView, WorkProgramInFolderView, CreateFolderView, EditFolderView, \ AddToFolderView, RemoveFromFolderView, DeleteFolderView, WorkProgramStatistic, \ AcademicPlanInFolderView, AddToFolderAcademicPlanView, RemoveFromFolderAcademicPlanView, \ @@ -193,6 +193,7 @@ path('api/export/academic_plan/', AcademicPlanGenerateXlsx.as_view()), path('api/export/general_characteristic/', GeneralCharacteristicGenerateDocx.as_view()), path('api/export/competence_matrix/', CompetenceMatrixGenerateExcel.as_view()), + path('api/export/calendar/', CalendarGenerateExcel.as_view()), # Учебный планы path('api/academicplan', AcademicPlanListAPIView.as_view()),