# -*- coding: utf-8 -*- from django import forms from django.shortcuts import render from django.views.decorators.csrf import csrf_protect from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth.decorators import permission_required from django.utils.encoding import force_text from django.conf import settings import xlrd from .models import Fond, FondStats from .forms import AdminBaseImportForm, AdminFondStatsImportForm DEBUG_IMPORT = getattr(settings, 'DEBUG_NPF_IMPORT', False) def _getval_str(row, cx): """Взять значение из колонки внутри переданной строки. Если значение прочитано из экселя как float вида 123.0, то .0 отбрасывается. Иначе значение берётся как есть. Всегда возвращает строку, начальные и хвостовые пробелы отрезаются. """ val = row[cx].value if isinstance(val, float) and val - int(val) == 0: val = int(val) return force_text((u'%s' % val).strip()) def _getval_int(row, cx): """Взять целое значение из колонки внутри переданной строки. Возвращает число или выбрасывает ошибку конвертации. """ val = row[cx].value return int(val) def _getval_int_or_none(row, cx): """Взять целое значение из колонки внутри переданной строки. Возвращает число или None в случае ошибки конвертации. """ val = row[cx].value try: return int(val) except ValueError: return None def _getval_float_or_none(row, cx): """Взять float из колонки внутри переданной строки. Возвращает число или None в случае ошибки конвертации. """ val = row[cx].value try: return float(val) except ValueError: return None @csrf_protect @staff_member_required @permission_required('can_import_export_fond', raise_exception=True) def revise_licenses(request): """Сверка лицензий НПФ.""" IDX_LICENSE = 0 # номер лицензии xls_file = None new_licenses = None closed_licenses = None start_nrow = 1 # с какой строки начинать импорт из файла (отсчёт с нуля) form_class = AdminBaseImportForm if request.method == 'GET': form = form_class() else: form = form_class(request.POST, request.FILES) if request.method == 'POST' and form.is_valid(): xls_file = request.FILES['xls_file'] xls_to_import = xls_file.read() book = xlrd.open_workbook(file_contents=xls_to_import) sh = book.sheet_by_index(0) # все лицензии в файле xls_licenses = set([_getval_str(sh.row(rx), IDX_LICENSE) for rx in xrange(start_nrow, sh.nrows)]) # все лицензии на сайте db_licenses = set(Fond.objects.all().order_by('license').values_list('license', flat=True)) # лицензии, которые есть в файле, но отсутствуют на сайте (новые фонды) new_licenses = xls_licenses.difference(db_licenses) # лицензии, которые есть на сайте, но отсутствуют в файле (закрывшиеся фонды) closed_licenses = db_licenses.difference(xls_licenses) return render(request, 'admin/npfs/revise_licenses.html', { 'form': form, 'xls': xls_file, 'new_licenses': new_licenses, 'closed_licenses': closed_licenses, }, ) @csrf_protect @staff_member_required @permission_required('can_imp_exp_fond_stats', raise_exception=True) def import_fond_stats(request): """Импорт основных показателей НПФ.""" import_errors = [] err_license_not_found = [] xls_file = None wrong_file = None start_nrow = 4 # с какой строки начинать импорт из файла (отсчёт с нуля) form_class = AdminFondStatsImportForm if request.method == 'GET': form = form_class() else: form = form_class(request.POST, request.FILES) if request.method == 'POST' and form.is_valid(): xls_file = request.FILES['xls_file'] xls_to_import = xls_file.read() book = xlrd.open_workbook(file_contents=xls_to_import) sh = book.sheet_by_index(0) god = int(form.cleaned_data['god']) kvartal = int(form.cleaned_data['kvartal']) # закешировать НПФ в словарь. ключ номер лицензии fond_cache = {_fond.license: _fond for _fond in Fond.objects.all()} rx = 0 for rx in xrange(start_nrow, sh.nrows): row = sh.row(rx) try: license = _getval_str(row, 0) if not license: raise Exception(u'Не указан `№ лицензии` в строке номер %d!' % (rx+1)) try: fond = fond_cache[license] except KeyError: err_license_not_found.append(rx + 1) raise Exception(u'Не найден `НПФ` в строке номер %d!' % (rx+1)) fond_stats, created = FondStats.objects.get_or_create( fond=fond, god=god, kvartal=kvartal) fond_stats.imusch = _getval_float_or_none(row, 2) fond_stats.kapital = _getval_float_or_none(row, 3) fond_stats.ioud = _getval_float_or_none(row, 4) fond_stats.pens_rezerv = _getval_float_or_none(row, 5) fond_stats.pens_nakopl = _getval_float_or_none(row, 6) fond_stats.obyazat = _getval_float_or_none(row, 7) fond_stats.pens_nakopl_rynok = _getval_float_or_none(row, 8) fond_stats.num_zastrah = _getval_int_or_none(row, 9) fond_stats.num_zastrah_pens = _getval_int_or_none(row, 10) fond_stats.pens_ops = _getval_float_or_none(row, 11) fond_stats.num_chel = _getval_int_or_none(row, 12) fond_stats.num_chel_pens = _getval_int_or_none(row, 13) fond_stats.vyplat_npo = _getval_float_or_none(row, 14) fond_stats.dohod_razmesch = _getval_float_or_none(row, 15) fond_stats.dohod_invest = _getval_float_or_none(row, 16) fond_stats.save() except: if DEBUG_IMPORT: raise else: import_errors.append(rx + 1) if rx + 1 > len(import_errors): wrong_file = False else: wrong_file = True return render(request, 'admin/npfs/fond_stats.html', { 'form': form, 'import_errors': import_errors, 'err_license_not_found': err_license_not_found, 'xls': xls_file, 'wrong_file': wrong_file, }, )