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. 37
      src/docs/as_xls/render_to_xls.py
  8. 2
      src/docs/views/ajax.py
  9. 12
      src/docs/views/aktrabot.py
  10. 17
      src/docs/views/aktsverki.py
  11. 19
      src/docs/views/base_views.py
  12. 8
      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 psycopg2==2.6
django-redis==4.8.0 django-redis==4.8.0
redis==2.10.5 redis==2.10.5
trans==2.1.0

@ -9,7 +9,7 @@ from commons.utils import safe_int
# допустимые значения `per_page` # допустимые значения `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) ALLOW_PER_PAGE = getattr(settings, 'ALLOW_PER_PAGE', _ALLOW_PER_PAGE)

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

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

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

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

@ -2,11 +2,7 @@
import os import os
import re import re
import math import math
try: from io import BytesIO
from StringIO import StringIO
except ImportError:
from io import StringIO
import xlrd import xlrd
import xlwt import xlwt
@ -52,14 +48,14 @@ def render_xls_to_string(request, xls_template, dictionary=None):
# настройки # настройки
xls_settings = get_settings(src_book) xls_settings = get_settings(src_book)
apply_page_settings(dst_sheet, xls_settings) apply_page_settings(dst_sheet, xls_settings)
# import ipdb;ipdb.set_trace()
# заполнить данными # заполнить данными
fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, fill_xls(request, dictionary, src_sheet, dst_sheet, style_list,
xls_settings) xls_settings)
# закрыть исходную книгу и сохранить созданную # закрыть исходную книгу и сохранить созданную
src_book.release_resources() src_book.release_resources()
f=StringIO() f = BytesIO()
dst_book.save(f) dst_book.save(f)
xls_content = f.getvalue() xls_content = f.getvalue()
f.close() 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 row_to = row_to or src_sheet.nrows-1
col_to = col_to or src_sheet.ncols-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 = [] 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 = src_sheet.cell(row, col)
cell_value = new_value = cell.value 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 cmd_draw_thin_bottom_border = False
# если в ячейке не строка - пропускаем # если в ячейке не строка - пропускаем
if not isinstance(new_value, unicode): if not isinstance(new_value, str):
continue 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'') new_value = new_value.replace(u'@@FIX_HEIGHT@@', u'')
cmd_fix_height.append({ cmd_fix_height.append({
'col': col, 'col': col,
'value': unicode(new_value), 'value': new_value,
}) })
if new_value != cell_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: for r1,r2,c1,c2 in src_sheet.merged_cells:
if r1 != row or c1 != fh['col']: if r1 != row or c1 != fh['col']:
continue continue
for colx in xrange(c1, c2): for colx in range(c1, c2):
width += src_sheet.computed_column_width(colx) width += src_sheet.computed_column_width(colx)
else: else:
break 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) horz_page_break(dst_sheet, p.TBL_FOOTER_TO + add_offset + 1)
parse_cells( parse_cells(
row_from = p.TBL_FOOTER_FROM, row_from=p.TBL_FOOTER_FROM,
dst_row_shift = add_offset dst_row_shift=add_offset
) )
return 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'): def get_settings(src_book, sheet_name=u'settings'):
"""Загрузить настройки с листа settings.""" """Загрузить настройки с листа settings."""
settings = {} settings = {}
# import ipdb;ipdb.set_trace()
try: try:
src_sheet = src_book.sheet_by_name(sheet_name) src_sheet = src_book.sheet_by_name(sheet_name)
except xlrd.XLRDError: except xlrd.XLRDError:
return settings return settings
for row in xrange(src_sheet.nrows): for row in range(src_sheet.nrows):
key_cell = src_sheet.cell(row, 0).value key_cell = src_sheet.cell(row, 0).value
if key_cell: 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'#'): if not key_name.startswith(u'#'):
val_cell = src_sheet.cell(row, 1).value val_cell = src_sheet.cell(row, 1).value
if (isinstance(val_cell, unicode) or if isinstance(val_cell, float) or isinstance(val_cell, int):
isinstance(val_cell, str)):
settings[key_name] = unicode(val_cell)
else:
settings[key_name] = val_cell settings[key_name] = val_cell
return settings return settings

@ -9,7 +9,7 @@ from django.core import serializers
from django.db.models.loading import get_model from django.db.models.loading import get_model
from django.views.decorators.csrf import csrf_protect 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 from customer.utils import raise_if_no_profile

@ -1,13 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from decimal import Decimal from decimal import Decimal
from ..models import AktRabot, AktRabotItem from docs.models import AktRabot, AktRabotItem
from ..forms import AktRabotForm, AktRabotItemForm from docs.forms import AktRabotForm, AktRabotItemForm
from ..filters import AktRabotFilterSet from docs.filters import AktRabotFilterSet
from .. import utils from docs import utils
from .base_views import BaseItemsViews from docs.views.base_views import BaseItemsViews
from .mixins import AddByInvoiceMethodMixin from docs.views.mixins import AddByInvoiceMethodMixin
class AktRabotViews(BaseItemsViews, AddByInvoiceMethodMixin): class AktRabotViews(BaseItemsViews, AddByInvoiceMethodMixin):

@ -3,11 +3,11 @@ from decimal import Decimal
from customer.forms import ClientsListForm from customer.forms import ClientsListForm
from ..models import AktSverki, AktSverkiItem from docs.models import AktSverki, AktSverkiItem
from ..forms import AktSverkiForm, AktSverkiItemForm from docs.forms import AktSverkiForm, AktSverkiItemForm
from ..filters import AktSverkiFilterSet from docs.filters import AktSverkiFilterSet
from .base_views import BaseItemsViews from docs.views.base_views import BaseItemsViews
class AktSverkiViews(BaseItemsViews): class AktSverkiViews(BaseItemsViews):
@ -86,11 +86,14 @@ class AktSverkiViews(BaseItemsViews):
obj.sum_debit += item.debit obj.sum_debit += item.debit
obj.sum_credit += item.credit 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 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_debit -= obj.sum_credit
obj.sum_credit = 0 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_credit -= obj.sum_debit
obj.sum_debit = 0 obj.sum_debit = 0

@ -389,7 +389,7 @@ class BaseViews(object):
c1 = time() c1 = time()
xls = render_xls_to_string(self.request, self.XLS_TEMPLATE, params) xls = render_xls_to_string(self.request, self.XLS_TEMPLATE, params)
if DEBUG: 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 return xls
def as_img(self, *args, **kwargs): def as_img(self, *args, **kwargs):
@ -508,20 +508,20 @@ class BaseViews(object):
'filename': '%s.%s' % (filename, doc_format,), 'filename': '%s.%s' % (filename, doc_format,),
'content': self.get_pdf(*args, **kwargs), 'content': self.get_pdf(*args, **kwargs),
'mimetype': 'application/pdf', 'mimetype': 'application/pdf',
},] }, ]
elif doc_format == 'xls': elif doc_format == 'xls':
files = [{ files = [{
'filename': '%s.%s' % (filename, doc_format,), 'filename': '%s.%s' % (filename, doc_format,),
'content': self.get_xls(*args, **kwargs), 'content': self.get_xls(*args, **kwargs),
'mimetype': 'application/ms-excel', 'mimetype': 'application/ms-excel',
},] }, ]
return self.send_email( return self.send_email(
subject = u'%s' % filename, # тема письма = имя файла без расширения subject=u'%s' % filename, # тема письма = имя файла без расширения
to = form.cleaned_data['to'], to=form.cleaned_data['to'],
body = form.cleaned_data['body'], body=form.cleaned_data['body'],
files = files, files=files,
sign_doc = form.cleaned_data.get('save_client_email', None) sign_doc=form.cleaned_data.get('save_client_email', None)
) )
return False # что-то пошло не так return False # что-то пошло не так
@ -542,7 +542,8 @@ class BaseViews(object):
initial = {} initial = {}
client = getattr(self.get_obj(kwargs['id']), 'client', None) client = getattr(self.get_obj(kwargs['id']), 'client', None)
if client: if client:
initial['to'] = client.contact_email # подставить в форму email клиента # подставить в форму email клиента
initial['to'] = client.contact_email
form = self.EMAIL_FORM_CLASS(initial=initial) form = self.EMAIL_FORM_CLASS(initial=initial)
dictionary = { dictionary = {

@ -3,11 +3,11 @@ import datetime
from customer.forms import ClientsListForm from customer.forms import ClientsListForm
from ..models import Dover, DoverItem from docs.models import Dover, DoverItem
from ..forms import DoverForm, DoverItemForm from docs.forms import DoverForm, DoverItemForm
from ..filters import DoverFilterSet from docs.filters import DoverFilterSet
from .base_views import BaseItemsViews from docs.views.base_views import BaseItemsViews
class DoverViews(BaseItemsViews): class DoverViews(BaseItemsViews):

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

Loading…
Cancel
Save