download pdf, refactor xls

feature/docker
Dmitriy Shesterkin 9 years ago
parent 4dd05235a4
commit cb13aee454
  1. 1
      requirements/base.txt
  2. 2
      src/commons/paginator.py
  3. 5
      src/commons/pdf_tools.py
  4. 1
      src/commons/xls/get_xlwt_style_list.py
  5. 15
      src/commons/xls/useful_tools.py
  6. 12
      src/commons/xls/xls_to_response.py
  7. 39
      src/docs/as_xls/render_to_xls.py
  8. 2
      src/docs/views/ajax.py
  9. 50
      src/docs/views/aktrabot.py
  10. 55
      src/docs/views/aktsverki.py
  11. 47
      src/docs/views/base_views.py
  12. 46
      src/docs/views/dover.py
  13. BIN
      src/xls_templates/aktrabot.xls
  14. BIN
      src/xls_templates/invoice.xls
  15. BIN
      stamp.png

@ -71,3 +71,4 @@ envvars==0.3.0
psycopg2==2.6
django-redis==4.8.0
redis==2.10.5
trans==2.1.0

@ -9,7 +9,7 @@ from commons.utils import safe_int
# допустимые значения `per_page`
_ALLOW_PER_PAGE = (10,20,50,75,100,) # по умолчанию
_ALLOW_PER_PAGE = (10, 20, 50, 75, 100,) # по умолчанию
ALLOW_PER_PAGE = getattr(settings, 'ALLOW_PER_PAGE', _ALLOW_PER_PAGE)

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from io import BytesIO
from trans import trans
from xhtml2pdf import pisa
from django.template.loader import render_to_string
@ -12,6 +12,9 @@ def pdf_to_response(content, filename=None):
"""Выводит content в django.http.HttpResponse, который и возвращает."""
response = HttpResponse(content, content_type='application/pdf')
if filename:
filename = filename.replace('"', "''")
filename = filename.replace('', 'N')
filename = trans(filename)
response['Content-Disposition'] = ('attachment; filename="{}"'.format(filename))
return response

@ -1,5 +1,6 @@
import xlwt
def get_xlwt_style_list(rdbook):
wt_style_list = []
for rdxf in rdbook.xf_list:

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
def copy_cells(src_sheet, dst_sheet, style_list,
row_from=0, row_to=None, dst_row_shift=0,
col_from=0, col_to=None, dst_col_shift=0):
@ -11,8 +12,8 @@ def copy_cells(src_sheet, dst_sheet, style_list,
row_to = row_to or src_sheet.nrows-1
col_to = col_to or src_sheet.ncols-1
for row in xrange(row_from, row_to+1):
for col in xrange(col_from, col_to+1):
for row in range(row_from, row_to+1):
for col in range(col_from, col_to+1):
cell = src_sheet.cell(row, col)
# скопировать контент и стиль ячейки
dst_sheet.write(
@ -36,7 +37,7 @@ def height_rows(src_sheet, dst_sheet,
"""Задать в диапазоне строк [row_from, row_to] высоту как в исходном листе.
"""
row_to = row_to or src_sheet.nrows-1
for row in xrange(row_from, row_to+1):
for row in range(row_from, row_to+1):
src_rowinfo = src_sheet.rowinfo_map.get(row)
if src_rowinfo:
dst_sheet.row(row+dst_row_shift).height = src_rowinfo.height
@ -88,7 +89,7 @@ def width_cols(src_sheet, dst_sheet, col_from=0, col_to=None, dst_col_shift=0):
как в исходном листе.
"""
col_to = col_to or src_sheet.ncols-1
for col in xrange(col_from, col_to+1):
for col in range(col_from, col_to+1):
dst_sheet.col(col+dst_col_shift).width = (
src_sheet.computed_column_width(col))
@ -111,7 +112,7 @@ def clone_row(src_sheet, dst_sheet, style_list,
Размножить n_times раз строку из исходного листа, с сохранением стилей
форматирования.
"""
for offset in xrange(n_times+1):
for offset in range(n_times+1):
copy_cells(src_sheet, dst_sheet, style_list,
row_from=src_row, row_to=src_row,
dst_row_shift=dst_row_shift+offset)
@ -141,7 +142,7 @@ def sum_src_heights(src_sheet, row_from, row_to):
исходного листа.
"""
result = 0
for row in xrange(row_from, row_to+1):
for row in range(row_from, row_to+1):
src_rowinfo = src_sheet.rowinfo_map.get(row)
if src_rowinfo:
result += src_rowinfo.height
@ -153,6 +154,6 @@ def sum_dst_heights(dst_sheet, row_from, row_to):
на новом листе.
"""
result = 0
for row in xrange(row_from, row_to+1):
for row in range(row_from, row_to+1):
result += dst_sheet.row(row).height
return result

@ -1,12 +1,14 @@
# -*- coding: utf-8 -*-
from trans import trans
from django.http import HttpResponse
def xls_to_response(content, filename=None, filename_encode='windows-1251'):
def xls_to_response(content, filename=None):
"""Выводит content в django.http.HttpResponse, который и возвращает."""
response = HttpResponse(content, mimetype='application/ms-excel')
response = HttpResponse(content, content_type='application/ms-excel')
if filename:
if filename_encode:
filename = filename.encode(filename_encode)
response['Content-Disposition'] = ('attachment; filename="%s"' % filename.replace('"', "''"))
filename = filename.replace('"', "''")
filename = filename.replace('', 'N')
filename = trans(filename)
response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
return response

@ -2,11 +2,7 @@
import os
import re
import math
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
from io import BytesIO
import xlrd
import xlwt
@ -34,7 +30,7 @@ def render_xls_to_string(request, xls_template, dictionary=None):
"""Создает по шаблону новую книгу Excel.
Возвращает строку, в которой сожержится сгенерированный Excel.
"""
src_xls = os.path.join(XLS_ROOT, xls_template) # файл шаблона
src_xls = os.path.join(XLS_ROOT, xls_template) # файл шаблона
src_book = None
try:
# откуда
@ -52,14 +48,14 @@ def render_xls_to_string(request, xls_template, dictionary=None):
# настройки
xls_settings = get_settings(src_book)
apply_page_settings(dst_sheet, xls_settings)
# import ipdb;ipdb.set_trace()
# заполнить данными
fill_xls(request, dictionary, src_sheet, dst_sheet, style_list,
xls_settings)
# закрыть исходную книгу и сохранить созданную
src_book.release_resources()
f=StringIO()
f = BytesIO()
dst_book.save(f)
xls_content = f.getvalue()
f.close()
@ -104,10 +100,10 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
row_to = row_to or src_sheet.nrows-1
col_to = col_to or src_sheet.ncols-1
for row in xrange(row_from, row_to+1):
for row in range(row_from, row_to+1):
cmd_fix_height = []
for col in xrange(col_from, col_to+1):
for col in range(col_from, col_to+1):
cell = src_sheet.cell(row, col)
cell_value = new_value = cell.value
@ -116,7 +112,7 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
cmd_draw_thin_bottom_border = False
# если в ячейке не строка - пропускаем
if not isinstance(new_value, unicode):
if not isinstance(new_value, str):
continue
# поискать шаблонные теги и переменные в ячейке
@ -149,7 +145,7 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
new_value = new_value.replace(u'@@FIX_HEIGHT@@', u'')
cmd_fix_height.append({
'col': col,
'value': unicode(new_value),
'value': new_value,
})
if new_value != cell_value:
@ -201,7 +197,7 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
for r1,r2,c1,c2 in src_sheet.merged_cells:
if r1 != row or c1 != fh['col']:
continue
for colx in xrange(c1, c2):
for colx in range(c1, c2):
width += src_sheet.computed_column_width(colx)
else:
break
@ -400,8 +396,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
horz_page_break(dst_sheet, p.TBL_FOOTER_TO + add_offset + 1)
parse_cells(
row_from = p.TBL_FOOTER_FROM,
dst_row_shift = add_offset
row_from=p.TBL_FOOTER_FROM,
dst_row_shift=add_offset
)
return
@ -410,24 +406,21 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
def get_settings(src_book, sheet_name=u'settings'):
"""Загрузить настройки с листа settings."""
settings = {}
# import ipdb;ipdb.set_trace()
try:
src_sheet = src_book.sheet_by_name(sheet_name)
except xlrd.XLRDError:
return settings
for row in xrange(src_sheet.nrows):
for row in range(src_sheet.nrows):
key_cell = src_sheet.cell(row, 0).value
if key_cell:
key_name = unicode(key_cell).strip()
# import ipdb;ipdb.set_trace()
key_name = key_cell.strip()
if not key_name.startswith(u'#'):
val_cell = src_sheet.cell(row, 1).value
if (isinstance(val_cell, unicode) or
isinstance(val_cell, str)):
settings[key_name] = unicode(val_cell)
else:
if isinstance(val_cell, float) or isinstance(val_cell, int):
settings[key_name] = val_cell
return settings

@ -9,7 +9,7 @@ from django.core import serializers
from django.db.models.loading import get_model
from django.views.decorators.csrf import csrf_protect
from ..models import Invoice
from docs.models import Invoice
from customer.utils import raise_if_no_profile

@ -1,26 +1,26 @@
# -*- coding: utf-8 -*-
from decimal import Decimal
from ..models import AktRabot, AktRabotItem
from ..forms import AktRabotForm, AktRabotItemForm
from ..filters import AktRabotFilterSet
from .. import utils
from docs.models import AktRabot, AktRabotItem
from docs.forms import AktRabotForm, AktRabotItemForm
from docs.filters import AktRabotFilterSet
from docs import utils
from .base_views import BaseItemsViews
from .mixins import AddByInvoiceMethodMixin
from docs.views.base_views import BaseItemsViews
from docs.views.mixins import AddByInvoiceMethodMixin
class AktRabotViews(BaseItemsViews, AddByInvoiceMethodMixin):
"""Views для актов выполн. работ."""
MODEL = AktRabot # модель документа
FORM_CLASS = AktRabotForm # форма документа
MODEL = AktRabot # модель документа
FORM_CLASS = AktRabotForm # форма документа
ITEM_MODEL = AktRabotItem # модель табличной части документа
ITEM_FORM_CLASS = AktRabotItemForm # форма табличной части документа
ITEM_FORM_PREFIX = 'aktrabot_items' # префикс формы табличной части
ITEM_MODEL = AktRabotItem # модель табличной части документа
ITEM_FORM_CLASS = AktRabotItemForm # форма табличной части документа
ITEM_FORM_PREFIX = 'aktrabot_items' # префикс формы табличной части
FILTERSET_CLASS = AktRabotFilterSet # фильтры
FILTERSET_CLASS = AktRabotFilterSet # фильтры
# по какому полю суммировать табличную часть документа при показе списком
LIST_SUM_FIELD = 'aktrabot_items__total_price'
@ -40,26 +40,26 @@ class AktRabotViews(BaseItemsViews, AddByInvoiceMethodMixin):
# для генерации pdf/xls
PDF_TEMPLATE = 'docs/aktrabot/as_pdf.html'
XLS_TEMPLATE = 'aktrabot.xls'
FILENAME = u'Акт выполненных работ № %s, %s' # без расширения
FILENAME = u'Акт выполненных работ № %s, %s' # без расширения
MAYBE_SIGNED = True
# --- грамматика для вывода наименований в шаблонах
PADEJI = {
'imenit': u'акт выполненных работ', # кто? что?
'rodit': u'акта выполненных работ', # кого? чего?
'dateln': u'акту выполненных работ', # кому? чему?
'vinit': u'акт выполненных работ', # кого? что?
'tvorit': u'актом выполненных работ', # кем? чем?
'predlojn': u'акте выполненных работ', # о ком? о чём?
'imenit': u'акт выполненных работ', # кто? что?
'rodit': u'акта выполненных работ', # кого? чего?
'dateln': u'акту выполненных работ', # кому? чему?
'vinit': u'акт выполненных работ', # кого? что?
'tvorit': u'актом выполненных работ', # кем? чем?
'predlojn': u'акте выполненных работ', # о ком? о чём?
}
PADEJI_MNOJ = {
'imenit': u'акты выполненных работ', # кто? что?
'rodit': u'актов выполненных работ', # кого? чего?
'dateln': u'актам выполненных работ', # кому? чему?
'vinit': u'акты выполненных работ', # кого? что?
'tvorit': u'актами выполненных работ', # кем? чем?
'predlojn': u'актах выполненных работ', # о ком? о чём?
'imenit': u'акты выполненных работ', # кто? что?
'rodit': u'актов выполненных работ', # кого? чего?
'dateln': u'актам выполненных работ', # кому? чему?
'vinit': u'акты выполненных работ', # кого? что?
'tvorit': u'актами выполненных работ', # кем? чем?
'predlojn': u'актах выполненных работ', # о ком? о чём?
}
def prepare(self, obj, obj_items, export_to=None):

@ -3,27 +3,27 @@ from decimal import Decimal
from customer.forms import ClientsListForm
from ..models import AktSverki, AktSverkiItem
from ..forms import AktSverkiForm, AktSverkiItemForm
from ..filters import AktSverkiFilterSet
from docs.models import AktSverki, AktSverkiItem
from docs.forms import AktSverkiForm, AktSverkiItemForm
from docs.filters import AktSverkiFilterSet
from .base_views import BaseItemsViews
from docs.views.base_views import BaseItemsViews
class AktSverkiViews(BaseItemsViews):
"""Views для актов сверки."""
MODEL = AktSverki # модель документа
FORM_CLASS = AktSverkiForm # форма документа
MODEL = AktSverki # модель документа
FORM_CLASS = AktSverkiForm # форма документа
ITEM_MODEL = AktSverkiItem # модель табличной части документа
ITEM_FORM_CLASS = AktSverkiItemForm # форма табличной части документа
ITEM_FORM_PREFIX = 'aktsverki_items' # префикс формы табличной части
ITEM_MODEL = AktSverkiItem # модель табличной части документа
ITEM_FORM_CLASS = AktSverkiItemForm # форма табличной части документа
ITEM_FORM_PREFIX = 'aktsverki_items' # префикс формы табличной части
# поля, по которым можно сортировать список документов
ORDER_FIELDS = ('doc_date', 'doc_num', 'client__name',)
FILTERSET_CLASS = AktSverkiFilterSet # фильтры
FILTERSET_CLASS = AktSverkiFilterSet # фильтры
# префикс именованных урлов этого типа документов, для передачи в шаблон
URL_PREFIX = 'docs_aktsverki_'
@ -39,25 +39,25 @@ class AktSverkiViews(BaseItemsViews):
# для генерации pdf/xls
PDF_TEMPLATE = 'docs/aktsverki/as_pdf.html'
XLS_TEMPLATE = 'aktsverki.xls'
FILENAME = u'Акт сверки № %s, %s' # без расширения
FILENAME = u'Акт сверки № %s, %s' # без расширения
# --- грамматика для вывода наименований в шаблонах
PADEJI = {
'imenit': u'акт сверки', # кто? что?
'rodit': u'акта сверки', # кого? чего?
'dateln': u'акту сверки', # кому? чему?
'vinit': u'акт сверки', # кого? что?
'tvorit': u'актом сверки', # кем? чем?
'predlojn': u'акте сверки', # о ком? о чём?
'imenit': u'акт сверки', # кто? что?
'rodit': u'акта сверки', # кого? чего?
'dateln': u'акту сверки', # кому? чему?
'vinit': u'акт сверки', # кого? что?
'tvorit': u'актом сверки', # кем? чем?
'predlojn': u'акте сверки', # о ком? о чём?
}
PADEJI_MNOJ = {
'imenit': u'акты сверки', # кто? что?
'rodit': u'актов сверки', # кого? чего?
'dateln': u'актам сверки', # кому? чему?
'vinit': u'акты сверки', # кого? что?
'tvorit': u'актами сверки', # кем? чем?
'predlojn': u'актах сверки', # о ком? о чём?
'imenit': u'акты сверки', # кто? что?
'rodit': u'актов сверки', # кого? чего?
'dateln': u'актам сверки', # кому? чему?
'vinit': u'акты сверки', # кого? что?
'tvorit': u'актами сверки', # кем? чем?
'predlojn': u'актах сверки', # о ком? о чём?
}
def update_list_dict(self, dictionary):
@ -86,11 +86,14 @@ class AktSverkiViews(BaseItemsViews):
obj.sum_debit += item.debit
obj.sum_credit += item.credit
if obj.sum_debit == obj.sum_credit: # нет задолженности
if obj.sum_debit == obj.sum_credit:
# нет задолженности
obj.sum_debit = obj.sum_credit = 0
elif obj.sum_debit > obj.sum_credit: # задолженность нам
elif obj.sum_debit > obj.sum_credit:
# задолженность нам
obj.sum_debit -= obj.sum_credit
obj.sum_credit = 0
elif obj.sum_debit < obj.sum_credit: # задолженность контрагенту
elif obj.sum_debit < obj.sum_credit:
# задолженность контрагенту
obj.sum_credit -= obj.sum_debit
obj.sum_debit = 0

@ -101,21 +101,21 @@ class BaseViews(object):
# --- константы для вывода наименований в шаблонах
PADEJI = {
'imenit': u'документ', # кто? что?
'rodit': u'документа', # кого? чего?
'dateln': u'документу', # кому? чему?
'vinit': u'документ', # кого? что?
'tvorit': u'документом', # кем? чем?
'predlojn': u'документе', # о ком? о чём?
'imenit': u'документ', # кто? что?
'rodit': u'документа', # кого? чего?
'dateln': u'документу', # кому? чему?
'vinit': u'документ', # кого? что?
'tvorit': u'документом', # кем? чем?
'predlojn': u'документе', # о ком? о чём?
}
PADEJI_MNOJ = {
'imenit': u'документы', # кто? что?
'rodit': u'документов', # кого? чего?
'dateln': u'документам', # кому? чему?
'vinit': u'документы', # кого? что?
'tvorit': u'документами', # кем? чем?
'predlojn': u'документах', # о ком? о чём?
'imenit': u'документы', # кто? что?
'rodit': u'документов', # кого? чего?
'dateln': u'документам', # кому? чему?
'vinit': u'документы', # кого? что?
'tvorit': u'документами', # кем? чем?
'predlojn': u'документах', # о ком? о чём?
}
def __init__(self, request):
@ -389,7 +389,7 @@ class BaseViews(object):
c1 = time()
xls = render_xls_to_string(self.request, self.XLS_TEMPLATE, params)
if DEBUG:
print ('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time()-c1,))
print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time()-c1,))
return xls
def as_img(self, *args, **kwargs):
@ -495,7 +495,7 @@ class BaseViews(object):
if form.cleaned_data['save_client_email']:
client = getattr(self.get_obj(kwargs['id']), 'client', None)
if client:
client.contact_email = form.cleaned_data['to'] # сохранить email клиента
client.contact_email = form.cleaned_data['to'] # сохранить email клиента
client.save()
doc_format = form.cleaned_data['doc_format']
@ -508,22 +508,22 @@ class BaseViews(object):
'filename': '%s.%s' % (filename, doc_format,),
'content': self.get_pdf(*args, **kwargs),
'mimetype': 'application/pdf',
},]
}, ]
elif doc_format == 'xls':
files = [{
'filename': '%s.%s' % (filename, doc_format,),
'content': self.get_xls(*args, **kwargs),
'mimetype': 'application/ms-excel',
},]
}, ]
return self.send_email(
subject = u'%s' % filename, # тема письма = имя файла без расширения
to = form.cleaned_data['to'],
body = form.cleaned_data['body'],
files = files,
sign_doc = form.cleaned_data.get('save_client_email', None)
subject=u'%s' % filename, # тема письма = имя файла без расширения
to=form.cleaned_data['to'],
body=form.cleaned_data['body'],
files=files,
sign_doc=form.cleaned_data.get('save_client_email', None)
)
return False # что-то пошло не так
return False # что-то пошло не так
@method_decorator(csrf_protect)
def email(self, *args, **kwargs):
@ -542,7 +542,8 @@ class BaseViews(object):
initial = {}
client = getattr(self.get_obj(kwargs['id']), 'client', None)
if client:
initial['to'] = client.contact_email # подставить в форму email клиента
# подставить в форму email клиента
initial['to'] = client.contact_email
form = self.EMAIL_FORM_CLASS(initial=initial)
dictionary = {

@ -3,27 +3,27 @@ import datetime
from customer.forms import ClientsListForm
from ..models import Dover, DoverItem
from ..forms import DoverForm, DoverItemForm
from ..filters import DoverFilterSet
from docs.models import Dover, DoverItem
from docs.forms import DoverForm, DoverItemForm
from docs.filters import DoverFilterSet
from .base_views import BaseItemsViews
from docs.views.base_views import BaseItemsViews
class DoverViews(BaseItemsViews):
"""Views для доверенностей на получение ТМЦ."""
MODEL = Dover # модель документа
FORM_CLASS = DoverForm # форма документа
MODEL = Dover # модель документа
FORM_CLASS = DoverForm # форма документа
ITEM_MODEL = DoverItem # модель табличной части документа
ITEM_FORM_CLASS = DoverItemForm # форма табличной части документа
ITEM_FORM_PREFIX = 'dover_items' # префикс формы табличной части
ITEM_MODEL = DoverItem # модель табличной части документа
ITEM_FORM_CLASS = DoverItemForm # форма табличной части документа
ITEM_FORM_PREFIX = 'dover_items' # префикс формы табличной части
# поля, по которым можно сортировать список документов
ORDER_FIELDS = ('doc_num', 'doc_date', 'doc_expire_date', 'dover_name', 'client__name',)
FILTERSET_CLASS = DoverFilterSet # фильтры
FILTERSET_CLASS = DoverFilterSet # фильтры
# префикс именованных урлов этого типа документов, для передачи в шаблон
URL_PREFIX = 'docs_dover_'
@ -39,25 +39,25 @@ class DoverViews(BaseItemsViews):
# для генерации pdf/xls
PDF_TEMPLATE = 'docs/dover/as_pdf.html'
XLS_TEMPLATE = 'dover.xls'
FILENAME = u'Доверенность № %s, %s' # без расширения
FILENAME = u'Доверенность № %s, %s' # без расширения
# --- грамматика для вывода наименований в шаблонах
PADEJI = {
'imenit': u'доверенность', # кто? что?
'rodit': u'доверенности', # кого? чего?
'dateln': u'доверенности', # кому? чему?
'vinit': u'доверенность', # кого? что?
'tvorit': u'доверенностью', # кем? чем?
'predlojn': u'доверенности', # о ком? о чём?
'imenit': u'доверенность', # кто? что?
'rodit': u'доверенности', # кого? чего?
'dateln': u'доверенности', # кому? чему?
'vinit': u'доверенность', # кого? что?
'tvorit': u'доверенностью', # кем? чем?
'predlojn': u'доверенности', # о ком? о чём?
}
PADEJI_MNOJ = {
'imenit': u'доверенности', # кто? что?
'rodit': u'доверенностью', # кого? чего?
'dateln': u'доверенностям', # кому? чему?
'vinit': u'доверенности', # кого? что?
'tvorit': u'доверенностями', # кем? чем?
'predlojn': u'доверенностях', # о ком? о чём?
'imenit': u'доверенности', # кто? что?
'rodit': u'доверенностью', # кого? чего?
'dateln': u'доверенностям', # кому? чему?
'vinit': u'доверенности', # кого? что?
'tvorit': u'доверенностями', # кем? чем?
'predlojn': u'доверенностях', # о ком? о чём?
}
def update_list_dict(self, dictionary):

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

Loading…
Cancel
Save