Browse Source

added documents app

devel
Dmitry Novikov 7 years ago
parent
commit
93c6702e02
  1. 4
      abonapp/templates/abonapp/editAbon.html
  2. 2
      devapp/locale/ru/LC_MESSAGES/django.po
  3. 2
      devapp/templates/devapp/devices.html
  4. 9
      djing/settings.py
  5. 3
      djing/urls.py
  6. 0
      docsapp/__init__.py
  7. 5
      docsapp/apps.py
  8. 8
      docsapp/forms.py
  9. 71
      docsapp/locale/ru/LC_MESSAGES/django.po
  10. 27
      docsapp/migrations/0001_initial.py
  11. 0
      docsapp/migrations/__init__.py
  12. 24
      docsapp/models.py
  13. 14
      docsapp/templates/docsapp/documenttemplatemodel_confirm_delete.html
  14. 39
      docsapp/templates/docsapp/documenttemplatemodel_form.html
  15. 77
      docsapp/templates/docsapp/documenttemplatemodel_list.html
  16. 26
      docsapp/templates/docsapp/simple_list.html
  17. 14
      docsapp/urls.py
  18. 101
      docsapp/views.py
  19. 2
      requirements.txt
  20. 6
      templates/base.html

4
abonapp/templates/abonapp/editAbon.html

@ -99,6 +99,10 @@
<span>{% trans 'Remove subscriber' %}</span> <span>{% trans 'Remove subscriber' %}</span>
</a> </a>
{% endif %} {% endif %}
<a href="{% url 'docsapp:simple_list' abon.username %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-print"></span> {% trans 'Document list' %}
</a>
</div> </div>
</div> </div>

2
devapp/locale/ru/LC_MESSAGES/django.po

@ -484,7 +484,7 @@ msgid "Are you sure you want to delete device?"
msgstr "Вы уверены что хотите удалить устройство?" msgstr "Вы уверены что хотите удалить устройство?"
#: templates/devapp/devices.html:83 templates/devapp/devices_null_group.html:65 #: templates/devapp/devices.html:83 templates/devapp/devices_null_group.html:65
msgid "Devices does not found"
msgid "Devices not found"
msgstr "Нет созданных устройств" msgstr "Нет созданных устройств"
#: templates/devapp/devices.html:83 templates/devapp/devices.html:93 #: templates/devapp/devices.html:83 templates/devapp/devices.html:93

2
devapp/templates/devapp/devices.html

@ -82,7 +82,7 @@
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>
<td colspan="6">{% trans 'Devices does not found' %}. <a href="{% url 'devapp:add' group.pk %}">{% trans 'Create' %}</a></td>
<td colspan="6">{% trans 'Devices not found' %}. <a href="{% url 'devapp:add' group.pk %}">{% trans 'Create' %}</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
{% endwith %} {% endwith %}

9
djing/settings.py

@ -43,6 +43,10 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'encrypted_model_fields', 'encrypted_model_fields',
'django_cleanup.apps.CleanupConfig', 'django_cleanup.apps.CleanupConfig',
'guardian',
'pinax_theme_bootstrap',
'bootstrapform',
'bootstrap3',
'ip_pool', 'ip_pool',
'accounts_app', 'accounts_app',
'gw_app', 'gw_app',
@ -59,10 +63,7 @@ INSTALLED_APPS = [
'msg_app', 'msg_app',
'group_app', 'group_app',
'new_customers', 'new_customers',
'guardian',
'pinax_theme_bootstrap',
'bootstrapform',
'bootstrap3'
'docsapp'
] ]
if DEBUG: if DEBUG:

3
djing/urls.py

@ -20,7 +20,8 @@ urlpatterns = [
path('messenger/', include('messenger.urls', namespace='messenger')), path('messenger/', include('messenger.urls', namespace='messenger')),
path('gw/', include('gw_app.urls', namespace='gw_app')), path('gw/', include('gw_app.urls', namespace='gw_app')),
path('new_customers/', include('new_customers.urls', namespace='new_customers')), path('new_customers/', include('new_customers.urls', namespace='new_customers')),
path('fin/', include('finapp.urls', namespace='finapp'))
path('fin/', include('finapp.urls', namespace='finapp')),
path('docs/', include('docsapp.urls', namespace='docsapp'))
# Switch language # Switch language
#path(r'i18n/', include('django.conf.urls.i18n')), #path(r'i18n/', include('django.conf.urls.i18n')),

0
docsapp/__init__.py

5
docsapp/apps.py

@ -0,0 +1,5 @@
from django.apps import AppConfig
class DocsappConfig(AppConfig):
name = 'docsapp'

8
docsapp/forms.py

@ -0,0 +1,8 @@
from django import forms
from docsapp.models import DocumentTemplateModel
class DocumentTemplateModelForm(forms.ModelForm):
class Meta:
model = DocumentTemplateModel
fields = '__all__'

71
docsapp/locale/ru/LC_MESSAGES/django.po

@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Dmitry Novikov nerosketch@gmail.com, 2019.
#
#, fuzzy
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-12 13:57+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: models.py:8 templates/docsapp/documenttemplatemodel_list.html:25
msgid "Title"
msgstr "Название"
#: models.py:10
msgid "File docx template"
msgstr "Файл шаблон docx"
#: templates/docsapp/documenttemplatemodel_confirm_delete.html:9
msgid "Remove document"
msgstr "Удалить документ"
#: templates/docsapp/documenttemplatemodel_confirm_delete.html:13
msgid "Are you sure you want to delete this document?"
msgstr "Вы уверены что хотите удалить документ?"
#: templates/docsapp/documenttemplatemodel_form.html:19
msgid "Change document"
msgstr "Изменить документ"
#: templates/docsapp/documenttemplatemodel_form.html:21
#: templates/docsapp/documenttemplatemodel_list.html:58
#: templates/docsapp/documenttemplatemodel_list.html:69
msgid "Add document"
msgstr "Добавить документ"
#: templates/docsapp/documenttemplatemodel_form.html:30
msgid "Save"
msgstr "Сохранить"
#: templates/docsapp/documenttemplatemodel_form.html:34
msgid "Back"
msgstr "Назад"
#: templates/docsapp/documenttemplatemodel_list.html:5
#: templates/docsapp/documenttemplatemodel_list.html:11
#: templates/docsapp/documenttemplatemodel_list.html:16
msgid "Documents"
msgstr "Документы"
#: templates/docsapp/documenttemplatemodel_list.html:26
msgid "File"
msgstr "Файл"
#: templates/docsapp/documenttemplatemodel_list.html:27
msgid "Document type"
msgstr "Тип документа"
#: templates/docsapp/documenttemplatemodel_list.html:57
msgid "Documents not found"
msgstr "Документы не найдены"

27
docsapp/migrations/0001_initial.py

@ -0,0 +1,27 @@
# Generated by Django 2.2.4 on 2019-09-12 12:52
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='DocumentTemplateModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=80, verbose_name='Title', unique=True)),
('doc_template', models.FileField(upload_to='word_docs', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=('docx',))], verbose_name='File docx template')),
],
options={
'db_table': 'documents',
'ordering': ('title',),
},
),
]

0
docsapp/migrations/__init__.py

24
docsapp/models.py

@ -0,0 +1,24 @@
from django.shortcuts import resolve_url
from django.utils.translation import gettext_lazy as _
from django.core.validators import FileExtensionValidator
from django.db import models
from abonapp.models import Abon
class DocumentTemplateModel(models.Model):
title = models.CharField(_('Title'), max_length=80, unique=True)
doc_template = models.FileField(
_('File docx template'), upload_to='word_docs',
validators=[FileExtensionValidator(allowed_extensions=('docx',))]
)
def get_absolute_url(self):
return resolve_url('docsapp:doc_edit', pk=self.pk)
def __str__(self):
return self.title
class Meta:
db_table = 'documents'
ordering = ('title',)

14
docsapp/templates/docsapp/documenttemplatemodel_confirm_delete.html

@ -0,0 +1,14 @@
{% extends 'base_delete_modal.html' %}
{% load i18n %}
{% block modal_form_url %}
{% url 'docsapp:doc_del' object.pk %}
{% endblock %}
{% block modal_form_title %}
{% trans 'Remove document' %}
{% endblock %}
{% block modal_form_text %}
<h4>{% trans 'Are you sure you want to delete this document?' %}</h4>
{% endblock %}

39
docsapp/templates/docsapp/documenttemplatemodel_form.html

@ -0,0 +1,39 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% load i18n bootstrap3 %}
{% block main %}
{% if object %}
{% url 'docsapp:doc_edit' object.pk as objurl %}
{% else %}
{% url 'docsapp:doc_add' as objurl %}
{% endif %}
<form action="{{ objurl }}" method="post" enctype="multipart/form-data">{% csrf_token %}
<div class="modal-header primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
<span class="glyphicon glyphicon-exclamation-sign"></span>
{% if object %}
{% trans 'Change document' %}
{% else %}
{% trans 'Add document' %}
{% endif %}
</h4>
</div>
<div class="modal-body">
{% bootstrap_form form %}
<div class="btn-group btn-group-sm">
{% bootstrap_button _('Save') button_type="submit" button_class="btn-primary" icon="save" %}
{% if not request.is_ajax %}
{% url 'docsapp:docs_list' as backurl %}
{% bootstrap_button _('Back') button_type="link" href=backurl icon="fast-backward" %}
{% endif %}
</div>
</div>
</form>
{% endblock %}

77
docsapp/templates/docsapp/documenttemplatemodel_list.html

@ -0,0 +1,77 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% load i18n %}
{% block title %}
{% trans 'Documents' %}
{% endblock %}
{% block breadcrumb %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li class="active">{% trans 'Documents' %}</li>
</ol>
{% endblock %}
{% block page-header %}
{% trans 'Documents' %}
{% endblock %}
{% block main %}
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>.</th>
<th class="col-md-2">{% trans 'Title' %}</th>
<th class="col-md-4">{% trans 'File' %}</th>
<th class="col-md-3">{% trans 'Document type' %}</th>
<th>#</th>
</tr>
</thead>
<tbody>
{% with can_del_doc=perms.docsapp.delete_documenttemplatemodel can_ch_doc=perms.docsapp.change_documenttemplatemodel %}
{% for doc in object_list %}
<tr>
<td>{{ doc.id }}</td>
<td>{{ doc.title }}</td>
<td>{{ doc.doc_template }}</td>
<td>DocX</td>
<td class="btn-group btn-group-xs btn-group-justified">
{% if can_del_doc %}
<a href="{% url 'docsapp:doc_del' doc.pk %}" class="btn btn-danger btn-modal">
<span class="glyphicon glyphicon-remove"></span>
</a>
{% endif %}
{% if can_ch_doc %}
<a href="{% url 'docsapp:doc_edit' doc.id %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-edit"></span>
</a>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="6">
{% trans 'Documents not found' %}.
<a href="{% url 'docsapp:doc_add' %}" class="btn-modal">{% trans 'Add document' %}</a>
</td>
</tr>
{% endfor %}
{% endwith %}
</tbody>
<tfoot>
<tr>
<td colspan="6">
<a href="{% url 'docsapp:doc_add' %}" class="btn btn-success btn-sm btn-modal">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add document' %}
</a>
</td>
</tr>
</tfoot>
</table>
</div>
{% endblock %}

26
docsapp/templates/docsapp/simple_list.html

@ -0,0 +1,26 @@
{% load i18n %}
<div class="modal-header primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">{% trans 'Documents' %}</h4>
</div>
<div class="modal-body">
<div class="panel panel-default">
<div class="panel-body">
<ul class="list-group">
{% for obj in object_list %}
<li class="list-group-item">
<b>{{ obj.title }}</b>
<a href="{% url 'docsapp:doc_render' obj.pk account_name %}" class="btn btn-default">
<span class="glyphicon glyphicon-print"></span> {% trans 'Render document' %}
</a>
</li>
{% empty %}
{% trans 'Documents not found' %}
{% endfor %}
</ul>
</div>
</div>
</div>

14
docsapp/urls.py

@ -0,0 +1,14 @@
from django.urls import path
from docsapp import views
app_name = 'docsapp'
urlpatterns = [
path('', views.DocumentsListView.as_view(), name='docs_list'),
path('add/', views.DocumentCreateView.as_view(), name='doc_add'),
path('<int:pk>/', views.DocumentUpdateView.as_view(), name='doc_edit'),
path('<int:pk>/del/', views.DocumentDeleteView.as_view(), name='doc_del'),
path('<int:pk>/<slug:uname>/render/', views.RenderDocument.as_view(), name='doc_render'),
path('<slug:account_name>/simple_list/', views.SimpleListView.as_view(), name='simple_list'),
]

101
docsapp/views.py

@ -0,0 +1,101 @@
from io import BytesIO
from django.contrib import messages
from django.utils.datetime_safe import datetime
from django.utils.translation import gettext_lazy as _
from django.views.generic import UpdateView, DeleteView, CreateView, DetailView, ListView
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ValidationError
from django.http import HttpResponse
from django.shortcuts import redirect, get_object_or_404
from django.urls import reverse_lazy
from docxtpl import DocxTemplate
from docx.opc.constants import CONTENT_TYPE
from jinja2.exceptions import UndefinedError, TemplateSyntaxError
from abonapp.models import Abon
from djing.global_base_views import OrderedFilteredList
from djing.lib.mixins import LoginAdminMixin, LoginAdminPermissionMixin
from docsapp.models import DocumentTemplateModel
from docsapp.forms import DocumentTemplateModelForm
class DocumentsListView(LoginAdminMixin, OrderedFilteredList):
model = DocumentTemplateModel
class SimpleListView(LoginAdminMixin, ListView):
template_name = 'docsapp/simple_list.html'
model = DocumentTemplateModel
def get_context_data(self, **kwargs):
kwargs.update({
'account_name': self.kwargs.get('account_name')
})
return super().get_context_data(**kwargs)
class DocumentUpdateView(LoginAdminPermissionMixin, UpdateView):
permission_required = 'docsapp.change_documenttemplatemodel'
model = DocumentTemplateModel
form_class = DocumentTemplateModelForm
class DocumentDeleteView(LoginAdminPermissionMixin, DeleteView):
permission_required = 'docsapp.delete_documenttemplatemodel'
model = DocumentTemplateModel
success_url = reverse_lazy('docsapp:docs_list')
class DocumentCreateView(LoginAdminMixin, PermissionRequiredMixin, CreateView):
model = DocumentTemplateModel
form_class = DocumentTemplateModelForm
permission_required = 'docsapp.add_documenttemplatemodel'
class RenderDocument(LoginAdminPermissionMixin, DetailView):
model = DocumentTemplateModel
permission_required = 'docsapp.view_documenttemplatemodel'
context_object_name = 'document'
extra_context = {
'date': datetime.now()
}
def get(self, request, *args, **kwargs):
obj = self.get_object()
self.object = obj
acc = get_object_or_404(Abon, username=self.kwargs.get('uname'))
try:
doc = DocxTemplate(
obj.doc_template.path
)
context = self.get_context_data(object=obj)
context.update(self.get_context_account(acc))
doc.render(context)
destination_document_file = BytesIO()
doc.get_docx().save(destination_document_file)
resp = HttpResponse(
destination_document_file.getvalue(),
content_type=CONTENT_TYPE.WML_DOCUMENT
)
resp['Content-Disposition'] = 'attachment; filename="document.docx"'
return resp
except (UndefinedError, ValidationError, TemplateSyntaxError) as e:
messages.error(request, str(e))
return redirect('docsapp:docs_list')
def get_context_account(self, account):
if not isinstance(account, Abon):
raise ValidationError(message=_('Account required and must be Abon'))
bp = '_' * 20
return {
'account': account,
'passport': getattr(account, 'passportinfo', {
'series': bp,
'number': bp,
'distributor': bp,
'date_of_acceptance': bp
})
}

2
requirements.txt

@ -45,3 +45,5 @@ django-encrypted-model-fields
Celery Celery
redis redis
celery[redis] celery[redis]
docxtpl

6
templates/base.html

@ -129,6 +129,12 @@
</a> </a>
</li> </li>
{% url 'docsapp:docs_list' as docslist %}
<li{% if docslist in request.path %} class="active"{% endif %}>
<a href="{{ docslist }}">
<span class="glyphicon glyphicon-book"></span> {% trans 'Documents' %}
</a>
</li>
</ul> </ul>
</div> </div>

Loading…
Cancel
Save