optimizations

remotes/origin/PR-39
PekopT 9 years ago
parent da3793495d
commit 669d1d5db0
  1. 1
      api/test.py
  2. 1
      api/urls.py
  3. 64
      api/views.py
  4. 10
      archilance/management/commands/generate_build_classifs.py
  5. 10
      archilance/management/commands/generate_constr_types.py
  6. 17
      archilance/management/commands/generate_locations.py
  7. 11
      archilance/management/commands/generate_perm_groups.py
  8. 18
      archilance/management/commands/generate_portfolios.py
  9. 10
      archilance/management/commands/generate_projects.py
  10. 14
      archilance/management/commands/generate_realties.py
  11. 14
      archilance/management/commands/generate_reviews.py
  12. 16
      archilance/management/commands/generate_specializations.py
  13. 10
      archilance/management/commands/generate_superuser.py
  14. 15
      archilance/management/commands/generate_teams.py
  15. 19
      archilance/management/commands/generate_users.py
  16. 15
      archilance/management/commands/generate_work_sells.py
  17. 16
      archilance/middlewares.py
  18. 1
      archilance/mixins.py
  19. 8
      archilance/settings/base.py
  20. 10
      archilance/urls.py
  21. 22
      archilance/util.py
  22. 26
      archilance/views.py
  23. 6
      archilance/wsgi.py
  24. 21
      assets/css/main.css
  25. BIN
      assets/img/skype.png
  26. BIN
      assets/img/user-4.png
  27. BIN
      assets/img/user-5.png
  28. 8
      assets/index.js
  29. 5
      chat/admin.py
  30. 25
      chat/chat.py
  31. 5
      chat/filters.py
  32. 1
      chat/forms.py
  33. 2
      chat/models.py
  34. 1
      chat/response.py
  35. 10
      chat/serializers.py
  36. 3
      chat/settings.example.py
  37. 2
      chat/tests.py
  38. 1
      chat/utils.py
  39. 46
      chat/views.py
  40. 5
      common/admin.py
  41. 6
      common/forms.py
  42. 7
      common/middleware.py
  43. 2
      common/models.py
  44. 2
      common/tests.py
  45. 3
      common/urls.py
  46. 14
      common/views.py
  47. 4
      projects/admin.py
  48. 3
      projects/apps.py
  49. 1
      projects/filters.py
  50. 23
      projects/forms.py
  51. BIN
      projects/locale/ru_RU/LC_MESSAGES/django.mo
  52. 48
      projects/locale/ru_RU/LC_MESSAGES/django.po
  53. 38
      projects/migrations/0047_auto_20161014_2349.py
  54. 31
      projects/models.py
  55. 13
      projects/serializers.py
  56. 4
      projects/signals.py
  57. 30
      projects/templates/_trash/project_form.html
  58. 2
      projects/templates/_trash/testport.html
  59. 4
      projects/templates/chattest.html
  60. 10
      projects/templates/comparison.html
  61. 43
      projects/templates/contractor_portfolio_edit.html
  62. 154
      projects/templates/customer_project_create.html
  63. 105
      projects/templates/customer_project_edit.html
  64. 3
      projects/templates/partials/modals/project_work_type_suggestion.html
  65. 1
      projects/templates/portfolio_create.html
  66. 211
      projects/templates/project_detail.html
  67. 41
      projects/templates/project_filter.html
  68. 16
      projects/templatetags/project_tags.py
  69. 2
      projects/tests.py
  70. 16
      projects/urls.py
  71. 35
      projects/views.py
  72. 1
      ratings/admin.py
  73. 6
      ratings/models.py
  74. 2
      ratings/tests.py
  75. 2
      ratings/views.py
  76. 1
      reviews/admin.py
  77. 2
      reviews/apps.py
  78. 3
      reviews/forms.py
  79. 2
      reviews/models.py
  80. 4
      reviews/serializers.py
  81. 2
      reviews/signals.py
  82. 2
      reviews/tests.py
  83. 6
      reviews/views.py
  84. 8
      specializations/admin.py
  85. 2
      specializations/filters.py
  86. 21
      specializations/migrations/0003_specialization_order.py
  87. 24
      specializations/migrations/0004_auto_20161014_2344.py
  88. 8
      specializations/models.py
  89. 2
      specializations/tests.py
  90. 1
      specializations/urls.py
  91. 13
      specializations/views.py
  92. 4
      users/admin.py
  93. 2
      users/apps.py
  94. 2
      users/backend.py
  95. 5
      users/filters.py
  96. 17
      users/forms.py
  97. 12
      users/helpers.py
  98. BIN
      users/locale/ru_RU/LC_MESSAGES/django.mo
  99. 42
      users/locale/ru_RU/LC_MESSAGES/django.po
  100. 1
      users/mixins.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -3,4 +3,3 @@ from rest_framework.test import APITestCase
class FileUploadTests(APITestCase): class FileUploadTests(APITestCase):
pass pass

@ -22,7 +22,6 @@ from .views import (
WorkSellViewSet, WorkSellViewSet,
) )
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register(r'answers', AnswerViewSet) router.register(r'answers', AnswerViewSet)

@ -4,41 +4,33 @@ from rest_framework import permissions
from rest_framework.pagination import PageNumberPagination from rest_framework.pagination import PageNumberPagination
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from projects.models import Project, Realty, Stage, Portfolio, PortfolioPhoto, Answer, AnswerFile, Order from chat.filters import MessageFilterSet, NoteFilterSet, DocumentFilterSet
from chat.models import Message, Notes, Documents, NewMessage
from projects.serializers import ( from chat.serializers import MessageSerializer, NoteSerializer, DocumentsSerializer
ProjectSerializer, RealtySerializer, StageSerializer, PortfolioSerializer, from common.filters import LocationFilterSet
PortfolioPhotoSerializer, AnswerSerializer, OrderSerializer, AnswerFileSerializer, from common.models import Location
) from common.serializers import LocationSerializer
from projects.filters import ( from projects.filters import (
ProjectFilterSet, RealtyFilterSet, StageFilterSet, PortfolioFilterSet, OrderFilterSet, ProjectFilterSet, RealtyFilterSet, StageFilterSet, PortfolioFilterSet, OrderFilterSet,
PortfolioPhotoFilterSet, AnswerFilterSet, PortfolioPhotoFilterSet, AnswerFilterSet,
) )
from projects.models import Project, Realty, Stage, Portfolio, PortfolioPhoto, Answer, Order
from projects.serializers import (
ProjectSerializer, RealtySerializer, StageSerializer, PortfolioSerializer,
PortfolioPhotoSerializer, AnswerSerializer, OrderSerializer, )
from reviews.filters import ReviewFilterSet
from reviews.models import Review
from reviews.serializers import ReviewSerializer
from specializations.filters import SpecializationFilterSet
from specializations.models import Specialization from specializations.models import Specialization
from specializations.serializers import SpecializationSerializer from specializations.serializers import SpecializationSerializer
from specializations.filters import SpecializationFilterSet from users.filters import UserFilterSet, TeamFilterSet
from users.models import User, ContractorResumeFiles, ContractorResume, Team from users.models import User, ContractorResumeFiles, ContractorResume, Team
from users.serializers import UserSerializer, ContractorResumeFilesSerializer, ContractorResumeSerializer, TeamSerializer from users.serializers import UserSerializer, ContractorResumeFilesSerializer, ContractorResumeSerializer, \
from users.filters import UserFilterSet, TeamFilterSet, ContractorResumeFilesFilterSet, ContractorResumeFilterSet TeamSerializer
from work_sell.filters import WorkSellFilterSet, WorkSellPhotoFilterSet
from common.models import Location
from common.serializers import LocationSerializer
from common.filters import LocationFilterSet
from chat.models import Message, Notes, Documents, NewMessage
from chat.serializers import MessageSerializer, NoteSerializer, DocumentsSerializer
from chat.filters import MessageFilterSet, NoteFilterSet, DocumentFilterSet
from reviews.models import Review
from reviews.serializers import ReviewSerializer
from reviews.filters import ReviewFilterSet
from work_sell.models import WorkSell, WorkSellPhoto from work_sell.models import WorkSell, WorkSellPhoto
from work_sell.serializers import WorkSellSerializer, WorkSellPhotoSerializer from work_sell.serializers import WorkSellSerializer, WorkSellPhotoSerializer
from work_sell.filters import WorkSellFilterSet, WorkSellPhotoFilterSet
class ContractorResumeFilesViewSet(ModelViewSet): class ContractorResumeFilesViewSet(ModelViewSet):
@ -83,7 +75,9 @@ class DocumentViewSet(ModelViewSet):
if search_param: if search_param:
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))
if search_param == 'in': if search_param == 'in':
queryset = queryset.filter(Q(sender__in=[sender_id, recipent_id]),Q(recipent__in=[sender_id, recipent_id])).filter(order__isnull=True).order_by('created') queryset = queryset.filter(Q(sender__in=[sender_id, recipent_id]),
Q(recipent__in=[sender_id, recipent_id])).filter(
order__isnull=True).order_by('created')
return queryset return queryset
@ -91,6 +85,7 @@ class ProjectViewSet(ModelViewSet):
queryset = Project.objects.all() queryset = Project.objects.all()
serializer_class = ProjectSerializer serializer_class = ProjectSerializer
filter_class = ProjectFilterSet filter_class = ProjectFilterSet
# permission_classes = (permissions.IsAuthenticatedOrReadOnly,) # permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self): def get_queryset(self):
@ -118,7 +113,8 @@ class NoteViewSet(ModelViewSet):
if search_param: if search_param:
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))
if search_param == 'in': if search_param == 'in':
queryset = queryset.filter(Q(sender__in=[sender_id,recipent_id]),Q(recipent__in=[sender_id,recipent_id])).order_by('created') queryset = queryset.filter(Q(sender__in=[sender_id, recipent_id]),
Q(recipent__in=[sender_id, recipent_id])).order_by('created')
return queryset return queryset
@ -135,11 +131,11 @@ class MessageViewSet(ModelViewSet):
if search_param: if search_param:
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))
if search_param == 'in': if search_param == 'in':
queryset = queryset.filter(Q(sender__in=[sender_id,recipent_id]),Q(recipent__in=[sender_id,recipent_id])).\ queryset = queryset.filter(Q(sender__in=[sender_id, recipent_id]),
filter(order__isnull=True).\ Q(recipent__in=[sender_id, recipent_id])). \
filter(order__isnull=True). \
filter(~Q(sender=F('recipent'))) filter(~Q(sender=F('recipent')))
queryset = queryset.order_by('created') queryset = queryset.order_by('created')
return queryset return queryset
@ -205,13 +201,12 @@ class PortfolioPhotoViewSet(ModelViewSet):
filter_class = PortfolioPhotoFilterSet filter_class = PortfolioPhotoFilterSet
class WorkSellPagination(PageNumberPagination): class WorkSellPagination(PageNumberPagination):
page_size = settings.API_PAGE_SIZE # Default page size page_size = settings.API_PAGE_SIZE # Default page size
page_size_query_param = 'page_size' # Provide custom page size through a query param page_size_query_param = 'page_size' # Provide custom page size through a query param
max_page_size = 1000 max_page_size = 1000
class WorkSellViewSet(ModelViewSet): class WorkSellViewSet(ModelViewSet):
queryset = WorkSell.objects.all() queryset = WorkSell.objects.all()
serializer_class = WorkSellSerializer serializer_class = WorkSellSerializer
@ -219,15 +214,12 @@ class WorkSellViewSet(ModelViewSet):
pagination_class = WorkSellPagination pagination_class = WorkSellPagination
class WorkSellPhotoViewSet(ModelViewSet): class WorkSellPhotoViewSet(ModelViewSet):
queryset = WorkSellPhoto.objects.all() queryset = WorkSellPhoto.objects.all()
serializer_class = WorkSellPhotoSerializer serializer_class = WorkSellPhotoSerializer
filter_class = WorkSellPhotoFilterSet filter_class = WorkSellPhotoFilterSet
class AnswerViewSet(ModelViewSet): class AnswerViewSet(ModelViewSet):
queryset = Answer.objects.all() queryset = Answer.objects.all()
serializer_class = AnswerSerializer serializer_class = AnswerSerializer

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
from archilance import util _.map = _.map_;
_.filter = _.filter_
from projects.models import BuildingClassfication from projects.models import BuildingClassfication

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
from archilance import util _.map = _.map_;
_.filter = _.filter_
from projects.models import ConstructionType from projects.models import ConstructionType

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
from archilance import util _.map = _.map_;
_.filter = _.filter_
from common.models import Location from common.models import Location
@ -15,14 +13,13 @@ class Command(BaseCommand):
print('Generating locations...') print('Generating locations...')
print('---------------------------------------') print('---------------------------------------')
_root = Location.objects.create(name='_root', type='_root') _root = Location.objects.create(name='_root', type='_root')
depths = ('A','B','C','D') depths = ('A', 'B', 'C', 'D')
for d1 in depths: for d1 in depths:
x = Location.objects.create(name='Страна %s' % d1, type='country', parent=_root) x = Location.objects.create(name='Страна %s' % d1, type='country', parent=_root)
for d2 in depths: for d2 in depths:
y = Location.objects.create(name='Регион %s-%s' % (d1,d2), type='region', parent=x) y = Location.objects.create(name='Регион %s-%s' % (d1, d2), type='region', parent=x)
for d3 in depths: for d3 in depths:
z = Location.objects.create(name='Город %s-%s-%s' % (d1,d2,d3), type='town', parent=y) z = Location.objects.create(name='Город %s-%s-%s' % (d1, d2, d3), type='town', parent=y)

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import Group
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
from archilance import util _.map = _.map_;
_.filter = _.filter_
class Command(BaseCommand): class Command(BaseCommand):
@ -14,6 +12,5 @@ class Command(BaseCommand):
print('Generating permission groups...') print('Generating permission groups...')
print('---------------------------------------') print('---------------------------------------')
Group.objects.create(name='Исполнители') Group.objects.create(name='Исполнители')
Group.objects.create(name='Заказчики') Group.objects.create(name='Заказчики')

@ -1,15 +1,14 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_ _.map = _.map_;
import random _.filter = _.filter_
from archilance import util from archilance import util
from common.models import Location from common.models import Location
from projects.models import Portfolio, PortfolioPhoto, CURRENCIES, TERM_TYPES, BuildingClassfication , ConstructionType from projects.models import Portfolio, CURRENCIES, TERM_TYPES, BuildingClassfication, ConstructionType
from specializations.models import Specialization from specializations.models import Specialization
from users.models import User, Team, GENDERS from users.models import User
class Command(BaseCommand): class Command(BaseCommand):
@ -18,7 +17,6 @@ class Command(BaseCommand):
print('Generating portfolios...') print('Generating portfolios...')
print('---------------------------------------') print('---------------------------------------')
# ('photos', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), # ('photos', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'),
# ('budget', 'Relation? False', 'Null? True', 'Blank? True', 'Hidden? False'), # ('budget', 'Relation? False', 'Null? True', 'Blank? True', 'Hidden? False'),
# ('building_classification', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), # ('building_classification', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'),
@ -56,7 +54,9 @@ class Command(BaseCommand):
portf.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() portf.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first()
portf.specialization = Specialization.objects.root_nodes()[0].get_descendants().order_by('?').first() portf.specialization = Specialization.objects.root_nodes()[0].get_descendants().order_by('?').first()
pic_names = _.split('a.png b.png c.jpg d.png e.jpg f.png g.png h.jpg i.png j.png k.jpg l.png m.png n.png o.png p.png q.jpg', ' ') pic_names = _.split(
'a.png b.png c.jpg d.png e.jpg f.png g.png h.jpg i.png j.png k.jpg l.png m.png n.png o.png p.png q.jpg',
' ')
_.times( _.times(
lambda i_: portf.photos.create(img='_sample_files/%s' % util.take_one_random(pic_names)), lambda i_: portf.photos.create(img='_sample_files/%s' % util.take_one_random(pic_names)),

@ -1,9 +1,8 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_ _.map = _.map_;
import random _.filter = _.filter_
from archilance import util from archilance import util
from projects.models import Project, Order, CURRENCIES, TERM_TYPES, Specialization, Realty from projects.models import Project, Order, CURRENCIES, TERM_TYPES, Specialization, Realty
@ -16,7 +15,6 @@ class Command(BaseCommand):
print('Generating projects...') print('Generating projects...')
print('---------------------------------------') print('---------------------------------------')
# Fields: # Fields:

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
from archilance import util _.map = _.map_;
_.filter = _.filter_
from common.models import Location from common.models import Location
from projects.models import Realty, BuildingClassfication, ConstructionType from projects.models import Realty, BuildingClassfication, ConstructionType
from users.models import User from users.models import User
@ -17,7 +15,6 @@ class Command(BaseCommand):
print('Generating realties...') print('Generating realties...')
print('---------------------------------------') print('---------------------------------------')
# # Fields: # # Fields:
# #
# #
@ -39,7 +36,8 @@ class Command(BaseCommand):
realty.building_classification = BuildingClassfication.objects.order_by('?').first() realty.building_classification = BuildingClassfication.objects.order_by('?').first()
realty.construction_type = ConstructionType.objects.order_by('?').first() realty.construction_type = ConstructionType.objects.order_by('?').first()
realty.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() realty.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first()
realty.user = User.objects.filter(groups__name='Заказчики', is_active=True, is_superuser=False).order_by('?').first() realty.user = User.objects.filter(groups__name='Заказчики', is_active=True, is_superuser=False).order_by(
'?').first()
realty.save() realty.save()
return realty return realty

@ -1,14 +1,12 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_ _.map = _.map_;
import random _.filter = _.filter_
from archilance import util from archilance import util
from projects.models import Project, Portfolio from projects.models import Project
from specializations.models import Specialization from users.models import User
from users.models import User, GENDERS, Team
from reviews.models import Review from reviews.models import Review

@ -1,8 +1,9 @@
import pydash as _;
from django.core.management import BaseCommand from django.core.management import BaseCommand
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
from archilance import util _.map = _.map_;
_.filter = _.filter_
from specializations.models import Specialization from specializations.models import Specialization
@ -12,16 +13,15 @@ class Command(BaseCommand):
print('Generating specializations...') print('Generating specializations...')
print('---------------------------------------') print('---------------------------------------')
_root = Specialization.objects.create(name='_root') _root = Specialization.objects.create(name='_root')
stages = ('A','B','C','D') stages = ('A', 'B', 'C', 'D')
for s1 in stages: for s1 in stages:
x = Specialization.objects.create(name='Специализация %s' % s1, parent=_root) x = Specialization.objects.create(name='Специализация %s' % s1, parent=_root)
for s2 in stages: for s2 in stages:
y = Specialization.objects.create(name='Специализация %s-%s' % (s1,s2), parent=x) y = Specialization.objects.create(name='Специализация %s-%s' % (s1, s2), parent=x)
for s3 in stages: for s3 in stages:
z = Specialization.objects.create(name='Специализация %s-%s-%s' % (s1,s2,s3), parent=y) z = Specialization.objects.create(name='Специализация %s-%s-%s' % (s1, s2, s3), parent=y)
for s4 in stages: for s4 in stages:
Specialization.objects.create(name='Специализация %s-%s-%s-%s' % (s1,s2,s3,s4), parent=z) Specialization.objects.create(name='Специализация %s-%s-%s-%s' % (s1, s2, s3, s4), parent=z)

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
from archilance import util _.map = _.map_;
_.filter = _.filter_
from users.models import User from users.models import User

@ -1,14 +1,13 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_ _.map = _.map_;
import random _.filter = _.filter_
from archilance import util from archilance import util
from projects.models import Portfolio from projects.models import Portfolio
from specializations.models import Specialization from specializations.models import Specialization
from users.models import User, GENDERS, Team from users.models import User, Team
class Command(BaseCommand): class Command(BaseCommand):
@ -17,7 +16,6 @@ class Command(BaseCommand):
print('Generating teams...') print('Generating teams...')
print('---------------------------------------') print('---------------------------------------')
# ('name', 'Relation? False', 'Null? False', 'Blank? False', 'Hidden? False'), # ('name', 'Relation? False', 'Null? False', 'Blank? False', 'Hidden? False'),
# ('portfolios', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'), # ('portfolios', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'),
@ -39,7 +37,8 @@ class Command(BaseCommand):
team.owner = owner team.owner = owner
team.contractors = _.sample(members, _.random(1, 5)) team.contractors = _.sample(members, _.random(1, 5))
team.specializations = Specialization.objects.root_nodes()[0].get_descendants().order_by('?')[:_.random(1, 5)] team.specializations = Specialization.objects.root_nodes()[0].get_descendants().order_by('?')[
:_.random(1, 5)]
team.portfolios = Portfolio.objects.order_by('?')[:_.random(1, 10)] team.portfolios = Portfolio.objects.order_by('?')[:_.random(1, 10)]
team.save() team.save()

@ -1,14 +1,13 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import Group
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
from archilance import util _.map = _.map_;
_.filter = _.filter_
from common.models import Location from common.models import Location
from specializations.models import Specialization from specializations.models import Specialization
from users.models import User, GENDERS from users.models import User
class Command(BaseCommand): class Command(BaseCommand):
@ -17,8 +16,6 @@ class Command(BaseCommand):
print('Generating users...') print('Generating users...')
print('---------------------------------------') print('---------------------------------------')
# # Fields: # # Fields:
# #
# ('contractor_specializations', 'Relation? True', 'Null? False', '(relation)', 'Hidden? False'), # ('contractor_specializations', 'Relation? True', 'Null? False', '(relation)', 'Hidden? False'),
@ -91,14 +88,14 @@ class Command(BaseCommand):
users = _.times(create_user, 500) users = _.times(create_user, 500)
contractor_group = Group.objects.get(name='Исполнители') contractor_group = Group.objects.get(name='Исполнители')
customer_group = Group.objects.get(name='Заказчики') customer_group = Group.objects.get(name='Заказчики')
for user in users: for user in users:
user.set_password('123') user.set_password('123')
user.groups.add(customer_group if user.pk % 2 == 0 else contractor_group) user.groups.add(customer_group if user.pk % 2 == 0 else contractor_group)
user.contractor_specializations = Specialization.objects.root_nodes()[0].get_descendants().order_by('?')[:_.random(1, 5)] user.contractor_specializations = Specialization.objects.root_nodes()[0].get_descendants().order_by('?')[
:_.random(1, 5)]
user.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() user.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first()
user.save() user.save()

@ -1,16 +1,15 @@
from django.contrib.auth.models import Group, Permission import pydash as _;
from django.contrib.contenttypes.models import ContentType
from django.core.management import BaseCommand from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_ _.map = _.map_;
import random _.filter = _.filter_
from archilance import util from archilance import util
from common.models import Location from common.models import Location
from projects.models import TERM_TYPES, CURRENCIES, BuildingClassfication, ConstructionType from projects.models import TERM_TYPES, CURRENCIES, BuildingClassfication, ConstructionType
from specializations.models import Specialization from specializations.models import Specialization
from users.models import User, Team from users.models import User, Team
from work_sell.models import WorkSell, WorkSellPhoto from work_sell.models import WorkSell
class Command(BaseCommand): class Command(BaseCommand):
@ -42,7 +41,9 @@ class Command(BaseCommand):
ws.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() ws.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first()
ws.specialization = Specialization.objects.root_nodes()[0].get_descendants().order_by('?').first() ws.specialization = Specialization.objects.root_nodes()[0].get_descendants().order_by('?').first()
pic_names = _.split('a.png b.png c.jpg d.png e.jpg f.png g.png h.jpg i.png j.png k.jpg l.png m.png n.png o.png p.png q.jpg', ' ') pic_names = _.split(
'a.png b.png c.jpg d.png e.jpg f.png g.png h.jpg i.png j.png k.jpg l.png m.png n.png o.png p.png q.jpg',
' ')
_.times( _.times(
lambda i_: ws.photos.create(img='_sample_files/%s' % util.take_one_random(pic_names)), lambda i_: ws.photos.create(img='_sample_files/%s' % util.take_one_random(pic_names)),

@ -0,0 +1,16 @@
from django.utils import translation
class LocaleMiddleware(object):
"""
This is a very simple middleware that parses a request
and decides what translation object to install in the current
thread context. This allows pages to be dynamically
translated to the language the user desires (if the language
is available, of course).
"""
def process_request(self, request):
user_language = 'ru_RU'
translation.activate(user_language)
request.session[translation.LANGUAGE_SESSION_KEY] = user_language

@ -22,5 +22,4 @@ class BaseMixin(ContextMixin):
return c return c
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))

@ -83,6 +83,7 @@ INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS + WAGTAIL
MIDDLEWARE_CLASSES = [ MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'archilance.middlewares.LocaleMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
@ -102,7 +103,6 @@ TEMPLATES = [
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(ROOT_DIR, 'templates')], 'DIRS': [os.path.join(ROOT_DIR, 'templates')],
'APP_DIRS': True, 'APP_DIRS': True,
'OPTIONS': { 'OPTIONS': {
'context_processors': [ 'context_processors': [
'django.template.context_processors.debug', 'django.template.context_processors.debug',
@ -237,7 +237,7 @@ FIELDS_STORED_IN_SESSION = ['user_type']
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/ # https://docs.djangoproject.com/en/1.9/topics/i18n/
LANGUAGE_CODE = 'ru-ru' LANGUAGE_CODE = 'ru_RU'
TIME_ZONE = 'Europe/Moscow' TIME_ZONE = 'Europe/Moscow'
@ -247,6 +247,10 @@ USE_L10N = True
USE_TZ = True USE_TZ = True
LANGUAGES = (
('ru_RU', 'Russian'),
)
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/ # https://docs.djangoproject.com/en/1.9/howto/static-files/

@ -4,14 +4,12 @@ from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.generic import TemplateView from django.views.generic import TemplateView
from .views import HomeTemplateView, TestChatTemplateView, TestView
from common.views import CustomRegistrationView
from wallets.views import TmpCheckOrderView, TmpPaymentAvisoView
from wagtail.wagtailadmin import urls as wagtailadmin_urls from wagtail.wagtailadmin import urls as wagtailadmin_urls
from wagtail.wagtailcore import urls as wagtail_urls from wagtail.wagtailcore import urls as wagtail_urls
from common.views import CustomRegistrationView
from wallets.views import TmpCheckOrderView, TmpPaymentAvisoView
from .views import HomeTemplateView, TestChatTemplateView, TestView
urlpatterns = [ urlpatterns = [
url(r'^$', HomeTemplateView.as_view()), url(r'^$', HomeTemplateView.as_view()),
@ -49,7 +47,7 @@ urlpatterns = [
'message': 'Произошла ошибка при оплате', 'message': 'Произошла ошибка при оплате',
}, name='tmp-payment-fail'), }, name='tmp-payment-fail'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if settings.DEBUG: if settings.DEBUG:
urlpatterns += staticfiles_urlpatterns() urlpatterns += staticfiles_urlpatterns()

@ -1,12 +1,16 @@
import datetime
from pprint import pprint
import natsort
import pydash as _;
from django.core import validators from django.core import validators
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.files.storage import FileSystemStorage from django.core.files.storage import FileSystemStorage
from django.shortcuts import _get_queryset from django.shortcuts import _get_queryset
from django.utils import timezone from django.utils import timezone
from pprint import pprint, pformat
import datetime _.map = _.map_;
import natsort _.filter = _.filter_
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random import random
import string import string
@ -33,7 +37,7 @@ def take_one_random(coll):
if len(coll) == 0: if len(coll) == 0:
return None return None
return coll.pop(_.random(0, len(coll)-1)) return coll.pop(_.random(0, len(coll) - 1))
def random_phone(): def random_phone():
@ -102,7 +106,8 @@ def lorem(words=None, sentences=5):
'vitae viverra volutpat vulputate' 'vitae viverra volutpat vulputate'
), ' ') ), ' ')
return _.join(_.times(lambda i_: _.capitalize(_.join(_.sample(vocab, words or _.random(5, 30)), ' ')), sentences), '. ') return _.join(_.times(lambda i_: _.capitalize(_.join(_.sample(vocab, words or _.random(5, 30)), ' ')), sentences),
'. ')
def decap(s): def decap(s):
@ -115,7 +120,7 @@ def decap(s):
def random_ident(length=8): def random_ident(length=8):
return ''.join( return ''.join(
[random.choice(string.ascii_lowercase)] + [random.choice(string.ascii_lowercase)] +
_.times(lambda x_: random.choice(string.ascii_letters + string.digits), length-1) _.times(lambda x_: random.choice(string.ascii_letters + string.digits), length - 1)
) )
@ -153,6 +158,7 @@ def morph(number, words):
return words[choice] return words[choice]
# # Example: # # Example:
# #
# words = ['яблоко', 'яблока', 'яблок'] # words = ['яблоко', 'яблока', 'яблок']
@ -166,6 +172,6 @@ class ASCIIFileSystemStorage(FileSystemStorage):
symbols = (u"абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ", symbols = (u"абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ",
u"abvgdeejzijklmnoprstufhzcss_y_euaABVGDEEJZIJKLMNOPRSTUFHZCSS_Y_EUA") u"abvgdeejzijklmnoprstufhzcss_y_euaABVGDEEJZIJKLMNOPRSTUFHZCSS_Y_EUA")
tr = {ord(a):ord(b) for a, b in zip(*symbols)} tr = {ord(a): ord(b) for a, b in zip(*symbols)}
name = name.translate(tr) name = name.translate(tr)
return super().get_valid_name(name) return super().get_valid_name(name)

@ -1,22 +1,15 @@
from django.conf import settings import pydash as _;
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.core.urlresolvers import reverse, reverse_lazy from django.shortcuts import render
from django.http import HttpResponseForbidden, JsonResponse, HttpResponseRedirect, HttpResponse, Http404 from django.views.generic import View
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import TemplateView, View _.map = _.map_;
from pprint import pprint, pformat _.filter = _.filter_
import json
import logging
import pydash as _; _.map = _.map_; _.filter = _.filter_
from .mixins import BaseMixin from .mixins import BaseMixin
from archilance import util
from chat.models import Documents from chat.models import Documents
from common.models import MainPage, PrintDocuments from common.models import MainPage
from projects.models import Order from users.models import User
from users.models import User, ContractorResumeFiles
from work_sell.models import Picture from work_sell.models import Picture
@ -36,7 +29,7 @@ class TestChatTemplateView(View):
template_name = 'chat_test.html' template_name = 'chat_test.html'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
test = [54,55,56] test = [54, 55, 56]
for pk in test: for pk in test:
picture = Picture.objects.get(pk=pk) picture = Picture.objects.get(pk=pk)
temp_file = ContentFile(picture.file.read()) temp_file = ContentFile(picture.file.read())
@ -61,5 +54,4 @@ class TestView(BaseMixin, View):
return render(request, self.template_name, context) return render(request, self.template_name, context)
# return redirect('projects:detail', pk=153) # return redirect('projects:detail', pk=153)
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))

@ -7,21 +7,23 @@ For more information on this file, see
https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/
""" """
import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
from django.template.base import Variable from django.template.base import Variable
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archilance.settings.local") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archilance.settings.local")
application = get_wsgi_application() application = get_wsgi_application()
# Patch template Variable to output empty string for None values: # Patch template Variable to output empty string for None values:
old_resolve_lookup = Variable._resolve_lookup old_resolve_lookup = Variable._resolve_lookup
def new_resolve_lookup(self, *args, **kwargs): def new_resolve_lookup(self, *args, **kwargs):
val = old_resolve_lookup(self, *args, **kwargs) val = old_resolve_lookup(self, *args, **kwargs)
return '' if val == None else val return '' if val == None else val
Variable._resolve_lookup = new_resolve_lookup Variable._resolve_lookup = new_resolve_lookup

@ -1073,7 +1073,7 @@ footer:after {
} }
.pagin nav ul li a { .pagin nav ul li a {
background-color: none; background-color: transparent;
color: black; color: black;
font-size: 20px; font-size: 20px;
line-height: 50px; line-height: 50px;
@ -1099,7 +1099,6 @@ footer:after {
.pagin nav ul li a:hover, .pagin nav ul li a:hover,
.pagin nav ul li a:active { .pagin nav ul li a:active {
color: black;
color: white; color: white;
background-color: #2c2c2c; background-color: #2c2c2c;
border-color: #2c2c2c; border-color: #2c2c2c;
@ -2560,7 +2559,7 @@ input[type="checkbox"]:checked + span {
text-align: center; text-align: center;
margin: 0 0 0 0; margin: 0 0 0 0;
position: relative; position: relative;
letter-spacing: 0px; letter-spacing: 0;
} }
.compareBlock p:before { .compareBlock p:before {
@ -2986,9 +2985,8 @@ input[type="checkbox"]:checked + span {
.compTable tr td:nth-child(6) ul li:nth-child(2):before { .compTable tr td:nth-child(6) ul li:nth-child(2):before {
height: 20px; height: 20px;
background: url('../img/listTable.png') no-repeat center;
background-size: cover; background-size: cover;
background-position: 0 -17px; background: url('../img/listTable.png') no-repeat 0 -17px;
} }
.compTable tr td:nth-child(7) { .compTable tr td:nth-child(7) {
@ -3005,7 +3003,6 @@ input[type="checkbox"]:checked + span {
font-weight: bold; font-weight: bold;
font-family: Arial, Verdana, Helvetica, sans-serif; font-family: Arial, Verdana, Helvetica, sans-serif;
position: relative; position: relative;
position: relative;
width: 100%; width: 100%;
float: left; float: left;
} }
@ -3839,7 +3836,7 @@ input[type="checkbox"]:checked + span {
border-top: 1px solid black; border-top: 1px solid black;
border-bottom: 1px solid black; border-bottom: 1px solid black;
-webkit-transform: scale(1.03); -webkit-transform: scale(1.03);
-moz- transform: scale(1.03); -moz-transform: scale(1.03);
transform: scale(1.03); transform: scale(1.03);
box-shadow: 0 0 10px rgba(0,0,0,0.7); box-shadow: 0 0 10px rgba(0,0,0,0.7);
z-index: 999; z-index: 999;
@ -3916,7 +3913,7 @@ input[type="checkbox"]:checked + span {
border-top: 1px solid black; border-top: 1px solid black;
border-bottom: 1px solid black; border-bottom: 1px solid black;
-webkit-transform: scale(1.03); -webkit-transform: scale(1.03);
-moz- transform: scale(1.03); -moz-transform: scale(1.03);
transform: scale(1.03); transform: scale(1.03);
box-shadow: 0 0 10px rgba(0,0,0,0.7); box-shadow: 0 0 10px rgba(0,0,0,0.7);
z-index: 999; z-index: 999;
@ -4286,7 +4283,6 @@ input[type="checkbox"]:checked + span {
#modal_form1 { #modal_form1 {
width: 600px; width: 600px;
height: 400px; height: 400px;
display: table;
position: fixed; position: fixed;
top: 50%; top: 50%;
left: 50%; left: 50%;
@ -4344,7 +4340,6 @@ input[type="checkbox"]:checked + span {
width: 300px; width: 300px;
height: 160px; height: 160px;
min-height: 160px; min-height: 160px;
display: table;
position: fixed; position: fixed;
right: 0; right: 0;
top: 50%; top: 50%;
@ -5438,7 +5433,7 @@ input[type="radio"]:checked + span {
font-family: Arial, Verdana, Helvetica, sans-serif; font-family: Arial, Verdana, Helvetica, sans-serif;
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
margin: 0px 0 -15 0; margin: 0px 0 -15px 0;
} }
.inp-edit { .inp-edit {
@ -5536,7 +5531,7 @@ input[type="radio"]:checked + span {
.caret:after { .caret:after {
content: "\e253"; content: "\e253";
position: absolute; position: absolute;
font-family: 'Glyphicons Halflings'; font-family: 'Glyphicons Halflings', serif;
right: -6.5px; right: -6.5px;
top: -19px; top: -19px;
font-size: 12px; font-size: 12px;
@ -6080,7 +6075,7 @@ input[type="radio"]{
.welcomeMain{ .welcomeMain{
line-height: 48px; line-height: 48px;
font-family: 'pfdintextcomppro-regular', sans-serif; font-family: 'pfdintextcomppro-regular', sans-serif;
font-size: 43.5px; font-size: 43px;
} }
.menuUser > div{ .menuUser > div{
padding: 10px 0; padding: 10px 0;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

@ -180,10 +180,10 @@ $('[data-tooltip]').tooltip({
specSelects[2].select2(_.merge(specSelectOptions, {ajax: {url: specs.urlLevel3}})) specSelects[2].select2(_.merge(specSelectOptions, {ajax: {url: specs.urlLevel3}}))
specSelects[3].select2(_.merge(specSelectOptions, {ajax: {url: specs.urlLevel4}})) specSelects[3].select2(_.merge(specSelectOptions, {ajax: {url: specs.urlLevel4}}))
var specLevel1 = specs.specLevel1 var specLevel1 = specs.specLevel1;
var specLevel2 = specs.specLevel2 var specLevel2 = specs.specLevel2;
var specLevel3 = specs.specLevel3 var specLevel3 = specs.specLevel3;
var specLevel4 = specs.specLevel4 var specLevel4 = specs.specLevel4;
specSelects[0].select2('data', specLevel1 ? {id: specLevel1.id, text: specLevel1.name, origItem: specLevel1} : null) specSelects[0].select2('data', specLevel1 ? {id: specLevel1.id, text: specLevel1.name, origItem: specLevel1} : null)
specSelects[1].select2('data', specLevel2 ? {id: specLevel2.id, text: specLevel2.name, origItem: specLevel2} : null) specSelects[1].select2('data', specLevel2 ? {id: specLevel2.id, text: specLevel2.name, origItem: specLevel2} : null)

@ -1,4 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import Message, Notes, Documents, NewMessage from .models import Message, Notes, Documents, NewMessage
@ -11,11 +12,11 @@ class NotesAdmin(admin.ModelAdmin):
class DocumentsAdmin(admin.ModelAdmin): class DocumentsAdmin(admin.ModelAdmin):
list_display = ('sender', 'recipent', 'order','team') list_display = ('sender', 'recipent', 'order', 'team')
class NewMessageAdmin(admin.ModelAdmin): class NewMessageAdmin(admin.ModelAdmin):
list_display = ('user', 'message_pk','message_recipent', 'message_order','message_team') list_display = ('user', 'message_pk', 'message_recipent', 'message_order', 'message_team')
def message_pk(self, obj): def message_pk(self, obj):
return obj.message.pk return obj.message.pk

@ -1,13 +1,11 @@
import html import html
from tornado import gen, web, websocket, escape, options
from tornado.ioloop import IOLoop
from tornado.httpserver import HTTPServer
from tornado.options import parse_command_line
from settings import settings, PORT, DATABASE_DSN
import psycopg2
import momoko import momoko
import json from settings import settings, PORT, DATABASE_DSN
from tornado import gen, web, websocket, escape
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.options import parse_command_line
class BaseHandler(web.RequestHandler): class BaseHandler(web.RequestHandler):
@ -91,8 +89,8 @@ class ChatHandler(websocket.WebSocketHandler):
insert_sql = "INSERT INTO chat_message (id,text,created, sender_id,recipent_id," \ insert_sql = "INSERT INTO chat_message (id,text,created, sender_id,recipent_id," \
" private_type,team_id, order_id,is_delete,is_new) " \ " private_type,team_id, order_id,is_delete,is_new) " \
"VALUES (DEFAULT,'{0}',NOW(),{1},{2},{3},{4},{5},{6},{7}) RETURNING id".\ "VALUES (DEFAULT,'{0}',NOW(),{1},{2},{3},{4},{5},{6},{7}) RETURNING id". \
format(message, sender_id, recipent_id, private_type, team_value,order_value, is_delete, is_new) format(message, sender_id, recipent_id, private_type, team_value, order_value, is_delete, is_new)
cursor_list = yield dict(cursor=self.db.execute(insert_sql)) cursor_list = yield dict(cursor=self.db.execute(insert_sql))
cursor = cursor_list.get('cursor') cursor = cursor_list.get('cursor')
@ -102,19 +100,20 @@ class ChatHandler(websocket.WebSocketHandler):
team_ids = [t for t in team_ids_raw.rstrip(';').split(';')] team_ids = [t for t in team_ids_raw.rstrip(';').split(';')]
values_str = ''; values_str = '';
for t in team_ids: for t in team_ids:
values_str +='(DEFAULT,{0},{1}),'.format(message_id,t) values_str += '(DEFAULT,{0},{1}),'.format(message_id, t)
values_str = values_str.rstrip(',') values_str = values_str.rstrip(',')
insert_new_messages = "INSERT INTO chat_newmessage (id,message_id, user_id) VALUES{0}".\ insert_new_messages = "INSERT INTO chat_newmessage (id,message_id, user_id) VALUES{0}". \
format(values_str) format(values_str)
else: else:
insert_new_messages = "INSERT INTO chat_newmessage (id,message_id, user_id) VALUES(DEFAULT,{0},{1})".\ insert_new_messages = "INSERT INTO chat_newmessage (id,message_id, user_id) VALUES(DEFAULT,{0},{1})". \
format(message_id, recipent_id) format(message_id, recipent_id)
yield self.db.execute(insert_new_messages) yield self.db.execute(insert_new_messages)
if docs_send_links: if docs_send_links:
is_send = 'true' is_send = 'true'
docs_send_ids = docs_send_links.rstrip(';').replace(';', ',') docs_send_ids = docs_send_links.rstrip(';').replace(';', ',')
update_sql_documents = "UPDATE chat_documents SET message_id={0},is_send={1} WHERE id IN({2})".format(message_id, is_send, docs_send_ids) update_sql_documents = "UPDATE chat_documents SET message_id={0},is_send={1} WHERE id IN({2})".format(
message_id, is_send, docs_send_ids)
yield self.db.execute(update_sql_documents) yield self.db.execute(update_sql_documents)
select_last_sql = "SELECT chat_message.id, chat_message.text, chat_message.created, chat_message.sender_id," \ select_last_sql = "SELECT chat_message.id, chat_message.text, chat_message.created, chat_message.sender_id," \

@ -2,6 +2,7 @@ from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter
from .models import Message, Notes, Documents from .models import Message, Notes, Documents
# #
# class DocumentsFilterSet(FilterSet): # class DocumentsFilterSet(FilterSet):
# file = AllLookupsFilter() # file = AllLookupsFilter()
@ -30,17 +31,15 @@ class MessageFilterSet(FilterSet):
model = Message model = Message
class DocumentFilterSet(FilterSet): class DocumentFilterSet(FilterSet):
id = AllLookupsFilter() id = AllLookupsFilter()
# order = RelatedFilter('projects.filters.OrderFilterSet') # order = RelatedFilter('projects.filters.OrderFilterSet')
class Meta: class Meta:
model = Documents model = Documents
class NoteFilterSet(FilterSet): class NoteFilterSet(FilterSet):
created = AllLookupsFilter() created = AllLookupsFilter()
id = AllLookupsFilter() id = AllLookupsFilter()

@ -4,4 +4,3 @@ from django import forms
class ArticleForm(forms.Form): class ArticleForm(forms.Form):
title = forms.CharField() title = forms.CharField()
pub_date = forms.DateField() pub_date = forms.DateField()

@ -8,7 +8,7 @@ from users.models import User, Team
class Message(models.Model): class Message(models.Model):
text = models.TextField() text = models.TextField()
created = models.DateTimeField(default=timezone.now) created = models.DateTimeField(default=timezone.now)
order = models.ForeignKey(Order, related_name='messages',null=True, blank=True) order = models.ForeignKey(Order, related_name='messages', null=True, blank=True)
sender = models.ForeignKey(User, related_name='sender_messages') sender = models.ForeignKey(User, related_name='sender_messages')
recipent = models.ForeignKey(User, related_name='recipent_messages') recipent = models.ForeignKey(User, related_name='recipent_messages')
private_type = models.BooleanField(default=False) private_type = models.BooleanField(default=False)

@ -1,4 +1,5 @@
import json import json
from django.http import HttpResponse from django.http import HttpResponse
MIMEANY = '*/*' MIMEANY = '*/*'

@ -1,8 +1,8 @@
from rest_framework import serializers from rest_framework import serializers
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from .models import Message, Notes, Documents
from users.serializers import UserSerializer from users.serializers import UserSerializer
from .models import Message, Notes, Documents
class DocumentsSerializer(ModelSerializer): class DocumentsSerializer(ModelSerializer):
@ -44,7 +44,6 @@ class MessageSerializer(ModelSerializer):
documents = DocumentsSerializer(read_only=True, many=True) documents = DocumentsSerializer(read_only=True, many=True)
text = serializers.SerializerMethodField() text = serializers.SerializerMethodField()
class Meta: class Meta:
model = Message model = Message
@ -62,14 +61,15 @@ class MessageSerializer(ModelSerializer):
def get_text(self, obj): def get_text(self, obj):
out = obj.text out = obj.text
documents = obj.documents.all() documents = obj.documents.all()
if len(documents)>0: if len(documents) > 0:
documents_str = '<br>'.join(['Приложенный файл. скачать: <br><a target="_blank" href="/chat/download/' + doc.file.name + '">' + doc.file.name + '</a>' for doc in documents]) documents_str = '<br>'.join([
'Приложенный файл. скачать: <br><a target="_blank" href="/chat/download/' + doc.file.name + '">' + doc.file.name + '</a>'
for doc in documents])
out += '<br><br>' + documents_str out += '<br><br>' + documents_str
return out return out
class NoteSerializer(ModelSerializer): class NoteSerializer(ModelSerializer):
class Meta: class Meta:
model = Notes model = Notes

@ -13,7 +13,4 @@ settings = {
'server_traceback': True, 'server_traceback': True,
} }
DATABASE_DSN = 'dbname=archilance user=postgres password=postgres host=localhost' DATABASE_DSN = 'dbname=archilance user=postgres password=postgres host=localhost'

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

@ -1,5 +1,4 @@
import mimetypes import mimetypes
from django.core.urlresolvers import reverse
def serialize(instance, file_attr='file'): def serialize(instance, file_attr='file'):

@ -1,18 +1,19 @@
import json import json
from django.shortcuts import render from wsgiref.util import FileWrapper
from django.conf import settings from django.conf import settings
from django.views.generic import View,CreateView
from django.http import HttpResponse, Http404
from django.db.models import Q
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from wsgiref.util import FileWrapper from django.db.models import Q
from django.http import HttpResponse, Http404
from django.shortcuts import render
from django.views.generic import View, CreateView
from .response import JSONResponse, response_mimetype
from .utils import serialize
from .models import Message, Documents, NewMessage
from projects.models import Order, Project from projects.models import Order, Project
from wallets.models import Transaction
from users.models import User, Team from users.models import User, Team
from wallets.models import Transaction
from .models import Message, Documents
from .response import JSONResponse, response_mimetype
from .utils import serialize
class DocumentCreateView(CreateView): class DocumentCreateView(CreateView):
@ -37,11 +38,11 @@ class ChatUserView(LoginRequiredMixin, View):
template_name = '' template_name = ''
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
user_id = request.GET.get('user_id',None) user_id = request.GET.get('user_id', None)
if request.user.is_customer(): if request.user.is_customer():
customer_contacts = Message.objects.values_list('sender_id', 'recipent_id'). \ customer_contacts = Message.objects.values_list('sender_id', 'recipent_id'). \
filter(Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).\ filter(Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)). \
filter(Q(team_id=None)).\ filter(Q(team_id=None)). \
filter(is_delete=False).distinct() filter(is_delete=False).distinct()
users_ids = [] users_ids = []
@ -57,7 +58,8 @@ class ChatUserView(LoginRequiredMixin, View):
contacts_users = User.objects.filter(pk__in=users_ids) contacts_users = User.objects.filter(pk__in=users_ids)
archive_projects = request.user.customer_projects.select_related('order').exclude(state='active') archive_projects = request.user.customer_projects.select_related('order').exclude(state='active')
chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk)) chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk))
orders = request.user.customer_projects.select_related('order').filter(state='active').exclude(order__contractor__isnull=True, order__team__isnull=True) orders = request.user.customer_projects.select_related('order').filter(state='active').exclude(
order__contractor__isnull=True, order__team__isnull=True)
order_ids = [order.order.pk for order in orders] order_ids = [order.order.pk for order in orders]
transaction = Transaction.objects.get_or_create(customer=request.user, type='reservation', complete=False) transaction = Transaction.objects.get_or_create(customer=request.user, type='reservation', complete=False)
@ -66,7 +68,8 @@ class ChatUserView(LoginRequiredMixin, View):
message__team__isnull=True message__team__isnull=True
).count() ).count()
orders_ms_count = request.user.new_messages.filter(message__order__in=order_ids, message__team__isnull=True).count() orders_ms_count = request.user.new_messages.filter(message__order__in=order_ids,
message__team__isnull=True).count()
self.template_name = 'chat_customer.html' self.template_name = 'chat_customer.html'
return render(request, self.template_name, {'contacts_users': contacts_users, return render(request, self.template_name, {'contacts_users': contacts_users,
'chat_messages': chat_messages, 'chat_messages': chat_messages,
@ -88,10 +91,12 @@ class ChatUserView(LoginRequiredMixin, View):
teams = Team.objects.filter(Q(contractors__id=request.user.pk) | Q(owner=request.user.pk)).all() teams = Team.objects.filter(Q(contractors__id=request.user.pk) | Q(owner=request.user.pk)).all()
team_orders = Order.objects.filter(team_id__in=[team.pk for team in teams]).all() team_orders = Order.objects.filter(team_id__in=[team.pk for team in teams]).all()
orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).filter(project__state='active') orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).filter(
archive_orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).exclude(project__state='active') project__state='active')
archive_orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).exclude(
project__state='active')
contractor_contacts = Message.objects.values_list('sender_id', 'recipent_id').filter( contractor_contacts = Message.objects.values_list('sender_id', 'recipent_id').filter(
Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)).\ Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)). \
filter(is_delete=False).distinct() filter(is_delete=False).distinct()
users_ids = [] users_ids = []
for msg in contractor_contacts: for msg in contractor_contacts:
@ -113,7 +118,8 @@ class ChatUserView(LoginRequiredMixin, View):
your_teams = Team.objects.filter(Q(contractors__id=request.user.pk) | Q(owner=request.user)) your_teams = Team.objects.filter(Q(contractors__id=request.user.pk) | Q(owner=request.user))
orders_ms_count = request.user.new_messages.filter(message__order__in=orders, message__team__isnull=True).count() orders_ms_count = request.user.new_messages.filter(message__order__in=orders,
message__team__isnull=True).count()
teams_ms_count = request.user.new_messages.filter(message__team__in=your_teams).count() teams_ms_count = request.user.new_messages.filter(message__team__in=your_teams).count()
self.template_name = 'chat_contractor.html' self.template_name = 'chat_contractor.html'
@ -146,7 +152,7 @@ def project_delete(request):
if request.is_ajax(): if request.is_ajax():
project_id = request.POST.get('project_id') project_id = request.POST.get('project_id')
try: try:
project = Project.objects.get(pk=project_id,customer=request.user) project = Project.objects.get(pk=project_id, customer=request.user)
except Documents.DoesNotExist: except Documents.DoesNotExist:
project = None project = None
if project: if project:
@ -160,7 +166,7 @@ def project_delete(request):
raise Http404 raise Http404
def download_file(request,file_name): def download_file(request, file_name):
try: try:
document = Documents.objects.get(file=file_name) document = Documents.objects.get(file=file_name)
except Documents.DoesNotExist: except Documents.DoesNotExist:

@ -1,7 +1,10 @@
import pydash as _;
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin
from mptt.admin import MPTTModelAdmin from mptt.admin import MPTTModelAdmin
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
from .models import ( from .models import (
LiveImageUpload, LiveImageUpload,

@ -1,10 +1,14 @@
import pydash as _;
from django import forms from django import forms
from registration.forms import RegistrationFormTermsOfService from registration.forms import RegistrationFormTermsOfService
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
from .models import PrintOrder, PrintDocuments from .models import PrintOrder, PrintDocuments
from captcha.fields import ReCaptchaField from captcha.fields import ReCaptchaField
class PrintOrderForm(forms.ModelForm): class PrintOrderForm(forms.ModelForm):
files = forms.ModelMultipleChoiceField( files = forms.ModelMultipleChoiceField(
queryset=PrintDocuments.objects.none(), queryset=PrintDocuments.objects.none(),

@ -1,11 +1,12 @@
import datetime import datetime
from django.utils.timezone import now from django.utils.timezone import now
from users.models import User
from ratings.models import HistoryRating from ratings.models import HistoryRating
from users.models import User
class SetLastVisitMiddleware(object): class SetLastVisitMiddleware(object):
def process_response(self, request, response): def process_response(self, request, response):
if hasattr(request, 'user'): if hasattr(request, 'user'):
if request.user.is_authenticated(): if request.user.is_authenticated():
@ -14,7 +15,6 @@ class SetLastVisitMiddleware(object):
class SetRatingToUserEveryDay(object): class SetRatingToUserEveryDay(object):
def process_response(self, request, response): def process_response(self, request, response):
if hasattr(request, 'user'): if hasattr(request, 'user'):
today_date = datetime.datetime.now().date() today_date = datetime.datetime.now().date()
@ -27,4 +27,3 @@ class SetRatingToUserEveryDay(object):
hs_new.description = 'Балл за вход на сайт' hs_new.description = 'Балл за вход на сайт'
hs_new.save() hs_new.save()
return response return response

@ -44,7 +44,7 @@ class Settings(models.Model):
document_send_time_remove = models.IntegerField(default=14) document_send_time_remove = models.IntegerField(default=14)
recalculation_spec_time = models.TimeField() recalculation_spec_time = models.TimeField()
recalculation_rating_time = models.TimeField() recalculation_rating_time = models.TimeField()
noreply_email = models.CharField(max_length=50,default='noreply@proekton.com') noreply_email = models.CharField(max_length=50, default='noreply@proekton.com')
def __str__(self): def __str__(self):
return 'Настройки сайта' return 'Настройки сайта'

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

@ -14,5 +14,6 @@ urlpatterns = [
urls.url(r'^printorder/(?P<pk>\d+)/$', PrintOrderDetailView.as_view(), name='print-order-detail'), urls.url(r'^printorder/(?P<pk>\d+)/$', PrintOrderDetailView.as_view(), name='print-order-detail'),
urls.url(r'^live-image-upload/create/$', LiveImageUploadCreateView.as_view(), name='live-image-upload-create'), urls.url(r'^live-image-upload/create/$', LiveImageUploadCreateView.as_view(), name='live-image-upload-create'),
urls.url(r'^live-image-upload/(?P<pk>\d+)/delete/$', LiveImageUploadDeleteView.as_view(), name='live-image-upload-delete'), urls.url(r'^live-image-upload/(?P<pk>\d+)/delete/$', LiveImageUploadDeleteView.as_view(),
name='live-image-upload-delete'),
] ]

@ -1,8 +1,7 @@
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.core.exceptions import PermissionDenied from django.core.mail import EmailMultiAlternatives
from django.core.mail import send_mail, EmailMultiAlternatives
from django.core.urlresolvers import reverse, reverse_lazy from django.core.urlresolvers import reverse, reverse_lazy
from django.http import JsonResponse from django.http import JsonResponse
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
@ -10,15 +9,13 @@ from django.template.loader import get_template, render_to_string
from django.views.generic import View, DetailView from django.views.generic import View, DetailView
from registration.backends.default.views import RegistrationView from registration.backends.default.views import RegistrationView
from sorl.thumbnail import get_thumbnail from sorl.thumbnail import get_thumbnail
import json
import jsonschema
from .forms import PrintOrderForm, CustomRegistrationForm
from .models import PrintDocuments, PrintOrder, Settings, LiveImageUpload
from archilance import util from archilance import util
from archilance.mixins import BaseMixin from archilance.mixins import BaseMixin
from common.mixins import NoCsrfMixin from common.mixins import NoCsrfMixin
from users.models import ContractorResume from users.models import ContractorResume
from .forms import PrintOrderForm, CustomRegistrationForm
from .models import PrintDocuments, PrintOrder, Settings, LiveImageUpload
class PrintOrderDetailView(DetailView): class PrintOrderDetailView(DetailView):
@ -62,7 +59,6 @@ class PrintDocumentCreate(BaseMixin, View):
'files': link_files, 'files': link_files,
} }
settings = Settings.objects.all().first() settings = Settings.objects.all().first()
subject, from_email, to = 'Заявка на распечатку', settings.noreply_email, settings.document_send_email subject, from_email, to = 'Заявка на распечатку', settings.noreply_email, settings.document_send_email
text_content = render_to_string('document_email.txt', ctx_dict) text_content = render_to_string('document_email.txt', ctx_dict)
@ -74,7 +70,7 @@ class PrintDocumentCreate(BaseMixin, View):
msg.send() msg.send()
messages.info(request, 'Заявка на распечатку принята') messages.info(request, 'Заявка на распечатку принята')
return redirect('common:print-order-detail',pk=print_order.pk) return redirect('common:print-order-detail', pk=print_order.pk)
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))
else: else:
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
@ -82,7 +78,6 @@ class PrintDocumentCreate(BaseMixin, View):
return render(request, self.template_name, context) return render(request, self.template_name, context)
class LiveImageUploadCreateView(NoCsrfMixin, LoginRequiredMixin, View): class LiveImageUploadCreateView(NoCsrfMixin, LoginRequiredMixin, View):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
image = request.FILES.get('image') image = request.FILES.get('image')
@ -153,5 +148,4 @@ class CustomRegistrationView(RegistrationView):
return user return user
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))

@ -35,7 +35,7 @@ class ProjectAdminForm(forms.ModelForm):
class ProjectAdmin(admin.ModelAdmin): class ProjectAdmin(admin.ModelAdmin):
readonly_fields = ('pk',) readonly_fields = ('pk',)
list_display = ('name','pk','customer','state') list_display = ('name', 'pk', 'customer', 'state')
form = ProjectAdminForm form = ProjectAdminForm
@ -44,7 +44,7 @@ class OrderAdmin(admin.ModelAdmin):
class StageAdmin(admin.ModelAdmin): class StageAdmin(admin.ModelAdmin):
list_display = ('name','status','pos','order','is_paid',) list_display = ('name', 'status', 'pos', 'order', 'is_paid',)
admin.site.register(Answer) admin.site.register(Answer)

@ -6,5 +6,4 @@ class ProjectsConfig(AppConfig):
name = 'projects' name = 'projects'
def ready(self): def ready(self):
import projects.signals pass

@ -129,6 +129,7 @@ class PortfolioPhotoFilterSet(FilterSet):
id = AllLookupsFilter() id = AllLookupsFilter()
portfolio = RelatedFilter('projects.filters.PortfolioFilterSet') portfolio = RelatedFilter('projects.filters.PortfolioFilterSet')
# img = ??? # img = ???
class Meta: class Meta:

@ -1,10 +1,13 @@
import itertools
import pydash as _;
from django import forms from django import forms
from django.db.models import Q from django.db.models import Q
from django.forms.models import inlineformset_factory from django.forms.models import inlineformset_factory
from mptt.forms import TreeNodeChoiceField from mptt.forms import TreeNodeChoiceField
from pprint import pprint, pformat
import itertools _.map = _.map_;
import pydash as _; _.map = _.map_; _.filter = _.filter_ _.filter = _.filter_
from .models import ( from .models import (
Project, ProjectFile, Portfolio, Answer, Project, ProjectFile, Portfolio, Answer,
@ -14,7 +17,7 @@ from .models import (
from archilance import util from archilance import util
from common.models import Location, LiveImageUpload from common.models import Location, LiveImageUpload
from specializations.models import Specialization from specializations.models import Specialization
from users.models import User, Team from users.models import Team
class ProjectFilterForm(forms.ModelForm): class ProjectFilterForm(forms.ModelForm):
@ -49,7 +52,7 @@ class ProjectFilterForm(forms.ModelForm):
self.request = kwargs.pop('request') self.request = kwargs.pop('request')
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['work_type'].choices = tuple(itertools.chain((('',''),), self.fields['work_type'].choices)) self.fields['work_type'].choices = tuple(itertools.chain((('', ''),), self.fields['work_type'].choices))
self.fields['work_type'].required = False self.fields['work_type'].required = False
self.fields['work_type'].initial = '' self.fields['work_type'].initial = ''
@ -85,7 +88,8 @@ class ProjectFilterRealtyForm(forms.ModelForm):
self.fields['construction_type'].required = False self.fields['construction_type'].required = False
self.fields['location'].queryset = Location.objects.root_nodes()[0].get_descendants() self.fields['location'].queryset = Location.objects.root_nodes()[0].get_descendants()
self.fields['building_classification'].queryset = BuildingClassfication.objects.root_nodes()[0].get_descendants() self.fields['building_classification'].queryset = BuildingClassfication.objects.root_nodes()[
0].get_descendants()
# self.fields['location'].queryset = Location.objects # Migrate with this enabled # self.fields['location'].queryset = Location.objects # Migrate with this enabled
@ -184,7 +188,8 @@ class RealtyForm(forms.ModelForm):
self.fields['name'].required = False self.fields['name'].required = False
self.fields['location'].queryset = Location.objects.root_nodes()[0].get_descendants() self.fields['location'].queryset = Location.objects.root_nodes()[0].get_descendants()
self.fields['building_classification'].queryset = BuildingClassfication.objects.root_nodes()[0].get_descendants() self.fields['building_classification'].queryset = BuildingClassfication.objects.root_nodes()[
0].get_descendants()
# self.fields['location'].queryset = Location.objects # Migrate with this enabled # self.fields['location'].queryset = Location.objects # Migrate with this enabled
@ -300,7 +305,8 @@ class ProjectAnswerForm(forms.ModelForm):
# for c in members: # for c in members:
# portfolios.extend(c.portfolios.all()) # portfolios.extend(c.portfolios.all())
portfolios = Portfolio.objects.filter(user__pk__in=tuple(m.pk for m in itertools.chain((contractor,), members))) portfolios = Portfolio.objects.filter(
user__pk__in=tuple(m.pk for m in itertools.chain((contractor,), members)))
self.fields['portfolios'].queryset = portfolios self.fields['portfolios'].queryset = portfolios
else: else:
@ -416,5 +422,4 @@ class ProjectWorkTypeSuggestionForm(forms.ModelForm):
self['username'].field.initial = self.request.user.username self['username'].field.initial = self.request.user.username
self['email'].field.initial = self.request.user.email self['email'].field.initial = self.request.user.email
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))

@ -0,0 +1,48 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-10-14 22:49+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: templates/_trash/project_form.html:46
#: templates/contractor_portfolio_edit.html:46
#: templates/customer_project_create.html:62
#: templates/customer_project_edit.html:72 templates/project_filter.html:21
msgid "project_stage0"
msgstr "Тип работы"
#: templates/contractor_portfolio_edit.html:59
#: templates/customer_project_create.html:89
#: templates/customer_project_edit.html:99 templates/project_filter.html:35
msgid "project_stage1"
msgstr "Стадия проекта"
#: templates/contractor_portfolio_edit.html:64
#: templates/customer_project_create.html:94
#: templates/customer_project_edit.html:104 templates/project_filter.html:39
msgid "project_stage2"
msgstr "Раздел"
#: templates/contractor_portfolio_edit.html:69
#: templates/customer_project_create.html:99
#: templates/customer_project_edit.html:109 templates/project_filter.html:43
msgid "project_stage3"
msgstr "Подраздел"
#: templates/contractor_portfolio_edit.html:74
#: templates/customer_project_create.html:104
#: templates/customer_project_edit.html:114 templates/project_filter.html:47
msgid "project_stage4"
msgstr "Подраздел ( доп. )"

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-14 20:49
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0046_merge'),
]
operations = [
migrations.AlterModelOptions(
name='buildingclassfication',
options={'ordering': ['order'], 'verbose_name': 'Тип здания', 'verbose_name_plural': 'Типы зданий'},
),
migrations.AlterModelOptions(
name='constructiontype',
options={'ordering': ['order'], 'verbose_name': 'Вид строительства', 'verbose_name_plural': 'Виды строительства'},
),
migrations.AlterModelManagers(
name='buildingclassfication',
managers=[
],
),
migrations.AddField(
model_name='buildingclassfication',
name='order',
field=models.PositiveSmallIntegerField(default=0, null=True),
),
migrations.AddField(
model_name='constructiontype',
name='order',
field=models.PositiveSmallIntegerField(default=0, null=True),
),
]

@ -1,17 +1,19 @@
import pydash as _;
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.db.models import Q from django.db.models import Q
from django.core.exceptions import ValidationError
from django.utils import timezone from django.utils import timezone
from hitcount.models import HitCountMixin from hitcount.models import HitCountMixin
from mptt.managers import TreeManager
from mptt.models import TreeForeignKey, MPTTModel from mptt.models import TreeForeignKey, MPTTModel
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
from users.models import User, Team from users.models import User, Team
from specializations.models import Specialization from specializations.models import Specialization
CURRENCIES = ( CURRENCIES = (
('rur', 'RUR'), ('rur', 'RUR'),
('usd', 'USD'), ('usd', 'USD'),
@ -36,22 +38,31 @@ TERM_TYPE_MORPHS = {
class BuildingClassfication(MPTTModel): class BuildingClassfication(MPTTModel):
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
parent = TreeForeignKey('self', blank=True, null=True, related_name='children', db_index=True) parent = TreeForeignKey('self', blank=True, null=True, related_name='children', db_index=True)
order = models.PositiveSmallIntegerField(default=0, null=True)
objects = TreeManager()
def __str__(self): def __str__(self):
return self.name return self.name
class MPTTMeta:
order_insertion_by = ['order']
class Meta: class Meta:
ordering = ['order']
verbose_name = 'Тип здания' verbose_name = 'Тип здания'
verbose_name_plural = 'Типы зданий' verbose_name_plural = 'Типы зданий'
class ConstructionType(models.Model): class ConstructionType(models.Model):
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
order = models.PositiveSmallIntegerField(default=0, null=True)
def __str__(self): def __str__(self):
return self.name return self.name
class Meta: class Meta:
ordering = ['order']
verbose_name = 'Вид строительства' verbose_name = 'Вид строительства'
verbose_name_plural = 'Виды строительства' verbose_name_plural = 'Виды строительства'
@ -137,7 +148,7 @@ class Answer(models.Model):
budget = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True) budget = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True)
created = models.DateTimeField(default=timezone.now) created = models.DateTimeField(default=timezone.now)
currency = models.CharField(max_length=5, choices=CURRENCIES, blank=True, null=True) currency = models.CharField(max_length=5, choices=CURRENCIES, blank=True, null=True)
portfolios = models.ManyToManyField('Portfolio', related_name ='answers', blank=True) portfolios = models.ManyToManyField('Portfolio', related_name='answers', blank=True)
project = models.ForeignKey(Project, related_name='answers') project = models.ForeignKey(Project, related_name='answers')
secure_deal_only = models.BooleanField(default=False) secure_deal_only = models.BooleanField(default=False)
term = models.IntegerField(blank=True, null=True) term = models.IntegerField(blank=True, null=True)
@ -145,7 +156,9 @@ class Answer(models.Model):
is_archive = models.BooleanField(default=False) is_archive = models.BooleanField(default=False)
rejected = models.BooleanField(default=False) rejected = models.BooleanField(default=False)
content_type = models.ForeignKey(ContentType, limit_choices_to=Q(app_label='users', model='user') | Q(app_label='users', model='team')) content_type = models.ForeignKey(ContentType,
limit_choices_to=Q(app_label='users', model='user') | Q(app_label='users',
model='team'))
object_id = models.IntegerField() object_id = models.IntegerField()
author = GenericForeignKey('content_type', 'object_id') author = GenericForeignKey('content_type', 'object_id')
@ -216,7 +229,8 @@ class Order(models.Model):
('completed', 'Завершен'), ('completed', 'Завершен'),
) )
contractor = models.ForeignKey(User, null=True, blank=True, related_name='orders') # Related name should've been "contractor_orders" contractor = models.ForeignKey(User, null=True, blank=True,
related_name='orders') # Related name should've been "contractor_orders"
created = models.DateTimeField(default=timezone.now) created = models.DateTimeField(default=timezone.now)
project = models.OneToOneField(Project, related_name='order') project = models.OneToOneField(Project, related_name='order')
secure = models.BooleanField(default=False) secure = models.BooleanField(default=False)
@ -238,6 +252,7 @@ class Order(models.Model):
else: else:
return None return None
class Arbitration(models.Model): class Arbitration(models.Model):
user = models.ForeignKey(User) user = models.ForeignKey(User)
text = models.TextField() text = models.TextField()
@ -264,7 +279,6 @@ STATUSES = (
('completed', 'Завершен'), ('completed', 'Завершен'),
) )
from .validators import validate_term
class Stage(models.Model): class Stage(models.Model):
cost = models.DecimalField(max_digits=10, decimal_places=0) cost = models.DecimalField(max_digits=10, decimal_places=0)
@ -305,7 +319,8 @@ class Stage(models.Model):
class Candidate(models.Model): class Candidate(models.Model):
answer = models.ForeignKey(Answer, related_name='candidates') # TODO: Swap to "OneToOneField" answer = models.ForeignKey(Answer, related_name='candidates') # TODO: Swap to "OneToOneField"
project = models.ForeignKey(Project, related_name='candidates') # TODO: Remove this redundant field at all (we've got "candidate.answer.project") project = models.ForeignKey(Project,
related_name='candidates') # TODO: Remove this redundant field at all (we've got "candidate.answer.project")
status = models.BooleanField(default=False) status = models.BooleanField(default=False)
position = models.PositiveIntegerField(default=0) position = models.PositiveIntegerField(default=0)

@ -1,12 +1,13 @@
from rest_framework import serializers
from generic_relations.relations import GenericRelatedField from generic_relations.relations import GenericRelatedField
from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField, PrimaryKeyRelatedField, ReadOnlyField from rest_framework import serializers
from rest_framework.serializers import ModelSerializer, ImageField, FileField, PrimaryKeyRelatedField
from .models import Project, Realty, BuildingClassfication, ConstructionType, Order, Stage, Portfolio, PortfolioPhoto, Answer, AnswerFile
from common.serializers import LocationSerializer, ContentTypeSerializer from common.serializers import LocationSerializer, ContentTypeSerializer
from specializations.serializers import SpecializationSerializer from specializations.serializers import SpecializationSerializer
from users.models import User, Team from users.models import User, Team
from users.serializers import UserSerializer, TeamSerializer from users.serializers import UserSerializer, TeamSerializer
from .models import Project, Realty, BuildingClassfication, ConstructionType, Order, Stage, Portfolio, PortfolioPhoto, \
Answer, AnswerFile
class AnswerFileSerializer(ModelSerializer): class AnswerFileSerializer(ModelSerializer):
@ -78,16 +79,16 @@ class RealtySerializer(ModelSerializer):
class StageSerializer(ModelSerializer): class StageSerializer(ModelSerializer):
term = serializers.DateField(format="%d.%m.%Y", input_formats=['%d.%m.%Y',]) term = serializers.DateField(format="%d.%m.%Y", input_formats=['%d.%m.%Y', ])
def validate(self, data): def validate(self, data):
if 'pos' in data and data['pos'] > 1: if 'pos' in data and data['pos'] > 1:
pos = data['pos'] -1 pos = data['pos'] - 1
stage_last = Stage.objects.filter(order=data['order'], pos=pos) stage_last = Stage.objects.filter(order=data['order'], pos=pos)
if stage_last: if stage_last:
stage_last = stage_last[0] stage_last = stage_last[0]
if stage_last.term > data['term']: if stage_last.term > data['term']:
raise serializers.ValidationError({'term':'Дата не должна быть меньше даты предыдущео этапа'}) raise serializers.ValidationError({'term': 'Дата не должна быть меньше даты предыдущео этапа'})
return data return data
class Meta: class Meta:

@ -1,7 +1,7 @@
from django.core.signals import request_finished
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.utils import timezone
from django.dispatch import receiver from django.dispatch import receiver
from django.utils import timezone
from .models import Stage from .models import Stage

@ -35,15 +35,15 @@
{# </div>#} {# </div>#}
{# <input type="submit" value="Submit" />#} {# <input type="submit" value="Submit" />#}
{# </form>#} {# </form>#}
<ul class="list-new-new"> {# <ul class="list-new-new">#}
<li> {# <li>#}
Архитерурное 2.jpg {# Архитерурное 2.jpg#}
<span>7мб</span> {# <span>7мб</span>#}
<div></div> {# <div></div>#}
</li> {# </li>#}
</ul> {# </ul>#}
</div> </div>
<p class="type-work">Тип работы:</p> <p class="type-work">{% trans 'project_stage0' %}:</p>
<div class="mail-block type-work-inset"> <div class="mail-block type-work-inset">
<div class="inset-mb"> <div class="inset-mb">
<label><input type="radio" value="1" name="{{ project_form.type_work.name }}"><span></span></label> <label><input type="radio" value="1" name="{{ project_form.type_work.name }}"><span></span></label>
@ -76,7 +76,7 @@
<select id="specialization1" name="{{ project_form.specialization.name }}"> <select id="specialization1" name="{{ project_form.specialization.name }}">
</select> </select>
{# {{ project_form.specialization }}#} {# {{ project_form.specialization }}#}
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<select class="selectpicker"> <select class="selectpicker">
@ -172,7 +172,7 @@
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="polsF1 polsF2 disTab">
<div class="col-lg-3"> <div class="col-lg-3">
<select class="selectpicker" > <select class="selectpicker">
<option>Mustard</option> <option>Mustard</option>
<option>Ketchup</option> <option>Ketchup</option>
<option>Relish</option> <option>Relish</option>
@ -224,7 +224,7 @@
<input style="border-radius: 40px; <input style="border-radius: 40px;
font-family: 'pfdintextcomppro-regular', sans-serif;color: black;font-size: 16px;padding: 17px 33px 17px 33px; font-family: 'pfdintextcomppro-regular', sans-serif;color: black;font-size: 16px;padding: 17px 33px 17px 33px;
float: left;margin: 0 15px 48px 15px;border: 1px solid #DFDFDF;text-transform: uppercase; float: left;margin: 0 15px 48px 15px;border: 1px solid #DFDFDF;text-transform: uppercase;
letter-spacing: 2px;color: #42B476;border: 1px solid #42B476" type="submit" value="Разместить проект" /> letter-spacing: 2px;color: #42B476;border: 1px solid #42B476" type="submit" value="Разместить проект"/>
<a href="javascript:void(0)">Сохранить</a> <a href="javascript:void(0)">Сохранить</a>
</div> </div>
@ -235,7 +235,6 @@
</div> </div>
</form> </form>
{% endblock %} {% endblock %}
@ -243,10 +242,11 @@
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(function () {
function updateSelectData(){ function updateSelectData() {
} }
$.ajax({ $.ajax({
url: '/api/specializations?parent=1', url: '/api/specializations?parent=1',
type: 'GET', type: 'GET',
@ -271,7 +271,7 @@
} }
}); });
$("#specialization1").on("change",function(){ $("#specialization1").on("change", function () {
}); });
}); });

@ -14,5 +14,5 @@
</div> </div>
{% endfor %} {% endfor %}
</fieldset> </fieldset>
<input type="submit" value="Add portfolio" class="submit" /> <input type="submit" value="Add portfolio" class="submit"/>
</form> </form>

@ -3,7 +3,7 @@
<h2>Мои проекты</h2> <h2>Мои проекты</h2>
{% for proj in request.user.customer_projects.all %} {% for proj in request.user.customer_projects.all %}
<h3>{{ proj }}</h3> <h3>{{ proj }}</h3>
<h5>{{ proj.order }}</h5> <h5>{{ proj.order }}</h5>
{% endfor %} {% endfor %}

@ -53,7 +53,8 @@
</td> </td>
<td> <td>
<span class="glyphicon glyphicon-info-sign" aria-hidden="true" data-tooltip data-placement="right" title="{{ cand.answer.get_first_message }}"></span> <span class="glyphicon glyphicon-info-sign" aria-hidden="true" data-tooltip data-placement="right"
title="{{ cand.answer.get_first_message }}"></span>
</td> </td>
<td> <td>
@ -62,7 +63,8 @@
<li><span>{{ cand.answer.author.rating }}</span></li> <li><span>{{ cand.answer.author.rating }}</span></li>
<li> <li>
<span>+0</span> 0 <small> - 0</small> <span>+0</span> 0
<small> - 0</small>
</li> </li>
{% if cand.answer.author.cro %} {% if cand.answer.author.cro %}
@ -82,7 +84,9 @@
<td> <td>
<div class="tableButtons disTab"> <div class="tableButtons disTab">
<form action="{% url 'projects:customer-offer-order' answer_id=cand.answer.pk project_id=cand.project.pk %}" method="POST" novalidate> <form
action="{% url 'projects:customer-offer-order' answer_id=cand.answer.pk project_id=cand.project.pk %}"
method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<a href="#" onclick="$(this).closest('form').submit(); return false"> <a href="#" onclick="$(this).closest('form').submit(); return false">

@ -1,11 +1,13 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load thumbnail %} {% load thumbnail %}
{% load i18n %}
{% block head_css %} {% block head_css %}
<style> <style>
.-live-image-upload-container .-position-relative-parent {position: relative} .-live-image-upload-container .-position-relative-parent {
position: relative
}
.-live-image-upload-container .-image-delete, .-live-image-upload-container .-image-delete,
.-live-image-upload-container .-live-image-delete { .-live-image-upload-container .-live-image-delete {
@ -34,7 +36,7 @@
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Название <span style="color: red">{{ form.name.errors.as_text }}</span></p> <p>Название <span style="color: red">{{ form.name.errors.as_text }}</span></p>
<input type="text" class="box-sizing" name="{{ form.name.html_name }}" value="{{ form.name.value }}"> <input type="text" class="box-sizing" name="{{ form.name.html_name }}" value="{{ form.name.value }}">
<input type="hidden" name="{{ form.contractor.html_name }}" value="{{ form.contractor.value }}" /> <input type="hidden" name="{{ form.contractor.html_name }}" value="{{ form.contractor.value }}"/>
</div> </div>
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
@ -43,7 +45,7 @@
</div> </div>
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Тип работы <span style="color: red">{{ form.work_type.errors.as_text }}</span></p> <p>{% trans 'project_stage0' %} <span style="color: red">{{ form.work_type.errors.as_text }}</span></p>
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
@ -56,22 +58,23 @@
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Стадия проекта <span style="color: red">{{ form.specialization.errors.as_text }}</span></div> <div class="-bold">{% trans 'project_stage1' %} <span
style="color: red">{{ form.specialization.errors.as_text }}</span></div>
<input type='hidden' class="-spec-select -spec-select-level-1" style="width: 100%"> <input type='hidden' class="-spec-select -spec-select-level-1" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold"><span class="-dynamic-label">Стадия проекта</span></div> <div class="-bold"><span class="-dynamic-label">{% trans 'project_stage2' %}</span></div>
<input type='hidden' class="-spec-select -spec-select-level-2" style="width: 100%"> <input type='hidden' class="-spec-select -spec-select-level-2" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Раздел</div> <div class="-bold">{% trans 'project_stage3' %}</div>
<input type='hidden' class="-spec-select -spec-select-level-3" style="width: 100%"> <input type='hidden' class="-spec-select -spec-select-level-3" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Подраздел</div> <div class="-bold">{% trans 'project_stage4' %}</div>
<input type='hidden' class="-spec-select -spec-select-level-4" style="width: 100%"> <input type='hidden' class="-spec-select -spec-select-level-4" style="width: 100%">
</div> </div>
@ -85,7 +88,7 @@
<input type="text" class="box-sizing" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}"> <input type="text" class="box-sizing" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}">
</div> </div>
<div class="col-lg-4"> <div class="col-lg-4">
{{ form.currency}} {{ form.currency }}
</div> </div>
</div> </div>
</div> </div>
@ -106,17 +109,16 @@
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="polsF1 polsF2 disTab">
<p>Вид строительства</p> <p>Вид строительства</p>
{{ form.construction_type}} {{ form.construction_type }}
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="polsF1 polsF2 disTab">
<p>Классификация здания</p> <p>Классификация здания</p>
{{ form.building_classification}} {{ form.building_classification }}
</div> </div>
<div class="textAreaBlock2 text-nn box-sizing disTab -live-image-upload-container"> <div class="textAreaBlock2 text-nn box-sizing disTab -live-image-upload-container">
<p>Фотографии</p> <p>Фотографии</p>
@ -130,7 +132,8 @@
{% endthumbnail %} {% endthumbnail %}
</div> </div>
<input type="checkbox" name="{{ form.photos.html_name }}" value="{{ photo.pk }}" checked style='display: none'> <input type="checkbox" name="{{ form.photos.html_name }}" value="{{ photo.pk }}" checked
style='display: none'>
</div> </div>
{% endfor %} {% endfor %}
@ -138,11 +141,13 @@
<% images.forEach(function(image) { %> <% images.forEach(function(image) { %>
<div class="col-lg-3"> <div class="col-lg-3">
<div class="-position-relative-parent" style="display: inline-block"> <div class="-position-relative-parent" style="display: inline-block">
<a href="#" onclick="return false" data-image-id="<%- image.id %>" class="btn close -live-image-delete">&times;</a> <a href="#" onclick="return false" data-image-id="<%- image.id %>"
class="btn close -live-image-delete">&times;</a>
<img src="<%- image.smallThumbnailUrl %>"> <img src="<%- image.smallThumbnailUrl %>">
</div> </div>
<input type="checkbox" name="{{ form.live_images.html_name }}" value="<%- image.id %>" checked style='display: none'> <input type="checkbox" name="{{ form.live_images.html_name }}" value="<%- image.id %>" checked
style='display: none'>
</div> </div>
<% }) %> <% }) %>
</script> </script>
@ -152,20 +157,22 @@
<div class="col-xs-12"> <div class="col-xs-12">
<input type="file" name="image" multiple class="-live-image-upload-field" style="display: none"> <input type="file" name="image" multiple class="-live-image-upload-field" style="display: none">
<a href="#" onclick="$(this).closest('.-live-image-upload-container').find('.-live-image-upload-field').first().click(); return false" class="btn btn-default add_file_to_port"> <a href="#"
onclick="$(this).closest('.-live-image-upload-container').find('.-live-image-upload-field').first().click(); return false"
class="btn btn-default add_file_to_port">
Выберите файлы Выберите файлы
</a> </a>
</div> </div>
</div> </div>
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
</div> </div>
<div class="searchF1 polsF1 polsFF links-filter"> <div class="searchF1 polsF1 polsFF links-filter">
<input type="submit" value="Сохранить" class="btn-submit-link add_file_to_port"> <input type="submit" value="Сохранить" class="btn-submit-link add_file_to_port">
<a href="{% url 'users:contractor-profile' request.user.pk %}" class="btn-submit-link add_file_to_port">Отмена</a> <a href="{% url 'users:contractor-profile' request.user.pk %}"
class="btn-submit-link add_file_to_port">Отмена</a>
</div> </div>

@ -1,8 +1,11 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load i18n %}
{% block head_css %} {% block head_css %}
<style> <style>
.-error, .errorlist {color: red} .-error, .errorlist {
color: red
}
</style> </style>
{% endblock %} {% endblock %}
@ -17,7 +20,8 @@
<p class="titleScore">Новый заказ</p> <p class="titleScore">Новый заказ</p>
</div> </div>
<form action="{% url 'projects:customer-project-create' %}" method="POST" enctype="multipart/form-data" novalidate class="-spec-work-type-combo-container"> <form action="{% url 'projects:customer-project-create' %}" method="POST" enctype="multipart/form-data" novalidate
class="-spec-work-type-combo-container">
{% csrf_token %} {% csrf_token %}
<input type="hidden" id="extraFields" name="extra_fields" value=""> <input type="hidden" id="extraFields" name="extra_fields" value="">
@ -31,13 +35,23 @@
{% endif %} {% endif %}
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
<p class="titleResF1">Название заказа <span data-tooltip data-placement="{% tooltip_placement pk=4 %}" title="{% tooltip pk=4 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span> <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.name.errors.as_text }}</span></p> <p class="titleResF1">Название заказа <span data-tooltip data-placement="{% tooltip_placement pk=4 %}"
title="{% tooltip pk=4 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span>
<span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.name.errors.as_text }}</span></p>
<input type="text" class="box-sizing" name="{{ form.name.html_name }}" value="{{ form.name.value }}"> <input type="text" class="box-sizing" name="{{ form.name.html_name }}" value="{{ form.name.value }}">
</div> </div>
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
<p class="titleResF1">Подробно опишите задание <span data-tooltip data-placement="{% tooltip_placement pk=5 %}" title="{% tooltip pk=5 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span> <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.text.errors.as_text }}</span></p> <p class="titleResF1">Подробно опишите задание <span data-tooltip
<textarea name="{{ form.text.html_name }}" id="text-new" style="margin-top:0;">{{ form.text.value }}</textarea> data-placement="{% tooltip_placement pk=5 %}"
title="{% tooltip pk=5 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span>
<span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.text.errors.as_text }}</span></p>
<textarea name="{{ form.text.html_name }}" id="text-new"
style="margin-top:0;">{{ form.text.value }}</textarea>
</div> </div>
</div> </div>
<div class="col-lg-3 wrChat1"> <div class="col-lg-3 wrChat1">
@ -51,14 +65,20 @@
<ul class="list-new-new"> <ul class="list-new-new">
<li class="file-upload-widget" style="display: none"> <li class="file-upload-widget" style="display: none">
<input type="file" name="new_files" class="file-upload-input" style="position: absolute; top: -1000px; left: -1000px"> <input type="file" name="new_files" class="file-upload-input"
style="position: absolute; top: -1000px; left: -1000px">
<p class="file-upload-label"></p> <p class="file-upload-label"></p>
<div class="file-upload-remove-btn"></div> <div class="file-upload-remove-btn"></div>
</li> </li>
</ul> </ul>
</div> </div>
<p class="type-work">Тип работы <span data-tooltip data-placement="{% tooltip_placement pk=6 %}" title="{% tooltip pk=6 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span> <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.work_type.errors.as_text }}</span></p> <p class="type-work">{% trans 'project_stage0' %} <span data-tooltip
data-placement="{% tooltip_placement pk=6 %}"
title="{% tooltip pk=6 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span>
<span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.work_type.errors.as_text }}</span></p>
<div class="mail-block type-work-inset -project-work-type-radios-container"> <div class="mail-block type-work-inset -project-work-type-radios-container">
{% for id, text in form.work_type.field.choices %} {% for id, text in form.work_type.field.choices %}
<div class="inset-mb"> <div class="inset-mb">
@ -77,7 +97,8 @@
{% endfor %} {% endfor %}
</div> </div>
<div class="textAreaBlock2 box-sizing disTab"> <div class="textAreaBlock2 box-sizing disTab">
<a href="#" onclick="return false" data-toggle="modal" data-target="#projectWorkTypeSuggestionModal" class="new-link new-lw">+ Добавить раздел</a> <a href="#" onclick="return false" data-toggle="modal" data-target="#projectWorkTypeSuggestionModal"
class="new-link new-lw">+ Добавить раздел</a>
</div> </div>
</div> </div>
</div> </div>
@ -85,34 +106,45 @@
<div class="filter clearfix"> <div class="filter clearfix">
<div class="polsF1 disTab"> <div class="polsF1 disTab">
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Стадия проекта <span data-tooltip data-placement="{% tooltip_placement pk=7 %}" title="{% tooltip pk=7 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span> <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.specialization.errors.as_text }}</span></div> <div class="-bold">{% trans 'project_stage1' %} <span data-tooltip
data-placement="{% tooltip_placement pk=7 %}"
title="{% tooltip pk=7 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span>
<span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.specialization.errors.as_text }}</span></div>
<input type="hidden" class="-spec-select -spec-select-level-1" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-1" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold"><span class="-dynamic-label">Стадия проекта</span></div> <div class="-bold"><span class="-dynamic-label">{% trans 'project_stage2' %}</span></div>
<input type="hidden" class="-spec-select -spec-select-level-2" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-2" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Раздел</div> <div class="-bold">{% trans 'project_stage3' %}</div>
<input type="hidden" class="-spec-select -spec-select-level-3" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-3" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Подраздел</div> <div class="-bold">{% trans 'project_stage4' %}</div>
<input type="hidden" class="-spec-select -spec-select-level-4" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-4" style="width: 100%">
</div> </div>
<input type="hidden" name="{{ form.specialization.html_name }}" value="{{ form.specialization.value }}" class="-chosen-spec-id"> <input type="hidden" name="{{ form.specialization.html_name }}" value="{{ form.specialization.value }}"
class="-chosen-spec-id">
</div> </div>
<div class="titleF1 titleF2 disTab"> <div class="titleF1 titleF2 disTab">
<div class="col-lg-12">Бюджет <span data-tooltip data-placement="{% tooltip_placement pk=8 %}" title="{% tooltip pk=8 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span> <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.budget.errors.as_text }}</span></div> <div class="col-lg-12">Бюджет <span data-tooltip data-placement="{% tooltip_placement pk=8 %}"
title="{% tooltip pk=8 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span>
<span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.budget.errors.as_text }}</span></div>
<!--<div class="col-lg-8"></div>--> <!--<div class="col-lg-8"></div>-->
</div> </div>
<div class="searchF1 polsF1 polsFF"> <div class="searchF1 polsF1 polsFF">
<div class="col-lg-4"> <div class="col-lg-4">
<input type="text" class="box-sizing surr" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}"> <input type="text" class="box-sizing surr" name="{{ form.budget.html_name }}"
value="{{ form.budget.value }}">
{{ form.currency }} {{ form.currency }}
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
@ -128,7 +160,9 @@
<span></span> <span></span>
</label> </label>
<p>или по договоренности <span data-tooltip data-placement="{% tooltip_placement pk=9 %}" title="{% tooltip pk=9 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span></p> <p>или по договоренности <span data-tooltip data-placement="{% tooltip_placement pk=9 %}"
title="{% tooltip pk=9 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span></p>
</div> </div>
</div> </div>
<div class="searchF1 polsF1 polsFF make-new"> <div class="searchF1 polsF1 polsFF make-new">
@ -144,7 +178,9 @@
<p>Сделать для исполнителей обязательным для заполнения поля цена и срок</p> <p>Сделать для исполнителей обязательным для заполнения поля цена и срок</p>
</div> </div>
<div class="titleF1 titleF2 disTab"> <div class="titleF1 titleF2 disTab">
<div class="col-lg-12">Способ оплаты <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.deal_type.errors.as_text }}</span></div> <div class="col-lg-12">Способ оплаты <span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.deal_type.errors.as_text }}</span>
</div>
</div> </div>
<div class="searchF1 polsF1 polsFF radio-afer"> <div class="searchF1 polsF1 polsFF radio-afer">
<div class="col-lg-6"> <div class="col-lg-6">
@ -189,14 +225,11 @@
</div> </div>
<div class="resSearchF1"> <div class="resSearchF1">
<div class="col-lg-3"> <div class="col-lg-3">
<p class="titleResF1">Расширенный поиск</p> <p class="titleResF1">Расширенный поиск</p>
<button data-tooltip data-placement="{% tooltip_placement pk=12 %}" title="{% tooltip pk=12 %}" class="resButtonF1"> <button data-tooltip data-placement="{% tooltip_placement pk=12 %}" title="{% tooltip pk=12 %}"
class="resButtonF1">
<span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span> <span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>
</button> </button>
</div> </div>
@ -207,10 +240,28 @@
<div class="slideRes disTab activeSlide"> <div class="slideRes disTab activeSlide">
<div class="titleF1 disTab"> <div class="titleF1 disTab">
<div class="col-lg-3">Выбор объекта <span data-tooltip data-placement="{% tooltip_placement pk=13 %}" title="{% tooltip pk=13 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span><br><span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.realty.errors.as_text }}</span></div> <div class="col-lg-3">Выбор объекта <span data-tooltip data-placement="{% tooltip_placement pk=13 %}"
<div class="col-lg-3">Наименование <span data-tooltip data-placement="{% tooltip_placement pk=14 %}" title="{% tooltip pk=14 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span><br><span id="{% random_ident %}" class="-validation-error" style="color: red">{{ realty_form.name.errors.as_text }}</span></div> title="{% tooltip pk=13 %}"
<div class="col-lg-3">Классификация здания <span data-tooltip data-placement="{% tooltip_placement pk=15 %}" title="{% tooltip pk=15 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span><br><span id="{% random_ident %}" class="-validation-error" style="color: red">{{ realty_form.building_classification.errors.as_text }}</span></div> class="-green-glyphicon glyphicon glyphicon-question-sign"></span><br><span
<div class="col-lg-3">Вид строительства <span data-tooltip data-placement="{% tooltip_placement pk=16 %}" title="{% tooltip pk=16 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span><br><span id="{% random_ident %}" class="-validation-error" style="color: red">{{ realty_form.construction_type.errors.as_text }}</span></div> id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.realty.errors.as_text }}</span></div>
<div class="col-lg-3">Наименование <span data-tooltip data-placement="{% tooltip_placement pk=14 %}"
title="{% tooltip pk=14 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span><br><span
id="{% random_ident %}" class="-validation-error"
style="color: red">{{ realty_form.name.errors.as_text }}</span></div>
<div class="col-lg-3">Классификация здания <span data-tooltip
data-placement="{% tooltip_placement pk=15 %}"
title="{% tooltip pk=15 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span><br><span
id="{% random_ident %}" class="-validation-error"
style="color: red">{{ realty_form.building_classification.errors.as_text }}</span></div>
<div class="col-lg-3">Вид строительства <span data-tooltip
data-placement="{% tooltip_placement pk=16 %}"
title="{% tooltip pk=16 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span><br><span
id="{% random_ident %}" class="-validation-error"
style="color: red">{{ realty_form.construction_type.errors.as_text }}</span></div>
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="polsF1 polsF2 disTab">
@ -222,7 +273,8 @@
<option value="" {% if not form.realty.value %}selected="selected"{% endif %}>Создать новый</option> <option value="" {% if not form.realty.value %}selected="selected"{% endif %}>Создать новый</option>
{% for r in form.realty.field.queryset %} {% for r in form.realty.field.queryset %}
<option value="{{ r.pk }}" {% if form.realty.value|int == r.pk %}selected="selected"{% endif %}>{{ r.name }}</option> <option value="{{ r.pk }}"
{% if form.realty.value|int == r.pk %}selected="selected"{% endif %}>{{ r.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -236,14 +288,14 @@
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
{{ realty_form.building_classification }} {{ realty_form.building_classification }}
{# <select#} {# <select#}
{# id="realtyBuildingClassificationId"#} {# id="realtyBuildingClassificationId"#}
{# #} {# #}
{# name="{{ realty_form.building_classification.html_name }}">#} {# name="{{ realty_form.building_classification.html_name }}">#}
{# {% for c in realty_form.building_classification.field.queryset %}#} {# {% for c in realty_form.building_classification.field.queryset %}#}
{# <option value="{{ c.pk }}" {% if realty_form.building_classification.value|int == c.pk %}selected="selected"{% endif %}>{{ c.name }}</option>#} {# <option value="{{ c.pk }}" {% if realty_form.building_classification.value|int == c.pk %}selected="selected"{% endif %}>{{ c.name }}</option>#}
{# {% endfor %}#} {# {% endfor %}#}
{# </select>#} {# </select>#}
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
<select <select
@ -251,13 +303,18 @@
class="selectpicker" class="selectpicker"
name="{{ realty_form.construction_type.html_name }}"> name="{{ realty_form.construction_type.html_name }}">
{% for t in realty_form.construction_type.field.queryset %} {% for t in realty_form.construction_type.field.queryset %}
<option value="{{ t.pk }}" {% if realty_form.construction_type.value|int == t.pk %}selected="selected"{% endif %}>{{ t.name }}</option> <option value="{{ t.pk }}"
{% if realty_form.construction_type.value|int == t.pk %}selected="selected"{% endif %}>{{ t.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
</div> </div>
<div class="titleF1 disTab"> <div class="titleF1 disTab">
<div class="col-lg-12">Местоположение <span data-tooltip data-placement="{% tooltip_placement pk=18 %}" title="{% tooltip pk=18 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span> <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ realty_form.location.errors.as_text }}</span></div> <div class="col-lg-12">Местоположение <span data-tooltip data-placement="{% tooltip_placement pk=18 %}"
title="{% tooltip pk=18 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span>
<span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ realty_form.location.errors.as_text }}</span></div>
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="polsF1 polsF2 disTab">
<div> <div>
@ -274,11 +331,14 @@
</div> </div>
</div> </div>
<input type="hidden" id="chosenLocationId" name="{{ realty_form.location.html_name }}" value="{{ realty_form.location.value }}"> <input type="hidden" id="chosenLocationId" name="{{ realty_form.location.html_name }}"
value="{{ realty_form.location.value }}">
<div class="col-lg-3 make-new"> <div class="col-lg-3 make-new">
<label>{{ form.cro }}<span></span></label> <label>{{ form.cro }}<span></span></label>
<p>Требуется допуск (СРО) <span data-tooltip data-placement="{% tooltip_placement pk=17 %}" title="{% tooltip pk=17 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span></p> <p>Требуется допуск (СРО) <span data-tooltip data-placement="{% tooltip_placement pk=17 %}"
title="{% tooltip pk=17 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span></p>
</div> </div>
</div> </div>
</div> </div>
@ -302,14 +362,15 @@
// Project work type suggestion modal --------------------------------- // Project work type suggestion modal ---------------------------------
;(function() { ;
(function () {
var $modal = $('#projectWorkTypeSuggestionModal') var $modal = $('#projectWorkTypeSuggestionModal')
var $form = $modal.find('.-project-work-type-suggestion-form').first() var $form = $modal.find('.-project-work-type-suggestion-form').first()
var workTypeSuggestionUrl = '/projects/suggest-work-type/' var workTypeSuggestionUrl = '/projects/suggest-work-type/'
$modal.find('.-action-button').first().on('click', function($evt) { $modal.find('.-action-button').first().on('click', function ($evt) {
$.post(workTypeSuggestionUrl, $form.serialize()) $.post(workTypeSuggestionUrl, $form.serialize())
.then(function(res) { .then(function (res) {
if (res.status === 'success') { if (res.status === 'success') {
$form.trigger('reset') $form.trigger('reset')
$('.-error').text('') $('.-error').text('')
@ -319,7 +380,7 @@
_.flow( _.flow(
_.toPairs, _.toPairs,
_.each(function(pair) { _.each(function (pair) {
var cssSelector = pair[0] var cssSelector = pair[0]
var errors = pair[1] var errors = pair[1]
@ -336,8 +397,11 @@
// Scroll to first form validation error --------------------------- // Scroll to first form validation error ---------------------------
;(function() { ;
var hash = $('.-validation-error').filter(function(i, el) {return $(el).text()}).first().attr('id') (function () {
var hash = $('.-validation-error').filter(function (i, el) {
return $(el).text()
}).first().attr('id')
if (hash) if (hash)
window.location.hash = hash window.location.hash = hash

@ -1,8 +1,11 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load i18n %}
{% block head_css %} {% block head_css %}
<style> <style>
.-error, .errorlist {color: red} .-error, .errorlist {
color: red
}
</style> </style>
{% endblock %} {% endblock %}
@ -17,7 +20,8 @@
<p class="titleScore">Изменение проекта</p> <p class="titleScore">Изменение проекта</p>
</div> </div>
<form action="{% url 'projects:customer-project-edit' pk=pk %}" method="POST" enctype="multipart/form-data" novalidate class="-spec-work-type-combo-container"> <form action="{% url 'projects:customer-project-edit' pk=pk %}" method="POST" enctype="multipart/form-data"
novalidate class="-spec-work-type-combo-container">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=pk %}"> <input type="hidden" name="next" value="{% url 'projects:detail' pk=pk %}">
@ -32,12 +36,14 @@
{% endif %} {% endif %}
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Название заказа <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.name.errors.as_text }}</span></p> <p>Название заказа <span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.name.errors.as_text }}</span></p>
<input type="text" class="box-sizing" name="{{ form.name.html_name }}" value="{{ form.name.value }}"> <input type="text" class="box-sizing" name="{{ form.name.html_name }}" value="{{ form.name.value }}">
</div> </div>
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Подробно опишите задание <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.text.errors.as_text }}</span></p> <p>Подробно опишите задание <span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.text.errors.as_text }}</span></p>
<textarea name="{{ form.text.html_name }}" id="text-new">{{ form.text.value }}</textarea> <textarea name="{{ form.text.html_name }}" id="text-new">{{ form.text.value }}</textarea>
</div> </div>
</div> </div>
@ -54,21 +60,25 @@
<ul class="list-new-new"> <ul class="list-new-new">
{% for file in form.files.field.queryset.all %} {% for file in form.files.field.queryset.all %}
<li class="existing-file-widget"> <li class="existing-file-widget">
<input type="checkbox" name="{{ form.files.html_name }}" value="{{ file.pk }}" checked style='display: none'> <input type="checkbox" name="{{ form.files.html_name }}" value="{{ file.pk }}" checked
style='display: none'>
<p class="file-upload-label">{{ file.file.name|basename }} {{ file.file.size|filesizeformat }}</p> <p class="file-upload-label">{{ file.file.name|basename }} {{ file.file.size|filesizeformat }}</p>
<div class="existing-file-remove-btn"></div> <div class="existing-file-remove-btn"></div>
</li> </li>
{% endfor %} {% endfor %}
<li class="file-upload-widget" style="display: none"> <li class="file-upload-widget" style="display: none">
<input type="file" name="new_files" class="file-upload-input" style="position: absolute; top: -1000px; left: -1000px"> <input type="file" name="new_files" class="file-upload-input"
style="position: absolute; top: -1000px; left: -1000px">
<p class="file-upload-label"></p> <p class="file-upload-label"></p>
<div class="file-upload-remove-btn"></div> <div class="file-upload-remove-btn"></div>
</li> </li>
</ul> </ul>
</div> </div>
<p class="type-work">Тип работы <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.work_type.errors.as_text }}</span></p> <p class="type-work">{% trans 'project_stage0' %} <span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.work_type.errors.as_text }}</span>
</p>
<div class="mail-block type-work-inset -project-work-type-radios-container"> <div class="mail-block type-work-inset -project-work-type-radios-container">
{% for id, text in form.work_type.field.choices %} {% for id, text in form.work_type.field.choices %}
<div class="inset-mb"> <div class="inset-mb">
@ -87,7 +97,8 @@
{% endfor %} {% endfor %}
</div> </div>
<div class="textAreaBlock2 box-sizing disTab"> <div class="textAreaBlock2 box-sizing disTab">
<a href="#" onclick="return false" data-toggle="modal" data-target="#projectWorkTypeSuggestionModal" class="new-link new-lw">+ Добавить раздел</a> <a href="#" onclick="return false" data-toggle="modal" data-target="#projectWorkTypeSuggestionModal"
class="new-link new-lw">+ Добавить раздел</a>
</div> </div>
</div> </div>
</div> </div>
@ -95,34 +106,42 @@
<div class="filter clearfix"> <div class="filter clearfix">
<div class="polsF1 disTab"> <div class="polsF1 disTab">
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Стадия проекта <span data-tooltip data-placement="{% tooltip_placement pk=7 %}" title="{% tooltip pk=7 %}" class="-green-glyphicon glyphicon glyphicon-question-sign"></span> <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.specialization.errors.as_text }}</span></div> <div class="-bold">{% trans 'project_stage1' %} <span data-tooltip
data-placement="{% tooltip_placement pk=7 %}"
title="{% tooltip pk=7 %}"
class="-green-glyphicon glyphicon glyphicon-question-sign"></span>
<span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.specialization.errors.as_text }}</span></div>
<input type="hidden" class="-spec-select -spec-select-level-1" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-1" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold"><span class="-dynamic-label">Стадия проекта</span></div> <div class="-bold"><span class="-dynamic-label">{% trans 'project_stage2' %}</span></div>
<input type="hidden" class="-spec-select -spec-select-level-2" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-2" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Раздел</div> <div class="-bold">{% trans 'project_stage3' %}</div>
<input type="hidden" class="-spec-select -spec-select-level-3" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-3" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Подраздел</div> <div class="-bold">{% trans 'project_stage4' %}</div>
<input type="hidden" class="-spec-select -spec-select-level-4" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-4" style="width: 100%">
</div> </div>
<input type="hidden" name="{{ form.specialization.html_name }}" value="{{ form.specialization.value }}" class="-chosen-spec-id"> <input type="hidden" name="{{ form.specialization.html_name }}" value="{{ form.specialization.value }}"
class="-chosen-spec-id">
</div> </div>
<div class="titleF1 titleF2 disTab"> <div class="titleF1 titleF2 disTab">
<div class="col-lg-12">Бюджет <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.budget.errors.as_text }}</span></div> <div class="col-lg-12">Бюджет <span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.budget.errors.as_text }}</span></div>
<!--<div class="col-lg-8"></div>--> <!--<div class="col-lg-8"></div>-->
</div> </div>
<div class="searchF1 polsF1 polsFF"> <div class="searchF1 polsF1 polsFF">
<div class="col-lg-4"> <div class="col-lg-4">
<input type="text" class="box-sizing surr" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}"> <input type="text" class="box-sizing surr" name="{{ form.budget.html_name }}"
value="{{ form.budget.value }}">
{{ form.currency }} {{ form.currency }}
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
@ -154,7 +173,9 @@
<p>Сделать для исполнителей обязательным для заполнения поля цена и срок</p> <p>Сделать для исполнителей обязательным для заполнения поля цена и срок</p>
</div> </div>
<div class="titleF1 titleF2 disTab"> <div class="titleF1 titleF2 disTab">
<div class="col-lg-12">Способ оплаты <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.deal_type.errors.as_text }}</span></div> <div class="col-lg-12">Способ оплаты <span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ form.deal_type.errors.as_text }}</span>
</div>
</div> </div>
<div class="searchF1 polsF1 polsFF radio-afer"> <div class="searchF1 polsF1 polsFF radio-afer">
<div class="col-lg-6"> <div class="col-lg-6">
@ -199,10 +220,6 @@
</div> </div>
<div class="resSearchF1"> <div class="resSearchF1">
<div class="col-lg-3"> <div class="col-lg-3">
<p class="titleResF1">Расширенный поиск</p> <p class="titleResF1">Расширенный поиск</p>
@ -216,10 +233,18 @@
</div> </div>
<div class="slideRes disTab activeSlide"> <div class="slideRes disTab activeSlide">
<div class="titleF1 disTab"> <div class="titleF1 disTab">
<div class="col-lg-3">Выбор объекта<br><span id="{% random_ident %}" class="-validation-error" style="color: red">{{ form.realty.errors.as_text }}</span></div> <div class="col-lg-3">Выбор объекта<br><span id="{% random_ident %}" class="-validation-error"
<div class="col-lg-3">Наименование<br><span id="{% random_ident %}" class="-validation-error" style="color: red">{{ realty_form.name.errors.as_text }}</span></div> style="color: red">{{ form.realty.errors.as_text }}</span>
<div class="col-lg-3">Классификация здания<br><span id="{% random_ident %}" class="-validation-error" style="color: red">{{ realty_form.building_classification.errors.as_text }}</span></div> </div>
<div class="col-lg-3">Вид строительства<br><span id="{% random_ident %}" class="-validation-error" style="color: red">{{ realty_form.construction_type.errors.as_text }}</span></div> <div class="col-lg-3">Наименование<br><span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ realty_form.name.errors.as_text }}</span>
</div>
<div class="col-lg-3">Классификация здания<br><span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ realty_form.building_classification.errors.as_text }}</span>
</div>
<div class="col-lg-3">Вид строительства<br><span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ realty_form.construction_type.errors.as_text }}</span>
</div>
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="polsF1 polsF2 disTab">
@ -231,7 +256,8 @@
<option value="" {% if not form.realty.value %}selected="selected"{% endif %}>Создать новый</option> <option value="" {% if not form.realty.value %}selected="selected"{% endif %}>Создать новый</option>
{% for r in form.realty.field.queryset %} {% for r in form.realty.field.queryset %}
<option value="{{ r.pk }}" {% if form.realty.value|int == r.pk %}selected="selected"{% endif %}>{{ r.name }}</option> <option value="{{ r.pk }}"
{% if form.realty.value|int == r.pk %}selected="selected"{% endif %}>{{ r.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -249,7 +275,8 @@
class="selectpicker" class="selectpicker"
name="{{ realty_form.building_classification.html_name }}"> name="{{ realty_form.building_classification.html_name }}">
{% for c in realty_form.building_classification.field.queryset %} {% for c in realty_form.building_classification.field.queryset %}
<option value="{{ c.pk }}" {% if realty_form.building_classification.value|int == c.pk %}selected="selected"{% endif %}>{{ c.name }}</option> <option value="{{ c.pk }}"
{% if realty_form.building_classification.value|int == c.pk %}selected="selected"{% endif %}>{{ c.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -259,13 +286,16 @@
class="selectpicker" class="selectpicker"
name="{{ realty_form.construction_type.html_name }}"> name="{{ realty_form.construction_type.html_name }}">
{% for t in realty_form.construction_type.field.queryset %} {% for t in realty_form.construction_type.field.queryset %}
<option value="{{ t.pk }}" {% if realty_form.construction_type.value|int == t.pk %}selected="selected"{% endif %}>{{ t.name }}</option> <option value="{{ t.pk }}"
{% if realty_form.construction_type.value|int == t.pk %}selected="selected"{% endif %}>{{ t.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
</div> </div>
<div class="titleF1 disTab"> <div class="titleF1 disTab">
<div class="col-lg-12">Местоположение <span id="{% random_ident %}" class="-validation-error" style="color: red">{{ realty_form.location.errors.as_text }}</span></div> <div class="col-lg-12">Местоположение <span id="{% random_ident %}" class="-validation-error"
style="color: red">{{ realty_form.location.errors.as_text }}</span>
</div>
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="polsF1 polsF2 disTab">
<div class="col-lg-3"> <div class="col-lg-3">
@ -280,7 +310,8 @@
<input type="hidden" class="-location-select -location-select-city" style="width: 100%"> <input type="hidden" class="-location-select -location-select-city" style="width: 100%">
</div> </div>
<input type="hidden" id="chosenLocationId" name="{{ realty_form.location.html_name }}" value="{{ realty_form.location.value }}"> <input type="hidden" id="chosenLocationId" name="{{ realty_form.location.html_name }}"
value="{{ realty_form.location.value }}">
<div class="col-lg-3 make-new"> <div class="col-lg-3 make-new">
<label> <label>
@ -315,14 +346,15 @@
// Project work type suggestion modal --------------------------------- // Project work type suggestion modal ---------------------------------
;(function() { ;
(function () {
var $modal = $('#projectWorkTypeSuggestionModal') var $modal = $('#projectWorkTypeSuggestionModal')
var $form = $modal.find('.-project-work-type-suggestion-form').first() var $form = $modal.find('.-project-work-type-suggestion-form').first()
var workTypeSuggestionUrl = '/projects/suggest-work-type/' var workTypeSuggestionUrl = '/projects/suggest-work-type/'
$modal.find('.-action-button').first().on('click', function($evt) { $modal.find('.-action-button').first().on('click', function ($evt) {
$.post(workTypeSuggestionUrl, $form.serialize()) $.post(workTypeSuggestionUrl, $form.serialize())
.then(function(res) { .then(function (res) {
if (res.status === 'success') { if (res.status === 'success') {
console.log('Success') console.log('Success')
$form.trigger('reset') $form.trigger('reset')
@ -335,7 +367,7 @@
_.flow( _.flow(
_.toPairs, _.toPairs,
_.each(function(pair) { _.each(function (pair) {
var cssSelector = pair[0] var cssSelector = pair[0]
var errors = pair[1] var errors = pair[1]
@ -352,8 +384,11 @@
// Scroll to first form validation error ------------------------------ // Scroll to first form validation error ------------------------------
;(function() { ;
var hash = $('.-validation-error').filter(function(i, el) {return $(el).text()}).first().attr('id') (function () {
var hash = $('.-validation-error').filter(function (i, el) {
return $(el).text()
}).first().attr('id')
if (hash) if (hash)
window.location.hash = hash window.location.hash = hash

@ -7,7 +7,8 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form action="{% url 'projects:suggest-work-type' %}" method="POST" novalidate class="-project-work-type-suggestion-form"> <form action="{% url 'projects:suggest-work-type' %}" method="POST" novalidate
class="-project-work-type-suggestion-form">
{% csrf_token %} {% csrf_token %}
<div>{{ work_type_suggestion_form.non_field_errors }}</div> <div>{{ work_type_suggestion_form.non_field_errors }}</div>

@ -23,7 +23,6 @@
</div> </div>
<div class="polsF1 disTab"> <div class="polsF1 disTab">
<div class="col-lg-3"> <div class="col-lg-3">
<input type='hidden' class="-spec-select -spec-select-level-1" style="width: 100%"> <input type='hidden' class="-spec-select -spec-select-level-1" style="width: 100%">

@ -46,7 +46,8 @@
</div> </div>
</a> </a>
<p class="nameExecutor"> <p class="nameExecutor">
<a href="{% url 'users:customer-profile-open-projects' project.customer.pk %}">{{ project.customer.get_full_name }} [{{ project.customer.username }}]</a> <a href="{% url 'users:customer-profile-open-projects' project.customer.pk %}">{{ project.customer.get_full_name }}
[{{ project.customer.username }}]</a>
</p> </p>
<p class="navv2">На сайте {{ project.created|naturaltime }}</p> <p class="navv2">На сайте {{ project.created|naturaltime }}</p>
@ -115,7 +116,8 @@
<p class="textProIn"> <p class="textProIn">
{{ project.text|linebreaksbr }} {{ project.text|linebreaksbr }}
</p> </p>
</div> br </div>
br
<div class="col-lg-10 col-lg-offset-1" style="margin-top: 15px;"> <div class="col-lg-10 col-lg-offset-1" style="margin-top: 15px;">
@ -124,7 +126,8 @@
{% for file in project.files.all %} {% for file in project.files.all %}
<li class="existing-file-widget"> <li class="existing-file-widget">
<a href="{{ file }}" class="file-upload-label">{{ file.file.name|basename }} {{ file.file.size|filesizeformat }}</a> <a href="{{ file }}"
class="file-upload-label">{{ file.file.name|basename }} {{ file.file.size|filesizeformat }}</a>
</li> </li>
{% endfor %} {% endfor %}
</p> </p>
@ -154,7 +157,8 @@
</div> </div>
{% endif %} {% endif %}
{% elif request.user.is_customer and request.user == project.customer %} {% elif request.user.is_customer and request.user == project.customer %}
<a href="{% url 'projects:customer-project-edit' pk=project.pk %}?back={{ request.path }}" class="linkProIn linkProIn1"> <a href="{% url 'projects:customer-project-edit' pk=project.pk %}?back={{ request.path }}"
class="linkProIn linkProIn1">
Редактировать Редактировать
</a> </a>
@ -230,7 +234,8 @@
</a> </a>
<p class="nameExecutor"> <p class="nameExecutor">
<a href="{% url 'users:contractor-profile' pk=answer.author.pk %}">{{ answer.author.get_full_name }} [{{ answer.author.username }}]</a> <a href="{% url 'users:contractor-profile' pk=answer.author.pk %}">{{ answer.author.get_full_name }}
[{{ answer.author.username }}]</a>
</p> </p>
{% elif answer.author|class_name == 'Team' %} {% elif answer.author|class_name == 'Team' %}
<a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe"> <a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe">
@ -304,7 +309,8 @@
<form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}"> <input type="hidden" name="next" value="{{ request.path }}">
<a href="#" class="candLink candLink3 reject-project-link-contractor" title="{{ answer.pk }}">отказ</a> <a href="#" class="candLink candLink3 reject-project-link-contractor"
title="{{ answer.pk }}">отказ</a>
</form> </form>
{% if project.order.contractor and project.order.contractor == answer.author %} {% if project.order.contractor and project.order.contractor == answer.author %}
@ -313,29 +319,26 @@
<a href="/chat/#order{{ project.order.pk }}" class="candLink candLink2">Перейти к обсуждению</a> <a href="/chat/#order{{ project.order.pk }}" class="candLink candLink2">Перейти к обсуждению</a>
{% else %} {% else %}
{% if answer.author|class_name == 'User' %} {% if answer.author|class_name == 'User' %}
<a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.pk }}" class="candLink candLink2">Перейти к обсуждению</a> <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.pk }}" class="candLink candLink2">Перейти
{% elif answer.author|class_name == 'Team'%} к обсуждению</a>
<a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.owner.pk }}" class="candLink candLink2">Перейти к обсуждению</a> {% elif answer.author|class_name == 'Team' %}
<a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.owner.pk }}"
class="candLink candLink2">Перейти к обсуждению</a>
{% endif %} {% endif %}
{% endif %} {% endif %}
</div> </div>
<div class="col-xs-12"> <div class="col-xs-12">
<ul> <ul>
{% for answer_file in answer.files.all %} {% for answer_file in answer.files.all %}
<li><a href="{{ answer_file.file.url }}">{{ answer_file.name }}</a> <span>{{ answer_file.file.size|filesizeformat }}</span></li> <li><a href="{{ answer_file.file.url }}">{{ answer_file.name }}</a>
<span>{{ answer_file.file.size|filesizeformat }}</span></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
<div class="gallMini disTab"> <div class="gallMini disTab">
{% for portf in answer.portfolios.all %} {% for portf in answer.portfolios.all %}
<div class="col-lg-3"> <div class="col-lg-3">
@ -349,13 +352,11 @@
</div> </div>
<div id="contractor-answers" class="commBlock44 disTab"> <div id="contractor-answers" class="commBlock44 disTab">
{% for message in answer.messages.all %} {% for message in answer.messages.all %}
<div class="comm44 disTab"> <div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1 {% if not message.is_sender_customer %}-highlighted-message{% endif %}"> <div
class="col-lg-10 col-lg-offset-1 {% if not message.is_sender_customer %}-highlighted-message{% endif %}">
{% if message.is_sender_customer %} {% if message.is_sender_customer %}
<p class="nameComm"> <p class="nameComm">
{% firstof project.customer.get_full_name.strip project.customer.username %} {% firstof project.customer.get_full_name.strip project.customer.username %}
@ -385,10 +386,13 @@
<div class="col-lg-10 col-lg-offset-1"> <div class="col-lg-10 col-lg-offset-1">
<form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}#contractor-answers"> <input type="hidden" name="next"
value="{% url 'projects:detail' pk=project.pk %}#contractor-answers">
<div><textarea name="text" class="fr_answer"></textarea></div> <div><textarea name="text" class="fr_answer"></textarea></div>
<div><button type="submit" class="fr_answer_sen">Отправить</button></div> <div>
<button type="submit" class="fr_answer_sen">Отправить</button>
</div>
</form> </form>
</div> </div>
</div> </div>
@ -396,7 +400,8 @@
</div> </div>
</div> </div>
{% else %} {% else %}
<form action="{% url 'projects:detail' pk=project.pk %}" method="POST" enctype="multipart/form-data" novalidate class="proj_answ_form -project-answer-form" style="display: none"> <form action="{% url 'projects:detail' pk=project.pk %}" method="POST" enctype="multipart/form-data"
novalidate class="proj_answ_form -project-answer-form" style="display: none">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}"> <input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}">
<input type="hidden" name="answer_as_team" value="{% if answer_as_team %}on{% endif %}"> <input type="hidden" name="answer_as_team" value="{% if answer_as_team %}on{% endif %}">
@ -411,7 +416,8 @@
<div class="col-lg-4"> <div class="col-lg-4">
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
<p class="titleResF1">Стоимость <span style="color: red">{{ form.budget.errors.as_text }}</span></p> <p class="titleResF1">Стоимость <span style="color: red">{{ form.budget.errors.as_text }}</span></p>
<input type="text" class="box-sizing" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}"> <input type="text" class="box-sizing" name="{{ form.budget.html_name }}"
value="{{ form.budget.value }}">
</div> </div>
</div> </div>
@ -486,12 +492,14 @@
<div class="col-lg-12"> <div class="col-lg-12">
<div id="fileUploadContainer"> <div id="fileUploadContainer">
<div> <div>
<button type="button" id="fileUploadAddBtn">Добавить файл</button> Не более 10 файлов общим объемом до 500 Мб <button type="button" id="fileUploadAddBtn">Добавить файл</button>
Не более 10 файлов общим объемом до 500 Мб
</div> </div>
<ul class="list-new-new"> <ul class="list-new-new">
<li class="file-upload-widget" style="display: none"> <li class="file-upload-widget" style="display: none">
<input type="file" name="new_files" class="file-upload-input" style="position: absolute; top: -1000px; left: -1000px"> <input type="file" name="new_files" class="file-upload-input"
style="position: absolute; top: -1000px; left: -1000px">
<span class="file-upload-label"></span> <span class="file-upload-label"></span>
<a href="#" onclick="return false" class="file-upload-remove-btn">&times;</a> <a href="#" onclick="return false" class="file-upload-remove-btn">&times;</a>
</li> </li>
@ -604,7 +612,8 @@
</a> </a>
<p class="nameExecutor"> <p class="nameExecutor">
<a href="{% url 'users:contractor-profile' pk=answer.author.pk %}">{{ answer.author.get_full_name }} [{{ answer.author.username }}]</a> <a href="{% url 'users:contractor-profile' pk=answer.author.pk %}">{{ answer.author.get_full_name }}
[{{ answer.author.username }}]</a>
</p> </p>
{% elif answer.author|class_name == 'Team' %} {% elif answer.author|class_name == 'Team' %}
<a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe"> <a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe">
@ -636,7 +645,7 @@
<div class="col-lg-3 retts"> <div class="col-lg-3 retts">
{% if answer.author|class_name == 'User' %} {% if answer.author|class_name == 'User' %}
{% ratings_widget answer.author.pk 'restList2' %} {% ratings_widget answer.author.pk 'restList2' %}
{% elif answer.author|class_name == 'Team'%} {% elif answer.author|class_name == 'Team' %}
{% ratings_team_widget answer.author.pk 'restList2' %} {% ratings_team_widget answer.author.pk 'restList2' %}
{% endif %} {% endif %}
@ -673,7 +682,8 @@
<div class="col-lg-3 retts"> <div class="col-lg-3 retts">
{% if answer.author not in project|get_candidates %} {% if answer.author not in project|get_candidates %}
<a href="{% url 'projects:add-candidate' answer_id=answer.pk project_id=project.pk %}" class="candLink candLink1"> <a href="{% url 'projects:add-candidate' answer_id=answer.pk project_id=project.pk %}"
class="candLink candLink1">
Кандидат Кандидат
</a> </a>
{% endif %} {% endif %}
@ -683,12 +693,15 @@
{% elif project.order.team and project.order.team == answer.author %} {% elif project.order.team and project.order.team == answer.author %}
<a href="/chat/#order{{ project.order.pk }}" class="candLink candLink2">Перейти к обсуждению</a> <a href="/chat/#order{{ project.order.pk }}" class="candLink candLink2">Перейти к обсуждению</a>
{% elif not project.order.contractor and not project.order.team %} {% elif not project.order.contractor and not project.order.team %}
<form action="{% url 'projects:customer-offer-order' answer_id=answer.pk project_id=project.pk %}" method="POST" novalidate> <form
action="{% url 'projects:customer-offer-order' answer_id=answer.pk project_id=project.pk %}"
method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<a href="#" <a href="#"
data-sender-id="{{ request.user.pk }}" data-sender-id="{{ request.user.pk }}"
data-recipent-id="{% if answer.author|class_name == 'User' %}{{ answer.author.pk }}{% elif answer.author|class_name == 'Team'%}{{ answer.author.owner.pk }}{% endif %}" data-recipent-id="
{% if answer.author|class_name == 'User' %}{{ answer.author.pk }}{% elif answer.author|class_name == 'Team' %}{{ answer.author.owner.pk }}{% endif %}"
data-order-id="{{ project.order.id }}" data-order-id="{{ project.order.id }}"
data-order-name="{{ project.name }}" data-order-name="{{ project.name }}"
@ -697,18 +710,19 @@
</a> </a>
</form> </form>
{% else %} {% else %}
{# {% if answer.author|class_name == 'User' %}#} {# {% if answer.author|class_name == 'User' %}#}
{# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#} {# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#}
{# {% elif answer.author|class_name == 'Team'%}#} {# {% elif answer.author|class_name == 'Team'%}#}
{# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.owner.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#} {# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.owner.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#}
{# {% endif %}#} {# {% endif %}#}
{% endif %} {% endif %}
<form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}"> <input type="hidden" name="next" value="{{ request.path }}">
<a href="#" data-sender-id="{{ request.user.pk }}" <a href="#" data-sender-id="{{ request.user.pk }}"
data-recipent-id="{% if answer.author|class_name == 'User' %}{{ answer.author.pk }}{% elif answer.author|class_name == 'Team'%}{{ answer.author.owner.pk }}{% endif %}" data-recipent-id="
{% if answer.author|class_name == 'User' %}{{ answer.author.pk }}{% elif answer.author|class_name == 'Team' %}{{ answer.author.owner.pk }}{% endif %}"
data-order-name="{{ project.name }}" data-order-name="{{ project.name }}"
data-project-id="{{ project.pk }}" data-project-id="{{ project.pk }}"
class="candLink candLink3 reject-project-link" title="{{ answer.pk }}">отказ</a> class="candLink candLink3 reject-project-link" title="{{ answer.pk }}">отказ</a>
@ -718,7 +732,8 @@
<div class="col-xs-12"> <div class="col-xs-12">
<ul> <ul>
{% for answer_file in answer.files.all %} {% for answer_file in answer.files.all %}
<li><a href="{{ answer_file.file.url }}">{{ answer_file.name }}</a> <span>{{ answer_file.file.size|filesizeformat }}</span></li> <li><a href="{{ answer_file.file.url }}">{{ answer_file.name }}</a>
<span>{{ answer_file.file.size|filesizeformat }}</span></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -727,7 +742,8 @@
{% for portf in answer.portfolios.all %} {% for portf in answer.portfolios.all %}
<div class="col-lg-3"> <div class="col-lg-3">
<div class="insetCol box-sizing disTab"> <div class="insetCol box-sizing disTab">
<div class="imgGal" style="background: url('{{ portf.photos.first.img.url }}') no-repeat center"> <div class="imgGal"
style="background: url('{{ portf.photos.first.img.url }}') no-repeat center">
<div class="imgFigure"></div> <div class="imgFigure"></div>
</div> </div>
</div> </div>
@ -738,7 +754,8 @@
<div class="commBlock44 disTab"> <div class="commBlock44 disTab">
{% for message in answer.messages.all %} {% for message in answer.messages.all %}
<div class="comm44 disTab"> <div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1 {% if message.is_sender_customer %}-highlighted-message{% endif %}"> <div
class="col-lg-10 col-lg-offset-1 {% if message.is_sender_customer %}-highlighted-message{% endif %}">
{% if message.is_sender_customer %} {% if message.is_sender_customer %}
<p class="nameComm nameCommAct"> <p class="nameComm nameCommAct">
{% firstof project.customer.get_full_name.strip project.customer.username %} {% firstof project.customer.get_full_name.strip project.customer.username %}
@ -766,12 +783,16 @@
<div class="comm44 disTab"> <div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1"> <div class="col-lg-10 col-lg-offset-1">
<form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST"
novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}#new-answers"> <input type="hidden" name="next"
value="{% url 'projects:detail' pk=project.pk %}#new-answers">
<div><textarea name="text" class="fr_answer" title="Текст сообщения"></textarea></div> <div><textarea name="text" class="fr_answer" title="Текст сообщения"></textarea></div>
<div><button type="submit" class="fr_answer_sen">Отправить</button></div> <div>
<button type="submit" class="fr_answer_sen">Отправить</button>
</div>
</form> </form>
</div> </div>
</div> </div>
@ -782,9 +803,6 @@
</div> </div>
<div id="candidate-answers" class="tab-pane fade"> <div id="candidate-answers" class="tab-pane fade">
<div class="col-lg-12 exNew"> <div class="col-lg-12 exNew">
<p>Кандидаты</p> <p>Кандидаты</p>
@ -808,7 +826,8 @@
</a> </a>
<p class="nameExecutor"> <p class="nameExecutor">
<a href="{% url 'users:contractor-profile' pk=answer.author.pk %}">{{ answer.author.get_full_name }} [{{ answer.author.username }}]</a> <a href="{% url 'users:contractor-profile' pk=answer.author.pk %}">{{ answer.author.get_full_name }}
[{{ answer.author.username }}]</a>
</p> </p>
{% elif answer.author|class_name == 'Team' %} {% elif answer.author|class_name == 'Team' %}
<a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe"> <a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe">
@ -840,7 +859,7 @@
<div class="col-lg-3 retts"> <div class="col-lg-3 retts">
{% if answer.author|class_name == 'User' %} {% if answer.author|class_name == 'User' %}
{% ratings_widget answer.author.pk 'restList2' %} {% ratings_widget answer.author.pk 'restList2' %}
{% elif answer.author|class_name == 'Team'%} {% elif answer.author|class_name == 'Team' %}
{% ratings_team_widget answer.author.pk 'restList2' %} {% ratings_team_widget answer.author.pk 'restList2' %}
{% endif %} {% endif %}
@ -877,7 +896,8 @@
<div class="col-lg-3 retts"> <div class="col-lg-3 retts">
{% if TESTING %} {% if TESTING %}
<a href="{% url 'projects:add-candidate' answer_id=answer.pk project_id=project.pk %}" class="candLink candLink1"> <a href="{% url 'projects:add-candidate' answer_id=answer.pk project_id=project.pk %}"
class="candLink candLink1">
Кандидат Кандидат
</a> </a>
{% endif %} {% endif %}
@ -887,12 +907,15 @@
{% elif project.order.team and project.order.team == answer.author %} {% elif project.order.team and project.order.team == answer.author %}
<a href="/chat/#order{{ project.order.pk }}" class="candLink candLink2">Перейти к обсуждению</a> <a href="/chat/#order{{ project.order.pk }}" class="candLink candLink2">Перейти к обсуждению</a>
{% elif not project.order.contractor and not project.order.team %} {% elif not project.order.contractor and not project.order.team %}
<form action="{% url 'projects:customer-offer-order' answer_id=answer.pk project_id=project.pk %}" method="POST" novalidate> <form
action="{% url 'projects:customer-offer-order' answer_id=answer.pk project_id=project.pk %}"
method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<a href="#" <a href="#"
data-sender-id="{{ request.user.pk }}" data-sender-id="{{ request.user.pk }}"
data-recipent-id="{% if answer.author|class_name == 'User' %}{{ answer.author.pk }}{% elif answer.author|class_name == 'Team'%}{{ answer.author.owner.pk }}{% endif %}" data-recipent-id="
{% if answer.author|class_name == 'User' %}{{ answer.author.pk }}{% elif answer.author|class_name == 'Team' %}{{ answer.author.owner.pk }}{% endif %}"
data-order-id="{{ project.order.id }}" data-order-id="{{ project.order.id }}"
data-order-name="{{ project.name }}" data-order-name="{{ project.name }}"
class="candLink candLink2 offer-order-contractor"> class="candLink candLink2 offer-order-contractor">
@ -900,11 +923,11 @@
</a> </a>
</form> </form>
{% else %} {% else %}
{# {% if answer.author|class_name == 'User' %}#} {# {% if answer.author|class_name == 'User' %}#}
{# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#} {# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#}
{# {% elif answer.author|class_name == 'Team'%}#} {# {% elif answer.author|class_name == 'Team'%}#}
{# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.owner.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#} {# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.owner.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#}
{# {% endif %}#} {# {% endif %}#}
{% endif %} {% endif %}
<form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate>
@ -912,7 +935,8 @@
<input type="hidden" name="next" value="{{ request.path }}"> <input type="hidden" name="next" value="{{ request.path }}">
<a href="#" <a href="#"
data-sender-id="{{ request.user.pk }}" data-sender-id="{{ request.user.pk }}"
data-recipent-id="{% if answer.author|class_name == 'User' %}{{ answer.author.pk }}{% elif answer.author|class_name == 'Team'%}{{ answer.author.owner.pk }}{% endif %}" data-recipent-id="
{% if answer.author|class_name == 'User' %}{{ answer.author.pk }}{% elif answer.author|class_name == 'Team' %}{{ answer.author.owner.pk }}{% endif %}"
data-order-name="{{ project.name }}" data-order-name="{{ project.name }}"
data-project-id="{{ project.pk }}" data-project-id="{{ project.pk }}"
class="candLink candLink3 reject-project-link" title="{{ answer.pk }}">отказ class="candLink candLink3 reject-project-link" title="{{ answer.pk }}">отказ
@ -923,7 +947,8 @@
<div class="col-xs-12"> <div class="col-xs-12">
<ul> <ul>
{% for answer_file in answer.files.all %} {% for answer_file in answer.files.all %}
<li><a href="{{ answer_file.file.url }}">{{ answer_file.name }}</a> <span>{{ answer_file.file.size|filesizeformat }}</span></li> <li><a href="{{ answer_file.file.url }}">{{ answer_file.name }}</a>
<span>{{ answer_file.file.size|filesizeformat }}</span></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -932,7 +957,8 @@
{% for portf in answer.portfolios.all %} {% for portf in answer.portfolios.all %}
<div class="col-lg-3"> <div class="col-lg-3">
<div class="insetCol box-sizing disTab"> <div class="insetCol box-sizing disTab">
<div class="imgGal" style="background: url('{{ portf.photos.first.img.url }}') no-repeat center"> <div class="imgGal"
style="background: url('{{ portf.photos.first.img.url }}') no-repeat center">
<div class="imgFigure"></div> <div class="imgFigure"></div>
</div> </div>
</div> </div>
@ -943,7 +969,8 @@
<div class="commBlock44 disTab"> <div class="commBlock44 disTab">
{% for message in answer.messages.all %} {% for message in answer.messages.all %}
<div class="comm44 disTab"> <div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1 {% if message.is_sender_customer %}-highlighted-message{% endif %}"> <div
class="col-lg-10 col-lg-offset-1 {% if message.is_sender_customer %}-highlighted-message{% endif %}">
{% if message.is_sender_customer %} {% if message.is_sender_customer %}
<p class="nameComm nameCommAct"> <p class="nameComm nameCommAct">
{% firstof project.customer.get_full_name.strip project.customer.username %} {% firstof project.customer.get_full_name.strip project.customer.username %}
@ -971,11 +998,16 @@
<div class="comm44 disTab"> <div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1" style="padding:0;"> <div class="col-lg-10 col-lg-offset-1" style="padding:0;">
<form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST"
novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}#candidate-answers"> <input type="hidden" name="next"
<div><textarea style="margin-left:0;" name="text" class="fr_answer" title="Текст сообщения"></textarea></div> value="{% url 'projects:detail' pk=project.pk %}#candidate-answers">
<div><button style="margin-left:0;" type="submit" class="fr_answer_sen">Отправить</button></div> <div><textarea style="margin-left:0;" name="text" class="fr_answer"
title="Текст сообщения"></textarea></div>
<div>
<button style="margin-left:0;" type="submit" class="fr_answer_sen">Отправить</button>
</div>
</form> </form>
</div> </div>
</div> </div>
@ -986,9 +1018,6 @@
</div> </div>
<div id="rejected-answers" class="tab-pane fade"> <div id="rejected-answers" class="tab-pane fade">
<div class="col-lg-12 exNew"> <div class="col-lg-12 exNew">
<p>Отказы</p> <p>Отказы</p>
@ -1014,7 +1043,8 @@
</a> </a>
<p class="nameExecutor"> <p class="nameExecutor">
<a href="{% url 'users:contractor-profile' pk=answer.author.pk %}">{{ answer.author.get_full_name }} [{{ answer.author.username }}]</a> <a href="{% url 'users:contractor-profile' pk=answer.author.pk %}">{{ answer.author.get_full_name }}
[{{ answer.author.username }}]</a>
</p> </p>
{% elif answer.author|class_name == 'Team' %} {% elif answer.author|class_name == 'Team' %}
<a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe"> <a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe">
@ -1046,7 +1076,7 @@
<div class="col-lg-3 retts"> <div class="col-lg-3 retts">
{% if answer.author|class_name == 'User' %} {% if answer.author|class_name == 'User' %}
{% ratings_widget answer.author.pk 'restList2' %} {% ratings_widget answer.author.pk 'restList2' %}
{% elif answer.author|class_name == 'Team'%} {% elif answer.author|class_name == 'Team' %}
{% ratings_team_widget answer.author.pk 'restList2' %} {% ratings_team_widget answer.author.pk 'restList2' %}
{% endif %} {% endif %}
@ -1086,20 +1116,22 @@
<form action="{% url 'projects:restore-project-answer' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:restore-project-answer' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}"> <input type="hidden" name="next" value="{{ request.path }}">
<a href="#" onclick="$(this).closest('form').submit(); return false" class="candLink candLink1" title="{{ answer.pk }}">Восстановить</a> <a href="#" onclick="$(this).closest('form').submit(); return false" class="candLink candLink1"
title="{{ answer.pk }}">Восстановить</a>
</form> </form>
{# {% if answer.author|class_name == 'User' %}#} {# {% if answer.author|class_name == 'User' %}#}
{# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#} {# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#}
{# {% elif answer.author|class_name == 'Team'%}#} {# {% elif answer.author|class_name == 'Team'%}#}
{# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.owner.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#} {# <a href="{% url 'chat:chat-user' %}?user_id={{ answer.author.owner.pk }}" class="candLink candLink2">Перейти к обсуждению</a>#}
{# {% endif %}#} {# {% endif %}#}
</div> </div>
<div class="col-xs-12"> <div class="col-xs-12">
<ul> <ul>
{% for answer_file in answer.files.all %} {% for answer_file in answer.files.all %}
<li><a href="{{ answer_file.file.url }}">{{ answer_file.name }}</a> <span>{{ answer_file.file.size|filesizeformat }}</span></li> <li><a href="{{ answer_file.file.url }}">{{ answer_file.name }}</a>
<span>{{ answer_file.file.size|filesizeformat }}</span></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -1108,7 +1140,8 @@
{% for portf in answer.portfolios.all %} {% for portf in answer.portfolios.all %}
<div class="col-lg-3"> <div class="col-lg-3">
<div class="insetCol box-sizing disTab"> <div class="insetCol box-sizing disTab">
<div class="imgGal" style="background: url('{{ portf.photos.first.img.url }}') no-repeat center"> <div class="imgGal"
style="background: url('{{ portf.photos.first.img.url }}') no-repeat center">
<div class="imgFigure"></div> <div class="imgFigure"></div>
</div> </div>
</div> </div>
@ -1119,7 +1152,8 @@
<div class="commBlock44 disTab"> <div class="commBlock44 disTab">
{% for message in answer.messages.all %} {% for message in answer.messages.all %}
<div class="comm44 disTab"> <div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1 {% if message.is_sender_customer %}-highlighted-message{% endif %}"> <div
class="col-lg-10 col-lg-offset-1 {% if message.is_sender_customer %}-highlighted-message{% endif %}">
{% if message.is_sender_customer %} {% if message.is_sender_customer %}
<p class="nameComm nameCommAct"> <p class="nameComm nameCommAct">
{% firstof project.customer.get_full_name.strip project.customer.username %} {% firstof project.customer.get_full_name.strip project.customer.username %}
@ -1163,7 +1197,8 @@
<script> <script>
// Persistent Bootstrap tabs -------------------------------------- // Persistent Bootstrap tabs --------------------------------------
;(function() { ;
(function () {
var $allTabs = $('a[data-toggle="tab"]'); var $allTabs = $('a[data-toggle="tab"]');
var $tab = $allTabs.filter('[href="' + window.location.hash + '"]').first(); var $tab = $allTabs.filter('[href="' + window.location.hash + '"]').first();
@ -1174,7 +1209,7 @@
$tab.tab('show'); $tab.tab('show');
$tab.addClass('active'); $tab.addClass('active');
$allTabs.on('click', function() { // Better handle "shown.bs.tab" event? $allTabs.on('click', function () { // Better handle "shown.bs.tab" event?
var $tab = $(this); var $tab = $(this);
$allTabs.removeClass('active'); $allTabs.removeClass('active');
@ -1185,7 +1220,8 @@
// Toggle project answer form ----------------------------------- // Toggle project answer form -----------------------------------
;(function() { ;
(function () {
var $projectAnswerForm = $('.-project-answer-form').first(); var $projectAnswerForm = $('.-project-answer-form').first();
if ($.cookie('projectAnswerFormVisible')) { if ($.cookie('projectAnswerFormVisible')) {
@ -1204,7 +1240,7 @@
} }
$('.offer-order-contractor').on('click', function(e){ $('.offer-order-contractor').on('click', function (e) {
e.preventDefault(); e.preventDefault();
var senderId = $(this).attr('data-sender-id'); var senderId = $(this).attr('data-sender-id');
@ -1229,10 +1265,10 @@
}); });
$('.reject-project-link').on('click', function(e){ $('.reject-project-link').on('click', function (e) {
e.preventDefault(); e.preventDefault();
var projectId = $(this).attr('data-project-id'); var projectId = $(this).attr('data-project-id');
var msg = 'Вам отказано по проекту " ' + $(this).attr("data-order-name") + '" <a class="message_connect" href="http://{{ request.get_host }}/projects/'+ projectId +'/" >Перейти</a>'; var msg = 'Вам отказано по проекту " ' + $(this).attr("data-order-name") + '" <a class="message_connect" href="http://{{ request.get_host }}/projects/' + projectId + '/" >Перейти</a>';
var customerId = $(this).attr('data-sender-id'); var customerId = $(this).attr('data-sender-id');
var contractorId = $(this).attr('data-recipent-id'); var contractorId = $(this).attr('data-recipent-id');
socketMain.add_message({ socketMain.add_message({
@ -1248,7 +1284,7 @@
}); });
$('.reject-project-link-contractor').on('click', function(e){ $('.reject-project-link-contractor').on('click', function (e) {
e.preventDefault(); e.preventDefault();
$(this).closest('form').submit(); $(this).closest('form').submit();
@ -1258,11 +1294,10 @@
}()); }());
// Scroll to answers ------------------------------------- // Scroll to answers -------------------------------------
setTimeout(function() { setTimeout(function () {
if (_.includes(window.location.hash, ['#new-answers','#candidate-answers','#rejected-answers'])) { if (_.includes(window.location.hash, ['#new-answers', '#candidate-answers', '#rejected-answers'])) {
$(window).scrollTop($('.-answers-scroll-to').first().offset().top) $(window).scrollTop($('.-answers-scroll-to').first().offset().top)
} }
}, 400) }, 400)

@ -1,6 +1,6 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load common_tags %} {% load common_tags i18n %}
{% block content %} {% block content %}
{% include 'partials/header.html' %} {% include 'partials/header.html' %}
@ -18,7 +18,7 @@
<div class="titleF1 disTab"> <div class="titleF1 disTab">
<div class="col-lg-3">Тип работы</div> <div class="col-lg-3">{% trans 'project_stage0' %}</div>
</div> </div>
<div class="polsF1 disTab"> <div class="polsF1 disTab">
<div class="col-lg-3"> <div class="col-lg-3">
@ -32,23 +32,25 @@
<div class="polsF1 disTab"> <div class="polsF1 disTab">
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Стадия проекта <span style="color: red">{{ form.specialization.errors.as_text }}</span></div> <div class="-bold">{% trans 'project_stage1' %} <span
style="color: red">{{ form.specialization.errors.as_text }}</span></div>
<input type="hidden" class="-spec-select -spec-select-level-1" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-1" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold"><span class="-dynamic-label">Стадия проекта</span></div> <div class="-bold"><span class="-dynamic-label">{% trans 'project_stage2' %}</span></div>
<input type="hidden" class="-spec-select -spec-select-level-2" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-2" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Раздел</div> <div class="-bold">{% trans 'project_stage3' %}</div>
<input type="hidden" class="-spec-select -spec-select-level-3" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-3" style="width: 100%">
</div> </div>
<div class="col-lg-3 -single-spec-select"> <div class="col-lg-3 -single-spec-select">
<div class="-bold">Подраздел</div> <div class="-bold">{% trans 'project_stage4' %}</div>
<input type="hidden" class="-spec-select -spec-select-level-4" style="width: 100%"> <input type="hidden" class="-spec-select -spec-select-level-4" style="width: 100%">
</div> </div>
<input type="hidden" name="{{ form.specialization.html_name }}" value="{{ form.specialization.value }}" class="-chosen-spec-id"> <input type="hidden" name="{{ form.specialization.html_name }}" value="{{ form.specialization.value }}"
class="-chosen-spec-id">
</div> </div>
@ -75,7 +77,6 @@
</div> </div>
<div class="resSearchF1"> <div class="resSearchF1">
<div class="col-lg-3"> <div class="col-lg-3">
<p class="titleResF1">Расширенные поля</p> <p class="titleResF1">Расширенные поля</p>
@ -89,13 +90,6 @@
</div> </div>
<div class="slideRes disTab activeSlide"> <div class="slideRes disTab activeSlide">
<div class="titleF1 disTab"> <div class="titleF1 disTab">
<div class="col-lg-3">Классификация здания</div> <div class="col-lg-3">Классификация здания</div>
@ -115,9 +109,6 @@
</div> </div>
<div class="slideRes disTab activeSlide"> <div class="slideRes disTab activeSlide">
<div class="titleF1 disTab"> <div class="titleF1 disTab">
<div class="col-lg-3">Местоположение</div> <div class="col-lg-3">Местоположение</div>
@ -136,7 +127,8 @@
<input type="hidden" class="-location-select -location-select-city" style="width: 100%"> <input type="hidden" class="-location-select -location-select-city" style="width: 100%">
</div> </div>
<input type="hidden" id="chosenLocationId" name="{{ realty_form.location.html_name }}" value="{{ realty_form.location.value }}"> <input type="hidden" id="chosenLocationId" name="{{ realty_form.location.html_name }}"
value="{{ realty_form.location.value }}">
</div> </div>
<div class="sro"> <div class="sro">
@ -150,12 +142,6 @@
</div> </div>
<div class="col-lg-12"> <div class="col-lg-12">
<p class="titleScore">{{ display_msg }}</p> <p class="titleScore">{{ display_msg }}</p>
<div class="linkSort"> <div class="linkSort">
@ -166,14 +152,13 @@
{% endfor %} {% endfor %}
<input type="hidden" name="{{ form.last_order_by.html_name }}" value="{{ last_order_by }}"> <input type="hidden" name="{{ form.last_order_by.html_name }}" value="{{ last_order_by }}">
<input type="checkbox" name="{{ form.reverse_order.html_name }}" {% if reverse_order %}checked{% endif %} style="display: none"> <input type="checkbox" name="{{ form.reverse_order.html_name }}" {% if reverse_order %}checked{% endif %}
style="display: none">
</div> </div>
</div> </div>
</form> </form>
<div class="projectsBlock disTab"> <div class="projectsBlock disTab">
{% for project in projects %} {% for project in projects %}
<div class="projectPro clearfix"> <div class="projectPro clearfix">

@ -1,28 +1,33 @@
import pydash as _;
from django import template from django import template
from pprint import pprint, pformat
import pydash as _; _.map = _.map_; _.filter = _.filter_
from archilance import util
_.map = _.map_;
_.filter = _.filter_
register = template.Library() register = template.Library()
@register.filter @register.filter
def get_candidates(project): def get_candidates(project):
return tuple(c.answer.author for c in project.candidates.all()) return tuple(c.answer.author for c in project.candidates.all())
@register.filter @register.filter
def get_new_answers(project): def get_new_answers(project):
return set(project.answers.filter(rejected=False)) - set(c.answer for c in project.candidates.filter(answer__rejected=False)) return set(project.answers.filter(rejected=False)) - set(
c.answer for c in project.candidates.filter(answer__rejected=False))
@register.filter @register.filter
def get_candidate_answers(project): def get_candidate_answers(project):
return tuple(c.answer for c in project.candidates.filter(answer__rejected=False)) return tuple(c.answer for c in project.candidates.filter(answer__rejected=False))
@register.filter @register.filter
def get_rejected_answers(project): def get_rejected_answers(project):
return project.answers.filter(rejected=True) return project.answers.filter(rejected=True)
@register.filter @register.filter
def get_answer(project, contractor): def get_answer(project, contractor):
answer = _.find(project.answers.all(), lambda a: a.author == contractor) answer = _.find(project.answers.all(), lambda a: a.author == contractor)
@ -32,5 +37,4 @@ def get_answer(project, contractor):
return answer return answer
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

@ -1,5 +1,4 @@
from django.conf import urls from django.conf import urls
from django.views.generic import TemplateView
from .views import ( from .views import (
# ContractorOfferOrder, # ContractorOfferOrder,
@ -40,24 +39,29 @@ urlpatterns = [
urls.url(r'^(?P<pk>\d+)/restore/$', CustomerProjectRestoreView.as_view(), name='customer-project-restore'), urls.url(r'^(?P<pk>\d+)/restore/$', CustomerProjectRestoreView.as_view(), name='customer-project-restore'),
urls.url(r'^(?P<pk>\d+)/delete/$', CustomerProjectDeleteView.as_view(), name='customer-project-delete'), urls.url(r'^(?P<pk>\d+)/delete/$', CustomerProjectDeleteView.as_view(), name='customer-project-delete'),
urls.url(r'^create-answer-message/(?P<pk>\d+)/$', ProjectAnswerCreateMessageView.as_view(), name='create-answer-message'), urls.url(r'^create-answer-message/(?P<pk>\d+)/$', ProjectAnswerCreateMessageView.as_view(),
name='create-answer-message'),
urls.url(r'^reject-project-answer/(?P<pk>\d+)/$', RejectProjectAnswerView.as_view(), name='reject-project-answer'), urls.url(r'^reject-project-answer/(?P<pk>\d+)/$', RejectProjectAnswerView.as_view(), name='reject-project-answer'),
urls.url(r'^restore-project-answer/(?P<pk>\d+)/$', RestoreProjectAnswerView.as_view(), name='restore-project-answer'), urls.url(r'^restore-project-answer/(?P<pk>\d+)/$', RestoreProjectAnswerView.as_view(),
name='restore-project-answer'),
urls.url(r'^arbitration/create/$', ArbitrationCreateView.as_view(), name='arbitration-create'), urls.url(r'^arbitration/create/$', ArbitrationCreateView.as_view(), name='arbitration-create'),
urls.url(r'^answer/move/archive/$', ContractorAnswerArchiveView.as_view(), name='contractor-answer-archive'), urls.url(r'^answer/move/archive/$', ContractorAnswerArchiveView.as_view(), name='contractor-answer-archive'),
urls.url(r'^portfolio/create/$', contractor_portfolio_create, name='contractor-portfolio-create'), urls.url(r'^portfolio/create/$', contractor_portfolio_create, name='contractor-portfolio-create'),
urls.url(r'^portfolio/(?P<pk>\d+)/$', PortfolioDetail.as_view(), name='contractor-portfolio-detail'), urls.url(r'^portfolio/(?P<pk>\d+)/$', PortfolioDetail.as_view(), name='contractor-portfolio-detail'),
urls.url(r'^portfolio/(?P<pk>\d+)/edit/$', ContractorPortfolioUpdateView.as_view(), name='contractor-portfolio-edit'), urls.url(r'^portfolio/(?P<pk>\d+)/edit/$', ContractorPortfolioUpdateView.as_view(),
urls.url(r'^portfolio/(?P<pk>\d+)/trash/$', ContractorPortfolioTrashView.as_view(), name='contractor-portfolio-trash'), name='contractor-portfolio-edit'),
urls.url(r'^portfolio/(?P<pk>\d+)/trash/$', ContractorPortfolioTrashView.as_view(),
name='contractor-portfolio-trash'),
urls.url(r'^candidate/add/(?P<answer_id>(\d+))/(?P<project_id>(\d+))/$', add_candidate, name='add-candidate'), urls.url(r'^candidate/add/(?P<answer_id>(\d+))/(?P<project_id>(\d+))/$', add_candidate, name='add-candidate'),
urls.url(r'^candidate/delete/(?P<pk>(\d+))/$', CandidateDeleteView.as_view(), name='delete-candidate'), urls.url(r'^candidate/delete/(?P<pk>(\d+))/$', CandidateDeleteView.as_view(), name='delete-candidate'),
urls.url(r'^candidate/comparison/sort/$', sort_candidates, name='comparison-sort'), urls.url(r'^candidate/comparison/sort/$', sort_candidates, name='comparison-sort'),
urls.url(r'^candidate/comparison/(?P<pk>\d+)/$', ProjectComparisonView.as_view(), name='comparison'), urls.url(r'^candidate/comparison/(?P<pk>\d+)/$', ProjectComparisonView.as_view(), name='comparison'),
urls.url(r'^customer-offer-order/(?P<answer_id>(\d+))/(?P<project_id>(\d+))/$', CustomerOfferOrderView.as_view(), name='customer-offer-order'), urls.url(r'^customer-offer-order/(?P<answer_id>(\d+))/(?P<project_id>(\d+))/$', CustomerOfferOrderView.as_view(),
name='customer-offer-order'),
urls.url(r'^suggest-work-type/$', ProjectWorkTypeSuggestionView.as_view(), name='suggest-work-type'), urls.url(r'^suggest-work-type/$', ProjectWorkTypeSuggestionView.as_view(), name='suggest-work-type'),
] ]

@ -1,26 +1,29 @@
import json
from pprint import pformat
import natsort
import pydash as _;
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.urlresolvers import reverse, reverse_lazy from django.core.urlresolvers import reverse, reverse_lazy
from django.db.models import Q, F from django.db.models import Q
from django.http import HttpResponseForbidden, JsonResponse, HttpResponseRedirect, HttpResponse, Http404 from django.http import HttpResponseForbidden, JsonResponse, HttpResponseRedirect, HttpResponse, Http404
from django.shortcuts import render, get_object_or_404, redirect from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, CreateView, DeleteView, View, UpdateView, TemplateView, FormView from django.views.generic import DetailView, CreateView, DeleteView, View, UpdateView
from hitcount.models import HitCount from hitcount.models import HitCount
from hitcount.views import HitCountMixin from hitcount.views import HitCountMixin
from pprint import pprint, pformat
import json _.map = _.map_;
import natsort _.filter = _.filter_
import pydash as _; _.map = _.map_; _.filter = _.filter_
import re import re
from .mixins import LastAccessMixin
from archilance import util from archilance import util
from archilance.mixins import BaseMixin from archilance.mixins import BaseMixin
from common.mixins import CustomerRequiredMixin, ContractorRequiredMixin, NoCsrfMixin from common.mixins import NoCsrfMixin
from users.models import User, Team from users.models import User, Team
from work_sell.models import Picture, WorkSell, WorkSellPhoto from work_sell.models import Picture, WorkSell, WorkSellPhoto
from ratings.models import HistoryRating from ratings.models import HistoryRating
@ -36,7 +39,6 @@ from .models import (
PortfolioPhoto, PortfolioPhoto,
Project, Project,
ProjectFile, ProjectFile,
Realty,
TERM_TYPE_MORPHS, TERM_TYPE_MORPHS,
) )
@ -113,7 +115,6 @@ class ProjectDetailWithAnswerView(BaseMixin, View):
if request.POST.get('answer_as_team') == 'on': if request.POST.get('answer_as_team') == 'on':
answer_as_team = True answer_as_team = True
# Check for duplicate answers: # Check for duplicate answers:
if answer_as_team and util.has_related(request.user, 'team'): if answer_as_team and util.has_related(request.user, 'team'):
@ -123,7 +124,6 @@ class ProjectDetailWithAnswerView(BaseMixin, View):
if project.answers.filter(object_id=request.user.pk, content_type__model='user').exists(): if project.answers.filter(object_id=request.user.pk, content_type__model='user').exists():
raise PermissionDenied('Повторный отклик') raise PermissionDenied('Повторный отклик')
if answer_as_team: if answer_as_team:
form = self.form_class(request.POST, request=request, answer_as_team=True, project=project) form = self.form_class(request.POST, request=request, answer_as_team=True, project=project)
else: else:
@ -416,7 +416,8 @@ class CustomerProjectCreateView(BaseMixin, View):
return render(request, self.template_name, context) return render(request, self.template_name, context)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request=request) # Passing `request.FILES` seems unnecessary here. Files are added manually below form = self.form_class(request.POST,
request=request) # Passing `request.FILES` seems unnecessary here. Files are added manually below
form.is_valid() form.is_valid()
realty = form.cleaned_data.get('realty') realty = form.cleaned_data.get('realty')
@ -525,7 +526,8 @@ class CustomerProjectEditView(BaseMixin, View):
if form.is_valid() and realty_form.is_valid(): if form.is_valid() and realty_form.is_valid():
project = form.save(commit=False) project = form.save(commit=False)
project.customer = request.user project.customer = request.user
project.files = form.cleaned_data.get('files') # TODO: Should we somehow get rid of this explicit assignment? project.files = form.cleaned_data.get(
'files') # TODO: Should we somehow get rid of this explicit assignment?
project.save() project.save()
form.save_m2m() form.save_m2m()
@ -566,11 +568,10 @@ class CustomerProjectEditView(BaseMixin, View):
class ContractorAnswerArchiveView(View): class ContractorAnswerArchiveView(View):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
project_pk = request.POST.get('project_pk') project_pk = request.POST.get('project_pk')
user_pk = request.POST.get('user_pk') user_pk = request.POST.get('user_pk')
answer = Answer.objects.filter(project_id=project_pk,object_id=user_pk, content_type__model='user').first() answer = Answer.objects.filter(project_id=project_pk, object_id=user_pk, content_type__model='user').first()
answer.is_archive = True answer.is_archive = True
answer.save() answer.save()
redirect_to = request.POST.get('next') redirect_to = request.POST.get('next')
@ -691,7 +692,6 @@ def add_candidate(request, answer_id, project_id):
if not candidate: if not candidate:
Candidate.objects.create(answer=answer, project=project, position=count_answers) Candidate.objects.create(answer=answer, project=project, position=count_answers)
redirect_to = '%s%s' % (reverse('projects:detail', kwargs={'pk': project_id}), '#answers') redirect_to = '%s%s' % (reverse('projects:detail', kwargs={'pk': project_id}), '#answers')
return redirect(redirect_to) return redirect(redirect_to)
@ -902,5 +902,4 @@ class ProjectWorkTypeSuggestionView(View):
'form_errors': form_errors, 'form_errors': form_errors,
}) })
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))

@ -1,4 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import SpecializationRating, HistoryRating from .models import SpecializationRating, HistoryRating
admin.site.register(SpecializationRating) admin.site.register(SpecializationRating)

@ -1,7 +1,8 @@
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from users.models import User, Team
from specializations.models import Specialization from specializations.models import Specialization
from users.models import User, Team
class HistoryRating(models.Model): class HistoryRating(models.Model):
@ -32,7 +33,8 @@ class HistoryRating(models.Model):
class SpecializationRating(models.Model): class SpecializationRating(models.Model):
user = models.ForeignKey(User, related_name='specialization_rating', null=True, blank=True) user = models.ForeignKey(User, related_name='specialization_rating', null=True, blank=True)
team = models.ForeignKey(Team, related_name='specialization_rating', null=True, blank=True) team = models.ForeignKey(Team, related_name='specialization_rating', null=True, blank=True)
specialization = models.ForeignKey(Specialization, related_name='specialization_rating') # TODO: Pluralize related name specialization = models.ForeignKey(Specialization,
related_name='specialization_rating') # TODO: Pluralize related name
position = models.PositiveIntegerField(default=0) position = models.PositiveIntegerField(default=0)
def __str__(self): def __str__(self):

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

@ -1,3 +1 @@
from django.shortcuts import render
# Create your views here. # Create your views here.

@ -1,4 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import Review from .models import Review
admin.site.register(Review) admin.site.register(Review)

@ -5,4 +5,4 @@ class ReviewConfig(AppConfig):
name = 'reviews' name = 'reviews'
def ready(self): def ready(self):
import reviews.signals pass

@ -1,9 +1,9 @@
from django import forms from django import forms
from .models import Review from .models import Review
class ReviewForm(forms.ModelForm): class ReviewForm(forms.ModelForm):
class Meta: class Meta:
model = Review model = Review
@ -18,4 +18,3 @@ class ReviewForm(forms.ModelForm):
'target_customer', 'target_customer',
'from_team', 'from_team',
) )

@ -1,5 +1,5 @@
from django.db import models
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models
from django.utils import timezone from django.utils import timezone
TYPE_REVIEWS = ( TYPE_REVIEWS = (

@ -1,8 +1,7 @@
from rest_framework.serializers import ModelSerializer
from rest_framework import serializers from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from .models import Review from .models import Review
from users.serializers import UserSerializer, TeamSerializer
class ReviewSerializer(ModelSerializer): class ReviewSerializer(ModelSerializer):
@ -38,4 +37,3 @@ class ReviewSerializer(ModelSerializer):
return obj.target_contractor.pk return obj.target_contractor.pk
elif obj.target_team: elif obj.target_team:
return obj.target_team.owner.pk return obj.target_team.owner.pk

@ -1,7 +1,6 @@
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from users.models import User, Team
from ratings.models import HistoryRating from ratings.models import HistoryRating
from .models import Review from .models import Review
@ -28,4 +27,3 @@ def add_rating_review(sender, instance, created, **kwargs):
order = instance.project.order order = instance.project.order
order.status = 'completed' order.status = 'completed'
order.save() order.save()

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

@ -1,8 +1,8 @@
from django.shortcuts import render from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import ListView, CreateView, DeleteView from django.views.generic import ListView, CreateView, DeleteView
from .models import Review
from .forms import ReviewForm from .forms import ReviewForm
from .models import Review
class ReviewsView(LoginRequiredMixin, ListView): class ReviewsView(LoginRequiredMixin, ListView):

@ -6,5 +6,13 @@ from .models import Specialization
class SpecializationAdmin(MPTTModelAdmin): class SpecializationAdmin(MPTTModelAdmin):
readonly_fields = ('pk', 'lft', 'rght', 'tree_id', 'level') readonly_fields = ('pk', 'lft', 'rght', 'tree_id', 'level')
list_display = ('pk', 'name', 'order')
def get_queryset(self, request):
qs = super(SpecializationAdmin, self).get_queryset(request)
qs.order_by('order')
return qs
admin.site.register(Specialization, SpecializationAdmin) admin.site.register(Specialization, SpecializationAdmin)

@ -1,6 +1,8 @@
from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter
from .models import Specialization from .models import Specialization
class SpecializationFilterSet(FilterSet): class SpecializationFilterSet(FilterSet):
id = AllLookupsFilter() id = AllLookupsFilter()
level = AllLookupsFilter() level = AllLookupsFilter()

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-14 20:06
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('specializations', '0002_auto_20161005_0342'),
]
operations = [
migrations.AddField(
model_name='specialization',
name='order',
field=models.PositiveIntegerField(default=0),
preserve_default=False,
),
]

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-14 20:44
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('specializations', '0003_specialization_order'),
]
operations = [
migrations.AlterModelOptions(
name='specialization',
options={'get_latest_by': 'order', 'ordering': ['order'], 'verbose_name': 'Специализация', 'verbose_name_plural': 'Специализации'},
),
migrations.AddField(
model_name='specialization',
name='selectable',
field=models.BooleanField(default=True),
),
]

@ -1,11 +1,13 @@
from django.db import models from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
from mptt.managers import TreeManager from mptt.managers import TreeManager
from mptt.models import MPTTModel, TreeForeignKey
class Specialization(MPTTModel): class Specialization(MPTTModel):
name = models.CharField(max_length=500) name = models.CharField(max_length=500)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True) parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
order = models.PositiveIntegerField()
selectable = models.BooleanField(default=True)
objects = TreeManager() objects = TreeManager()
@ -13,8 +15,10 @@ class Specialization(MPTTModel):
return self.name return self.name
class Meta: class Meta:
get_latest_by = 'order'
ordering = ['order']
verbose_name = 'Специализация' verbose_name = 'Специализация'
verbose_name_plural = 'Специализации' verbose_name_plural = 'Специализации'
class MPTTMeta: class MPTTMeta:
order_insertion_by = ['name'] order_insertion_by = ['order', 'name']

@ -1,3 +1 @@
from django.test import TestCase
# Create your tests here. # Create your tests here.

@ -1,5 +1,4 @@
from django.conf import urls from django.conf import urls
# from django.contrib.auth.views import login, logout
from .views import SpecListView, SpecChildrenDetailView, test_page, test_spec from .views import SpecListView, SpecChildrenDetailView, test_page, test_spec

@ -1,10 +1,11 @@
from django.shortcuts import render from django.http import HttpResponse
from django.views.generic import ListView, DetailView
from django.http import JsonResponse from django.http import JsonResponse
from django.views.generic import ListView, DetailView
from django.views.generic import TemplateView from django.views.generic import TemplateView
from django.http import HttpResponse
from .models import Specialization from .models import Specialization
class SpecListView(ListView): class SpecListView(ListView):
model = Specialization model = Specialization
template_name = 'specializations/specialization.html' template_name = 'specializations/specialization.html'
@ -29,14 +30,18 @@ def test_page(request):
children = spec.get_children() children = spec.get_children()
return JsonResponse({"hello": 'yes'}) return JsonResponse({"hello": 'yes'})
else: else:
return JsonResponse({"hello":"python"}) return JsonResponse({"hello": "python"})
import json import json
def test_spec(request): def test_spec(request):
spec = Specialization.objects.get(pk=2) spec = Specialization.objects.get(pk=2)
children = spec.get_children() children = spec.get_children()
return HttpResponse(json.dumps(children)) return HttpResponse(json.dumps(children))
class SpecChildrenDetailView(DetailView): class SpecChildrenDetailView(DetailView):
model = Specialization model = Specialization

@ -11,8 +11,8 @@ from .models import (
class UserAdmin(admin.ModelAdmin): class UserAdmin(admin.ModelAdmin):
readonly_fields = ('pk','is_staff') readonly_fields = ('pk', 'is_staff')
list_display = ('username', 'email', 'get_groups', 'cro', 'is_active', 'rating','last_time_visit') list_display = ('username', 'email', 'get_groups', 'cro', 'is_active', 'rating', 'last_time_visit')
ordering = ('-rating',) ordering = ('-rating',)
def get_groups(self, obj): def get_groups(self, obj):

@ -5,4 +5,4 @@ class UsersConfig(AppConfig):
name = 'users' name = 'users'
def ready(self): def ready(self):
import users.signals pass

@ -1,11 +1,9 @@
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from .models import User from .models import User
class EmailOrUsernameModelBackend(object): class EmailOrUsernameModelBackend(object):
def authenticate(self, username=None, password=None): def authenticate(self, username=None, password=None):
if '@' in username: if '@' in username:
kwargs = {'email': username} kwargs = {'email': username}

@ -1,5 +1,8 @@
import pydash as _;
from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter, MethodFilter from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter, MethodFilter
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
from .models import User, Team, ContractorResumeFiles, ContractorResume from .models import User, Team, ContractorResumeFiles, ContractorResume

@ -1,11 +1,15 @@
import itertools
import pydash as _;
from django import forms from django import forms
from mptt.forms import TreeNodeChoiceField from mptt.forms import TreeNodeChoiceField
import itertools
import pydash as _; _.map = _.map_; _.filter = _.filter_ _.map = _.map_;
_.filter = _.filter_
from .models import User, UserFinancialInfo, Team, ContractorResume, ContractorResumeFiles, GENDERS from .models import User, UserFinancialInfo, Team, ContractorResume, ContractorResumeFiles, GENDERS
from common.models import Location, LiveImageUpload from common.models import Location, LiveImageUpload
from projects.models import Project, Realty, BuildingClassfication, ConstructionType from projects.models import Project, BuildingClassfication, ConstructionType
from specializations.models import Specialization from specializations.models import Specialization
@ -165,8 +169,7 @@ class ContractorFilterForm(forms.Form):
last_order_by = forms.ChoiceField(required=False, choices=CONTRACTOR_ORDER_CHOICES) last_order_by = forms.ChoiceField(required=False, choices=CONTRACTOR_ORDER_CHOICES)
reverse_order = forms.BooleanField(required=False) reverse_order = forms.BooleanField(required=False)
try: # TODO: dirty
try: #TODO: dirty
qs = Specialization.objects.root_nodes()[0].get_descendants() qs = Specialization.objects.root_nodes()[0].get_descendants()
except: except:
qs = Specialization.objects qs = Specialization.objects
@ -203,7 +206,7 @@ class ContractorFilterForm(forms.Form):
) )
work_type = forms.ChoiceField( work_type = forms.ChoiceField(
choices=tuple(itertools.chain((('',''),), Project.WORK_TYPES)), choices=tuple(itertools.chain((('', ''),), Project.WORK_TYPES)),
widget=forms.Select(attrs={'class': 'selectpicker -project-work-type-select-field'}), widget=forms.Select(attrs={'class': 'selectpicker -project-work-type-select-field'}),
required=False, required=False,
) )
@ -233,7 +236,6 @@ class ContractorFilterForm(forms.Form):
class CustomerProfileProjectRealtyForm(forms.Form): class CustomerProfileProjectRealtyForm(forms.Form):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request') self.request = kwargs.pop('request')
self.customer = kwargs.pop('customer') self.customer = kwargs.pop('customer')
@ -252,5 +254,4 @@ class CustomerProfileProjectRealtyForm(forms.Form):
required=False, required=False,
) )
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))

@ -1,15 +1,19 @@
def get_projects_grouped(contractor): def get_projects_grouped(contractor):
private_open_projects = tuple(a.project for a in contractor.contractor_answers.filter(project__state='active', rejected=False)) private_open_projects = tuple(
a.project for a in contractor.contractor_answers.filter(project__state='active', rejected=False))
try: try:
team_open_projects = tuple(a.project for a in contractor.team.answers.filter(project__state='active', rejected=False)) team_open_projects = tuple(
a.project for a in contractor.team.answers.filter(project__state='active', rejected=False))
except: except:
team_open_projects = () team_open_projects = ()
private_archived_projects = tuple(a.project for a in contractor.contractor_answers.filter(project__state='active', rejected=True)) private_archived_projects = tuple(
a.project for a in contractor.contractor_answers.filter(project__state='active', rejected=True))
try: try:
team_archived_projects = tuple(a.project for a in contractor.team.answers.filter(project__state='active', rejected=True)) team_archived_projects = tuple(
a.project for a in contractor.team.answers.filter(project__state='active', rejected=True))
except: except:
team_archived_projects = () team_archived_projects = ()

@ -0,0 +1,42 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-10-14 22:49+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: templates/contractor_filter.html:27 templates/portfolio_create_form.html:25
#: templates/worksell_create_form.html:20
msgid "project_stage0"
msgstr "Тип работы"
#: templates/contractor_filter.html:46 templates/portfolio_create_form.html:37
#: templates/worksell_create_form.html:32
msgid "project_stage1"
msgstr "Стадия проекта"
#: templates/contractor_filter.html:50 templates/portfolio_create_form.html:42
#: templates/worksell_create_form.html:37
msgid "project_stage2"
msgstr "Раздел"
#: templates/contractor_filter.html:54 templates/portfolio_create_form.html:47
#: templates/worksell_create_form.html:42
msgid "project_stage3"
msgstr "Подраздел"
#: templates/contractor_filter.html:58 templates/portfolio_create_form.html:52
#: templates/worksell_create_form.html:47
msgid "project_stage4"
msgstr "Подраздел ( доп. )"

@ -14,6 +14,5 @@ class CheckForUserMixin(object):
class OwnershipMixin(object): class OwnershipMixin(object):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
pass pass

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save