You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
710 lines
25 KiB
710 lines
25 KiB
# -*- coding: utf-8 -*-
|
|
from StringIO import StringIO
|
|
|
|
from django import forms
|
|
from django.shortcuts import render, redirect
|
|
from django.http import HttpResponse
|
|
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.utils import timezone
|
|
from django.db import connection, transaction
|
|
from django.conf import settings
|
|
|
|
import xlrd
|
|
import xlsxwriter
|
|
from urlify import urlify
|
|
|
|
from .models import OblOtdelen, NasPunkt, NasPunktOtdelen, OtdelType, Otdel
|
|
|
|
from .forms import AdminBaseImportForm
|
|
|
|
|
|
DEBUG_IMPORT = getattr(settings, 'DEBUG_PENSFONDS_IMPORT', False)
|
|
|
|
ALLOW_EMPTY_NASPUNKTS = False # разрешить пустые населенные пункты при импорте отделений
|
|
|
|
|
|
def _getval_str(row, cx, multiline=False):
|
|
"""Взять значение из колонки внутри переданной строки.
|
|
Если значение прочитано из экселя как float,
|
|
то сначала переводит его в int - чтобы отбросить дробную часть.
|
|
Если задан multiline, то преобразует символы # в \n.
|
|
Всегда возвращает строку, начальные и хвостовые пробелы отрезаются.
|
|
"""
|
|
val = row[cx].value
|
|
if isinstance(val, float):
|
|
val = int(val)
|
|
if multiline:
|
|
return force_text(u'%s' % val).replace('#','\n').replace('\r','').strip()
|
|
else:
|
|
return force_text((u'%s' % val).strip())
|
|
|
|
|
|
def _getval_int(row, cx):
|
|
"""Взять целое значение из колонки внутри переданной строки.
|
|
Возвращает число или выбрасывает ошибку конвертации.
|
|
"""
|
|
val = row[cx].value
|
|
return int(val)
|
|
|
|
|
|
def _prep_str(s):
|
|
"""Заменяет в переданной строке \r\n на \n.
|
|
Преобразует \n в символ #.
|
|
Начальные и хвостовые пробелы отрезаются.
|
|
"""
|
|
return s.replace('\r\n','\n').replace('\n','#').strip()
|
|
|
|
@csrf_protect
|
|
@staff_member_required
|
|
@permission_required('can_import_export_oblotdelen', raise_exception=True)
|
|
def import_obl_otdelen(request):
|
|
"""Импорт центральных отделений."""
|
|
import_errors = []
|
|
xls_file = None
|
|
wrong_file = 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)
|
|
|
|
rx = 0
|
|
for rx in xrange(start_nrow, sh.nrows):
|
|
row = sh.row(rx)
|
|
|
|
try:
|
|
oblast = _getval_str(row, 0)
|
|
|
|
if not oblast:
|
|
raise Exception(u'Не указана `область` в строке номер %d!' % (rx+1))
|
|
|
|
otdelen, created = OblOtdelen.objects.get_or_create(
|
|
oblast__iexact=oblast)
|
|
|
|
otdelen.oblast = oblast
|
|
otdelen.oblast_short = _getval_str(row, 1)
|
|
|
|
otdelen.po_regionu = _getval_str(row, 2)
|
|
otdelen.po_regionu_short = _getval_str(row, 3)
|
|
otdelen.regiona = _getval_str(row, 4)
|
|
otdelen.regiona_short = _getval_str(row, 5)
|
|
otdelen.regionalnoe = _getval_str(row, 6)
|
|
otdelen.otdely = _getval_str(row, 7)
|
|
|
|
otdelen.addr = _getval_str(row, 8)
|
|
#
|
|
otdelen.tel_hotline = _getval_str(row, 9, multiline=True) # multiline
|
|
otdelen.priemnaya = _getval_str(row, 10)
|
|
otdelen.fax = _getval_str(row, 11)
|
|
otdelen.smi = _getval_str(row, 12)
|
|
otdelen.head = _getval_str(row, 13)
|
|
otdelen.min_pensia = row[14].value or None
|
|
#
|
|
otdelen.doplata = row[15].value or None
|
|
|
|
## make slug
|
|
|
|
otdelen.slug = urlify(otdelen.oblast)
|
|
|
|
# now make sure slug is unique
|
|
_suffix = 2
|
|
while OblOtdelen.objects.filter(slug=otdelen.slug).exclude(pk=otdelen.pk).exists():
|
|
if _suffix > 10:
|
|
raise Exception(u'Too many iterations! Row %d.' % (rx+1))
|
|
otdelen.slug = "%s-%d" % (otdelen.slug, _suffix)
|
|
_suffix += 1
|
|
|
|
##
|
|
otdelen.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/pensfonds/import_obl_otdelen.html',
|
|
{
|
|
'form': form,
|
|
'import_errors': import_errors,
|
|
'xls': xls_file,
|
|
'wrong_file': wrong_file,
|
|
},
|
|
)
|
|
|
|
|
|
@csrf_protect
|
|
@staff_member_required
|
|
@permission_required('can_import_export_naspunkts', raise_exception=True)
|
|
def import_naspunkts(request):
|
|
"""Импорт населённых пунктов."""
|
|
import_errors = []
|
|
xls_file = None
|
|
wrong_file = 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)
|
|
|
|
# закешировать центральные отделения в словарь. ключ название области
|
|
obl_otdelens_cache = {_obl.oblast: _obl for _obl in OblOtdelen.objects.all()}
|
|
|
|
# закешировать населенные пункты в словарь. ключ tuple(naspunkt.obl_otdelen.pk, naspunkt.name)
|
|
naspunkts_cache = {(_naspunkt.obl_otdelen.pk, _naspunkt.name): _naspunkt
|
|
for _naspunkt in NasPunkt.objects.all().select_related()}
|
|
|
|
# какие нас. пункты уже добавили: уникальность по tuple(obl_otdelen.pk, naspunkt.name)
|
|
added_otdelens = set()
|
|
|
|
# список нас.пунктов, которые нужно добававить в базу (для bulk_create)
|
|
create_list = []
|
|
|
|
# список нас.пунктов, которые нужно изменить в базе (для bulk_update)
|
|
update_list = []
|
|
|
|
update_sql = '''UPDATE ''' + NasPunkt._meta.db_table + '''
|
|
SET
|
|
obl_otdelen_id = %s,
|
|
name = %s,
|
|
gde = %s,
|
|
chego = %s,
|
|
chemu = %s,
|
|
kakoy = %s,
|
|
kakoe = %s,
|
|
kakie = %s,
|
|
people_count = %s,
|
|
slug = %s,
|
|
updated_at = %s
|
|
WHERE id = %s;
|
|
'''
|
|
|
|
rx = 0
|
|
for rx in xrange(start_nrow, sh.nrows):
|
|
row = sh.row(rx)
|
|
|
|
try:
|
|
oblast = _getval_str(row, 0)
|
|
|
|
if not oblast:
|
|
raise Exception(u'Не указана `область` в строке номер %d!' % (rx+1))
|
|
|
|
try:
|
|
obl_otdelen = obl_otdelens_cache[oblast]
|
|
except KeyError:
|
|
raise Exception(u'Не найдено `центральное отделение` в строке номер %d!' % (rx+1))
|
|
|
|
#
|
|
naspunkt_name = _getval_str(row, 1)
|
|
|
|
if not naspunkt_name:
|
|
raise Exception(u'Не указан `населенный пункт` в строке номер %d!' % (rx+1))
|
|
|
|
#
|
|
_curr_otdelen_key = (obl_otdelen.pk, naspunkt_name)
|
|
|
|
# пропускать повторы
|
|
if _curr_otdelen_key in added_otdelens:
|
|
raise Exception(u'Повтор населенного пункта в строке номер %d!' % (rx+1))
|
|
|
|
added_otdelens.add(_curr_otdelen_key)
|
|
|
|
# изменить существующий объект или создать новый
|
|
if _curr_otdelen_key in naspunkts_cache:
|
|
otdelen = naspunkts_cache[_curr_otdelen_key]
|
|
else:
|
|
otdelen = NasPunkt()
|
|
|
|
otdelen.obl_otdelen = obl_otdelen
|
|
otdelen.name = naspunkt_name
|
|
|
|
otdelen.gde = _getval_str(row, 2)
|
|
otdelen.chego = _getval_str(row, 3)
|
|
otdelen.chemu = _getval_str(row, 4)
|
|
otdelen.kakoy = _getval_str(row, 5)
|
|
otdelen.kakoe = _getval_str(row, 6)
|
|
otdelen.kakie = _getval_str(row, 7)
|
|
|
|
otdelen.people_count = _getval_int(row, 8)
|
|
|
|
otdelen.slug = urlify(otdelen.name)
|
|
|
|
#
|
|
if _curr_otdelen_key in naspunkts_cache:
|
|
update_list.append(otdelen)
|
|
else:
|
|
create_list.append(otdelen)
|
|
|
|
except:
|
|
if DEBUG_IMPORT:
|
|
raise
|
|
else:
|
|
import_errors.append(rx + 1)
|
|
|
|
if create_list:
|
|
NasPunkt.objects.bulk_create(create_list)
|
|
|
|
if update_list:
|
|
_params = []
|
|
for otdelen in update_list:
|
|
_params.append((
|
|
otdelen.obl_otdelen.pk,
|
|
otdelen.name,
|
|
otdelen.gde,
|
|
otdelen.chego,
|
|
otdelen.chemu,
|
|
otdelen.kakoy,
|
|
otdelen.kakoe,
|
|
otdelen.kakie,
|
|
otdelen.people_count,
|
|
otdelen.slug,
|
|
timezone.now(), # updated_at
|
|
otdelen.pk, # record id for where clause
|
|
))
|
|
cursor = connection.cursor()
|
|
cursor.executemany(update_sql, _params)
|
|
transaction.commit_unless_managed()
|
|
|
|
if rx + 1 > len(import_errors):
|
|
wrong_file = False
|
|
else:
|
|
wrong_file = True
|
|
|
|
return render(request, 'admin/pensfonds/import_naspunkts.html',
|
|
{
|
|
'form': form,
|
|
'import_errors': import_errors,
|
|
'xls': xls_file,
|
|
'wrong_file': wrong_file,
|
|
},
|
|
)
|
|
|
|
|
|
@csrf_protect
|
|
@staff_member_required
|
|
@permission_required('can_import_export_naspunktotdelen', raise_exception=True)
|
|
def import_naspunkt_otdelen(request):
|
|
"""Импорт отделений в нас. пунктах."""
|
|
import_errors = []
|
|
xls_file = None
|
|
wrong_file = 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)
|
|
|
|
types_sh = book.sheet_by_index(1)
|
|
sh = book.sheet_by_index(0)
|
|
|
|
# закешировать центральные отделения в словарь. ключ название области
|
|
obl_otdelens_cache = {_obl.oblast: _obl for _obl in OblOtdelen.objects.all()}
|
|
|
|
# закешировать населенные пункты в словарь. ключ tuple(naspunkt.obl_otdelen.pk, naspunkt.name)
|
|
naspunkts_cache = {(_naspunkt.obl_otdelen.pk, _naspunkt.name): _naspunkt
|
|
for _naspunkt in NasPunkt.objects.all().select_related()}
|
|
|
|
# какие отделения в нас. пунктах уже добавили: уникальность по tuple(naspunkt.pk, obj)
|
|
added_otdelens = set()
|
|
|
|
# список объектов отделений, которые нужно сохранить в базу (для bulk_create)
|
|
objects_list = []
|
|
|
|
# в файле есть данные для импорта?
|
|
if sh.nrows > start_nrow:
|
|
NasPunktOtdelen.objects.all().delete() # очистить таблицу нас. пунктов
|
|
|
|
rx = 0
|
|
for rx in xrange(start_nrow, sh.nrows):
|
|
row = sh.row(rx)
|
|
|
|
try:
|
|
order = _getval_str(row, 0)
|
|
if not order:
|
|
continue # информацию по отделам заполняем в другом цикле
|
|
oblast = _getval_str(row, 1)
|
|
|
|
if not oblast:
|
|
raise Exception(u'Не указана `область` в строке номер %d!' % (rx+1))
|
|
|
|
try:
|
|
obl_otdelen = obl_otdelens_cache[oblast]
|
|
except KeyError:
|
|
raise Exception(u'Не найдено `центральное отделение` в строке номер %d!' % (rx+1))
|
|
|
|
#
|
|
|
|
naspunkt_name = _getval_str(row, 2)
|
|
|
|
if not naspunkt_name and not ALLOW_EMPTY_NASPUNKTS:
|
|
raise Exception(u'Не указан `населенный пункт` в строке номер %d!' % (rx+1))
|
|
|
|
try:
|
|
naspunkt = naspunkts_cache[(obl_otdelen.pk, naspunkt_name)]
|
|
except KeyError:
|
|
if not ALLOW_EMPTY_NASPUNKTS:
|
|
raise Exception(u'Не найден `населенный пункт` в строке номер %d!' % (rx+1))
|
|
else:
|
|
naspunkt = None
|
|
|
|
#
|
|
|
|
obj = _getval_str(row, 3)
|
|
|
|
if not obj:
|
|
raise Exception(u'Не указан `объект` в строке номер %d!' % (rx+1))
|
|
|
|
#
|
|
|
|
if naspunkt:
|
|
_curr_otdelen_key = (naspunkt.pk, obj)
|
|
|
|
if _curr_otdelen_key in added_otdelens:
|
|
raise Exception(u'Повтор отделения в строке номер %d!' % (rx+1))
|
|
|
|
added_otdelens.add((naspunkt.pk, obj))
|
|
|
|
#
|
|
|
|
otdelen = NasPunktOtdelen()
|
|
|
|
#
|
|
otdelen.obl_otdelen = obl_otdelen
|
|
otdelen.naspunkt = naspunkt
|
|
otdelen.obj = obj
|
|
#
|
|
otdelen.addr = _getval_str(row, 4)
|
|
#
|
|
otdelen.tel_hotline = _getval_str(row, 5, multiline=True) # multiline
|
|
otdelen.tel_priemn = _getval_str(row, 6, multiline=True) # multiline
|
|
otdelen.tel_info = _getval_str(row, 7, multiline=True) # multiline
|
|
#
|
|
otdelen.ordering = order
|
|
|
|
objects_list.append(otdelen)
|
|
|
|
except:
|
|
if DEBUG_IMPORT:
|
|
raise
|
|
else:
|
|
import_errors.append(rx + 1)
|
|
|
|
if objects_list:
|
|
NasPunktOtdelen.objects.bulk_create(objects_list)
|
|
|
|
order = None
|
|
|
|
OtdelType.objects.all().delete()
|
|
Otdel.objects.all().delete()
|
|
otdeltype_list = []
|
|
for rx in xrange(0, types_sh.nrows):
|
|
row = types_sh.row(rx)
|
|
otdel_type = OtdelType(name=_getval_str(row, 1))
|
|
otdeltype_list.append(otdel_type)
|
|
|
|
OtdelType.objects.bulk_create(otdeltype_list)
|
|
otdel_types = {i.name: i.id for i in OtdelType.objects.all()}
|
|
|
|
otdel_list = []
|
|
last_item = None
|
|
for rx in xrange(start_nrow, sh.nrows):
|
|
row = sh.row(rx)
|
|
|
|
try:
|
|
order = _getval_str(row, 0)
|
|
if order:
|
|
last_item = NasPunktOtdelen.objects.get(ordering=order).id
|
|
otdel = Otdel()
|
|
otdel.nas_punkt_otdelen_id = last_item
|
|
otdel.otdel_type_id = otdel_types[_getval_str(row, 8)]
|
|
otdel.phones = _getval_str(row, 9, multiline=True)
|
|
otdel.schedule = {
|
|
u'Пн': [_getval_str(row, 10),
|
|
_getval_str(row, 11)],
|
|
u'Вт': [_getval_str(row, 12),
|
|
_getval_str(row, 13)],
|
|
u'Ср': [_getval_str(row, 14),
|
|
_getval_str(row, 15)],
|
|
u'Чт': [_getval_str(row, 16),
|
|
_getval_str(row, 17)],
|
|
u'Пт': [_getval_str(row, 18),
|
|
_getval_str(row, 19)],
|
|
}
|
|
otdel.text_block = _getval_str(row, 20, multiline=True)
|
|
otdel_list.append(otdel)
|
|
except Exception as e:
|
|
pass
|
|
Otdel.objects.bulk_create(otdel_list)
|
|
|
|
|
|
if rx + 1 > len(import_errors):
|
|
wrong_file = False
|
|
else:
|
|
wrong_file = True
|
|
|
|
return render(request, 'admin/pensfonds/import_naspunkt_otdelen.html',
|
|
{
|
|
'form': form,
|
|
'import_errors': import_errors,
|
|
'xls': xls_file,
|
|
'wrong_file': wrong_file,
|
|
},
|
|
)
|
|
|
|
|
|
@staff_member_required
|
|
@permission_required('can_import_export_oblotdelen', raise_exception=True)
|
|
def export_obl_otdelen(request):
|
|
"""Экспорт центральных отделений."""
|
|
buf = StringIO()
|
|
|
|
book = xlsxwriter.Workbook(buf, {'constant_memory': True})
|
|
sh = book.add_worksheet()
|
|
|
|
sh.set_column('A:T', 30)
|
|
|
|
format_caption = book.add_format()
|
|
format_caption.set_bg_color('yellow')
|
|
format_caption.set_border(1)
|
|
|
|
sh.set_row(0, None, format_caption)
|
|
|
|
sh.write(0, 0, u'Регион')
|
|
sh.write(0, 1, u'Регион - коротко')
|
|
sh.write(0, 2, u'По региону')
|
|
sh.write(0, 3, u'По региону коротко')
|
|
sh.write(0, 4, u'Региона')
|
|
sh.write(0, 5, u'Региона коротко')
|
|
sh.write(0, 6, u'Региональное')
|
|
sh.write(0, 7, u'Отделы и управления')
|
|
sh.write(0, 8, u'Адрес')
|
|
sh.write(0, 9, u'Горячая линия')
|
|
sh.write(0, 10, u'Приемная')
|
|
sh.write(0, 11, u'Факс')
|
|
sh.write(0, 12, u'Работа со СМИ')
|
|
sh.write(0, 13, u'Руководитель отделения')
|
|
sh.write(0, 14, u'Мин. пенсия')
|
|
sh.write(0, 15, u'Размер соцдоплаты')
|
|
|
|
for rx, otd in enumerate(OblOtdelen.objects.all(), start=1):
|
|
sh.write(rx, 0, otd.oblast)
|
|
#
|
|
sh.write(rx, 1, otd.oblast_short)
|
|
sh.write(rx, 2, otd.po_regionu)
|
|
sh.write(rx, 3, otd.po_regionu_short)
|
|
sh.write(rx, 4, otd.regiona)
|
|
sh.write(rx, 5, otd.regiona_short)
|
|
sh.write(rx, 6, otd.regionalnoe)
|
|
#
|
|
sh.write(rx, 7, otd.otdely)
|
|
#
|
|
sh.write(rx, 8, otd.addr) # multiline
|
|
sh.write(rx, 9, _prep_str(otd.tel_hotline)) # multiline
|
|
sh.write(rx, 10, _prep_str(otd.priemnaya)) # multiline
|
|
sh.write(rx, 11, _prep_str(otd.fax)) # multiline
|
|
sh.write(rx, 12, _prep_str(otd.smi)) # multiline
|
|
#
|
|
sh.write(rx, 13, otd.head)
|
|
#
|
|
sh.write(rx, 14, otd.min_pensia)
|
|
sh.write(rx, 15, otd.doplata)
|
|
|
|
book.close()
|
|
|
|
content = buf.getvalue()
|
|
buf.close()
|
|
|
|
#
|
|
filename = u'Центральные_отделения'
|
|
|
|
response = HttpResponse(content, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
|
response['Content-Disposition'] = 'attachment; filename=%s.xlsx' % filename.encode('windows-1251')
|
|
|
|
return response
|
|
|
|
|
|
@staff_member_required
|
|
@permission_required('can_import_export_naspunkts', raise_exception=True)
|
|
def export_naspunkts(request):
|
|
"""Экспорт населённых пунктов."""
|
|
buf = StringIO()
|
|
|
|
book = xlsxwriter.Workbook(buf, {'constant_memory': True})
|
|
sh = book.add_worksheet()
|
|
|
|
sh.set_column('A:J', 30)
|
|
|
|
format_caption = book.add_format()
|
|
format_caption.set_bg_color('yellow')
|
|
format_caption.set_border(1)
|
|
|
|
sh.set_row(0, None, format_caption)
|
|
|
|
sh.write(0, 0, u'Регион')
|
|
sh.write(0, 1, u'населенный пункт')
|
|
sh.write(0, 2, u'где')
|
|
sh.write(0, 3, u'чего')
|
|
sh.write(0, 4, u'чему')
|
|
sh.write(0, 5, u'какой')
|
|
sh.write(0, 6, u'какое')
|
|
sh.write(0, 7, u'какие')
|
|
sh.write(0, 8, u'пенсионеры')
|
|
|
|
for rx, otd in enumerate(NasPunkt.objects.all().select_related(), start=1):
|
|
sh.write(rx, 0, otd.obl_otdelen.oblast)
|
|
#
|
|
sh.write(rx, 1, otd.name)
|
|
sh.write(rx, 2, otd.gde)
|
|
sh.write(rx, 3, otd.chego)
|
|
sh.write(rx, 4, otd.chemu)
|
|
sh.write(rx, 5, otd.kakoy)
|
|
sh.write(rx, 6, otd.kakoe)
|
|
sh.write(rx, 7, otd.kakie)
|
|
#
|
|
sh.write(rx, 8, otd.people_count)
|
|
|
|
book.close()
|
|
|
|
content = buf.getvalue()
|
|
buf.close()
|
|
|
|
#
|
|
filename = u'Населенные_пункты'
|
|
|
|
response = HttpResponse(content, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
|
response['Content-Disposition'] = 'attachment; filename=%s.xlsx' % filename.encode('windows-1251')
|
|
|
|
return response
|
|
|
|
|
|
@staff_member_required
|
|
@permission_required('can_import_export_naspunktotdelen', raise_exception=True)
|
|
def export_naspunkt_otdelen(request):
|
|
"""Экспорт всех отделений в нас. пунктах."""
|
|
buf = StringIO()
|
|
|
|
book = xlsxwriter.Workbook(buf, {'constant_memory': True})
|
|
sh = book.add_worksheet()
|
|
|
|
sh.set_column('A:O', 30)
|
|
|
|
format_caption = book.add_format()
|
|
format_caption.set_bg_color('yellow')
|
|
format_caption.set_border(1)
|
|
|
|
sh.set_row(0, None, format_caption)
|
|
|
|
sh.write(0, 0, u'№ объекта')
|
|
sh.write(0, 1, u'Область')
|
|
sh.write(0, 2, u'Населенный пункт')
|
|
sh.write(0, 3, u'Объект')
|
|
sh.write(0, 4, u'Адрес')
|
|
sh.write(0, 5, u'телефон горячей линии')
|
|
sh.write(0, 6, u'телефон приемной')
|
|
sh.write(0, 7, u'доп. телефоны')
|
|
|
|
sh.write(0, 8, u'Отдел')
|
|
sh.write(0, 9, u'телефоны')
|
|
sh.write(0, 10, u'Пн.')
|
|
sh.write(0, 11, u'Пн. обед')
|
|
sh.write(0, 12, u'Вт.')
|
|
sh.write(0, 13, u'Вт. обед')
|
|
sh.write(0, 14, u'Ср.')
|
|
sh.write(0, 15, u'Ср. обед')
|
|
sh.write(0, 16, u'Чт.')
|
|
sh.write(0, 17, u'Чт. обед')
|
|
sh.write(0, 18, u'Пт.')
|
|
sh.write(0, 19, u'Пт. обед')
|
|
sh.write(0, 20, u'текст в блок')
|
|
|
|
rx = 1
|
|
for otd in NasPunktOtdelen.objects.all().order_by('ordering').select_related():
|
|
sh.write(rx, 0, otd.ordering)
|
|
sh.write(rx, 1, otd.obl_otdelen.oblast)
|
|
#
|
|
if otd.naspunkt:
|
|
sh.write(rx, 2, otd.naspunkt.name)
|
|
#
|
|
sh.write(rx, 3, otd.obj)
|
|
#
|
|
sh.write(rx, 4, otd.addr)
|
|
sh.write(rx, 5, _prep_str(otd.tel_hotline)) # multiline
|
|
sh.write(rx, 6, _prep_str(otd.tel_priemn)) # multiline
|
|
sh.write(rx, 7, _prep_str(otd.tel_info)) # multiline
|
|
otdels = otd.otdels.all().select_related('otdel_type').order_by()
|
|
for otdel in otdels:
|
|
sh.write(rx, 8, otdel.otdel_type.name)
|
|
sh.write(rx, 9, _prep_str(otdel.phones))
|
|
sh.write(rx, 10, otdel.schedule[u'Пн'][0])
|
|
sh.write(rx, 11, otdel.schedule[u'Пн'][1])
|
|
sh.write(rx, 12, otdel.schedule[u'Вт'][0])
|
|
sh.write(rx, 13, otdel.schedule[u'Вт'][1])
|
|
sh.write(rx, 14, otdel.schedule[u'Ср'][0])
|
|
sh.write(rx, 15, otdel.schedule[u'Ср'][1])
|
|
sh.write(rx, 16, otdel.schedule[u'Чт'][0])
|
|
sh.write(rx, 17, otdel.schedule[u'Чт'][1])
|
|
sh.write(rx, 18, otdel.schedule[u'Пт'][0])
|
|
sh.write(rx, 19, otdel.schedule[u'Пт'][1])
|
|
sh.write(rx, 20, _prep_str(otdel.text_block))
|
|
rx += 1
|
|
|
|
if not otdels:
|
|
rx += 1
|
|
|
|
# справочник отделов
|
|
types_sh = book.add_worksheet()
|
|
types_sh.set_column('B:B', 60)
|
|
for rx, otdel_type in enumerate(OtdelType.objects.all()):
|
|
types_sh.write(rx, 1, otdel_type.name)
|
|
|
|
book.close()
|
|
|
|
content = buf.getvalue()
|
|
buf.close()
|
|
|
|
#
|
|
filename = u'Отделения_в_населенных_пунктах'
|
|
|
|
response = HttpResponse(content, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
|
response['Content-Disposition'] = 'attachment; filename=%s.xlsx' % filename.encode('windows-1251')
|
|
|
|
return response
|
|
|