optimizations

remotes/origin/PR-39
PekopT 9 years ago
parent da3793495d
commit 669d1d5db0
  1. 1
      api/test.py
  2. 1
      api/urls.py
  3. 62
      api/views.py
  4. 10
      archilance/management/commands/generate_build_classifs.py
  5. 10
      archilance/management/commands/generate_constr_types.py
  6. 11
      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. 8
      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. 8
      archilance/urls.py
  21. 16
      archilance/util.py
  22. 24
      archilance/views.py
  23. 6
      archilance/wsgi.py
  24. 17
      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. 1
      chat/admin.py
  30. 15
      chat/chat.py
  31. 5
      chat/filters.py
  32. 1
      chat/forms.py
  33. 1
      chat/response.py
  34. 8
      chat/serializers.py
  35. 3
      chat/settings.example.py
  36. 2
      chat/tests.py
  37. 1
      chat/utils.py
  38. 34
      chat/views.py
  39. 5
      common/admin.py
  40. 6
      common/forms.py
  41. 7
      common/middleware.py
  42. 2
      common/tests.py
  43. 3
      common/urls.py
  44. 12
      common/views.py
  45. 3
      projects/apps.py
  46. 1
      projects/filters.py
  47. 21
      projects/forms.py
  48. BIN
      projects/locale/ru_RU/LC_MESSAGES/django.mo
  49. 48
      projects/locale/ru_RU/LC_MESSAGES/django.po
  50. 38
      projects/migrations/0047_auto_20161014_2349.py
  51. 29
      projects/models.py
  52. 7
      projects/serializers.py
  53. 4
      projects/signals.py
  54. 20
      projects/templates/_trash/project_form.html
  55. 10
      projects/templates/comparison.html
  56. 35
      projects/templates/contractor_portfolio_edit.html
  57. 132
      projects/templates/customer_project_create.html
  58. 99
      projects/templates/customer_project_edit.html
  59. 3
      projects/templates/partials/modals/project_work_type_suggestion.html
  60. 1
      projects/templates/portfolio_create.html
  61. 159
      projects/templates/project_detail.html
  62. 41
      projects/templates/project_filter.html
  63. 16
      projects/templatetags/project_tags.py
  64. 2
      projects/tests.py
  65. 16
      projects/urls.py
  66. 33
      projects/views.py
  67. 1
      ratings/admin.py
  68. 6
      ratings/models.py
  69. 2
      ratings/tests.py
  70. 2
      ratings/views.py
  71. 1
      reviews/admin.py
  72. 2
      reviews/apps.py
  73. 3
      reviews/forms.py
  74. 2
      reviews/models.py
  75. 4
      reviews/serializers.py
  76. 2
      reviews/signals.py
  77. 2
      reviews/tests.py
  78. 6
      reviews/views.py
  79. 8
      specializations/admin.py
  80. 2
      specializations/filters.py
  81. 21
      specializations/migrations/0003_specialization_order.py
  82. 24
      specializations/migrations/0004_auto_20161014_2344.py
  83. 8
      specializations/models.py
  84. 2
      specializations/tests.py
  85. 1
      specializations/urls.py
  86. 11
      specializations/views.py
  87. 2
      users/apps.py
  88. 2
      users/backend.py
  89. 5
      users/filters.py
  90. 13
      users/forms.py
  91. 12
      users/helpers.py
  92. BIN
      users/locale/ru_RU/LC_MESSAGES/django.mo
  93. 42
      users/locale/ru_RU/LC_MESSAGES/django.po
  94. 1
      users/mixins.py
  95. 10
      users/models.py
  96. 6
      users/pipeline.py
  97. 7
      users/serializers.py
  98. 11
      users/signals.py
  99. 11
      users/templates/contractor_filter.html
  100. 12
      users/templates/portfolio_create_form.html
  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):
pass

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

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

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
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

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
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

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
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
@ -15,7 +13,6 @@ class Command(BaseCommand):
print('Generating locations...')
print('---------------------------------------')
_root = Location.objects.create(name='_root', type='_root')
depths = ('A', 'B', 'C', 'D')

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
from django.contrib.auth.models import Group
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):
@ -14,6 +12,5 @@ class Command(BaseCommand):
print('Generating permission groups...')
print('---------------------------------------')
Group.objects.create(name='Исполнители')
Group.objects.create(name='Заказчики')

@ -1,15 +1,14 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
_.map = _.map_;
_.filter = _.filter_
from archilance import util
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 users.models import User, Team, GENDERS
from users.models import User
class Command(BaseCommand):
@ -18,7 +17,6 @@ class Command(BaseCommand):
print('Generating portfolios...')
print('---------------------------------------')
# ('photos', 'Relation? True', 'Null? True', '(relation)', 'Hidden? False'),
# ('budget', 'Relation? False', 'Null? True', 'Blank? True', '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.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(
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
from django.contrib.contenttypes.models import ContentType
import pydash as _;
from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
_.map = _.map_;
_.filter = _.filter_
from archilance import util
from projects.models import Project, Order, CURRENCIES, TERM_TYPES, Specialization, Realty
@ -16,7 +15,6 @@ class Command(BaseCommand):
print('Generating projects...')
print('---------------------------------------')
# Fields:

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
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 projects.models import Realty, BuildingClassfication, ConstructionType
from users.models import User
@ -17,7 +15,6 @@ class Command(BaseCommand):
print('Generating realties...')
print('---------------------------------------')
# # Fields:
#
#
@ -39,7 +36,8 @@ class Command(BaseCommand):
realty.building_classification = BuildingClassfication.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.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()
return realty

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

@ -1,8 +1,9 @@
import pydash as _;
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
@ -12,7 +13,6 @@ class Command(BaseCommand):
print('Generating specializations...')
print('---------------------------------------')
_root = Specialization.objects.create(name='_root')
stages = ('A', 'B', 'C', 'D')

@ -1,11 +1,9 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
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

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

@ -1,14 +1,13 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
from django.contrib.auth.models import Group
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 specializations.models import Specialization
from users.models import User, GENDERS
from users.models import User
class Command(BaseCommand):
@ -17,8 +16,6 @@ class Command(BaseCommand):
print('Generating users...')
print('---------------------------------------')
# # Fields:
#
# ('contractor_specializations', 'Relation? True', 'Null? False', '(relation)', 'Hidden? False'),
@ -91,14 +88,14 @@ class Command(BaseCommand):
users = _.times(create_user, 500)
contractor_group = Group.objects.get(name='Исполнители')
customer_group = Group.objects.get(name='Заказчики')
for user in users:
user.set_password('123')
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.save()

@ -1,16 +1,15 @@
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pydash as _;
from django.core.management import BaseCommand
from django.utils import timezone
import pydash as _; _.map = _.map_; _.filter = _.filter_
import random
_.map = _.map_;
_.filter = _.filter_
from archilance import util
from common.models import Location
from projects.models import TERM_TYPES, CURRENCIES, BuildingClassfication, ConstructionType
from specializations.models import Specialization
from users.models import User, Team
from work_sell.models import WorkSell, WorkSellPhoto
from work_sell.models import WorkSell
class Command(BaseCommand):
@ -42,7 +41,9 @@ class Command(BaseCommand):
ws.location = Location.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(
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
# import code; code.interact(local=dict(globals(), **locals()))

@ -83,6 +83,7 @@ INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS + WAGTAIL
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'archilance.middlewares.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
@ -102,7 +103,6 @@ TEMPLATES = [
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(ROOT_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
@ -237,7 +237,7 @@ FIELDS_STORED_IN_SESSION = ['user_type']
# Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/
LANGUAGE_CODE = 'ru-ru'
LANGUAGE_CODE = 'ru_RU'
TIME_ZONE = 'Europe/Moscow'
@ -247,6 +247,10 @@ USE_L10N = True
USE_TZ = True
LANGUAGES = (
('ru_RU', 'Russian'),
)
# Static files (CSS, JavaScript, Images)
# 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.staticfiles.urls import staticfiles_urlpatterns
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.wagtailcore import urls as wagtail_urls
from common.views import CustomRegistrationView
from wallets.views import TmpCheckOrderView, TmpPaymentAvisoView
from .views import HomeTemplateView, TestChatTemplateView, TestView
urlpatterns = [
url(r'^$', HomeTemplateView.as_view()),

@ -1,12 +1,16 @@
import datetime
from pprint import pprint
import natsort
import pydash as _;
from django.core import validators
from django.core.exceptions import ObjectDoesNotExist
from django.core.files.storage import FileSystemStorage
from django.shortcuts import _get_queryset
from django.utils import timezone
from pprint import pprint, pformat
import datetime
import natsort
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
import random
import string
@ -102,7 +106,8 @@ def lorem(words=None, sentences=5):
'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):
@ -153,6 +158,7 @@ def morph(number, words):
return words[choice]
# # Example:
#
# words = ['яблоко', 'яблока', 'яблок']

@ -1,22 +1,15 @@
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import PermissionDenied
import pydash as _;
from django.core.files.base import ContentFile
from django.core.urlresolvers import reverse, reverse_lazy
from django.http import HttpResponseForbidden, JsonResponse, HttpResponseRedirect, HttpResponse, Http404
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import TemplateView, View
from pprint import pprint, pformat
import json
import logging
import pydash as _; _.map = _.map_; _.filter = _.filter_
from django.shortcuts import render
from django.views.generic import View
_.map = _.map_;
_.filter = _.filter_
from .mixins import BaseMixin
from archilance import util
from chat.models import Documents
from common.models import MainPage, PrintDocuments
from projects.models import Order
from users.models import User, ContractorResumeFiles
from common.models import MainPage
from users.models import User
from work_sell.models import Picture
@ -61,5 +54,4 @@ class TestView(BaseMixin, View):
return render(request, self.template_name, context)
# return redirect('projects:detail', pk=153)
# 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/
"""
import os
from django.core.wsgi import get_wsgi_application
from django.template.base import Variable
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archilance.settings.local")
application = get_wsgi_application()
# Patch template Variable to output empty string for None values:
old_resolve_lookup = Variable._resolve_lookup
def new_resolve_lookup(self, *args, **kwargs):
val = old_resolve_lookup(self, *args, **kwargs)
return '' if val == None else val
Variable._resolve_lookup = new_resolve_lookup

@ -1073,7 +1073,7 @@ footer:after {
}
.pagin nav ul li a {
background-color: none;
background-color: transparent;
color: black;
font-size: 20px;
line-height: 50px;
@ -1099,7 +1099,6 @@ footer:after {
.pagin nav ul li a:hover,
.pagin nav ul li a:active {
color: black;
color: white;
background-color: #2c2c2c;
border-color: #2c2c2c;
@ -2560,7 +2559,7 @@ input[type="checkbox"]:checked + span {
text-align: center;
margin: 0 0 0 0;
position: relative;
letter-spacing: 0px;
letter-spacing: 0;
}
.compareBlock p:before {
@ -2986,9 +2985,8 @@ input[type="checkbox"]:checked + span {
.compTable tr td:nth-child(6) ul li:nth-child(2):before {
height: 20px;
background: url('../img/listTable.png') no-repeat center;
background-size: cover;
background-position: 0 -17px;
background: url('../img/listTable.png') no-repeat 0 -17px;
}
.compTable tr td:nth-child(7) {
@ -3005,7 +3003,6 @@ input[type="checkbox"]:checked + span {
font-weight: bold;
font-family: Arial, Verdana, Helvetica, sans-serif;
position: relative;
position: relative;
width: 100%;
float: left;
}
@ -4286,7 +4283,6 @@ input[type="checkbox"]:checked + span {
#modal_form1 {
width: 600px;
height: 400px;
display: table;
position: fixed;
top: 50%;
left: 50%;
@ -4344,7 +4340,6 @@ input[type="checkbox"]:checked + span {
width: 300px;
height: 160px;
min-height: 160px;
display: table;
position: fixed;
right: 0;
top: 50%;
@ -5438,7 +5433,7 @@ input[type="radio"]:checked + span {
font-family: Arial, Verdana, Helvetica, sans-serif;
font-size: 16px;
font-weight: bold;
margin: 0px 0 -15 0;
margin: 0px 0 -15px 0;
}
.inp-edit {
@ -5536,7 +5531,7 @@ input[type="radio"]:checked + span {
.caret:after {
content: "\e253";
position: absolute;
font-family: 'Glyphicons Halflings';
font-family: 'Glyphicons Halflings', serif;
right: -6.5px;
top: -19px;
font-size: 12px;
@ -6080,7 +6075,7 @@ input[type="radio"]{
.welcomeMain{
line-height: 48px;
font-family: 'pfdintextcomppro-regular', sans-serif;
font-size: 43.5px;
font-size: 43px;
}
.menuUser > div{
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[3].select2(_.merge(specSelectOptions, {ajax: {url: specs.urlLevel4}}))
var specLevel1 = specs.specLevel1
var specLevel2 = specs.specLevel2
var specLevel3 = specs.specLevel3
var specLevel4 = specs.specLevel4
var specLevel1 = specs.specLevel1;
var specLevel2 = specs.specLevel2;
var specLevel3 = specs.specLevel3;
var specLevel4 = specs.specLevel4;
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)

@ -1,4 +1,5 @@
from django.contrib import admin
from .models import Message, Notes, Documents, NewMessage

@ -1,13 +1,11 @@
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 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):
@ -114,7 +112,8 @@ class ChatHandler(websocket.WebSocketHandler):
if docs_send_links:
is_send = 'true'
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)
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
#
# class DocumentsFilterSet(FilterSet):
# file = AllLookupsFilter()
@ -30,17 +31,15 @@ class MessageFilterSet(FilterSet):
model = Message
class DocumentFilterSet(FilterSet):
id = AllLookupsFilter()
# order = RelatedFilter('projects.filters.OrderFilterSet')
class Meta:
model = Documents
class NoteFilterSet(FilterSet):
created = AllLookupsFilter()
id = AllLookupsFilter()

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

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

@ -1,8 +1,8 @@
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from .models import Message, Notes, Documents
from users.serializers import UserSerializer
from .models import Message, Notes, Documents
class DocumentsSerializer(ModelSerializer):
@ -44,7 +44,6 @@ class MessageSerializer(ModelSerializer):
documents = DocumentsSerializer(read_only=True, many=True)
text = serializers.SerializerMethodField()
class Meta:
model = Message
@ -63,13 +62,14 @@ class MessageSerializer(ModelSerializer):
out = obj.text
documents = obj.documents.all()
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
return out
class NoteSerializer(ModelSerializer):
class Meta:
model = Notes

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

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

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

@ -1,18 +1,19 @@
import json
from django.shortcuts import render
from wsgiref.util import FileWrapper
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 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 wallets.models import Transaction
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):
@ -57,7 +58,8 @@ class ChatUserView(LoginRequiredMixin, View):
contacts_users = User.objects.filter(pk__in=users_ids)
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))
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]
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
).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'
return render(request, self.template_name, {'contacts_users': contacts_users,
'chat_messages': chat_messages,
@ -88,8 +91,10 @@ class ChatUserView(LoginRequiredMixin, View):
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()
orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).filter(project__state='active')
archive_orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).exclude(project__state='active')
orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).filter(
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(
Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)). \
filter(is_delete=False).distinct()
@ -113,7 +118,8 @@ class ChatUserView(LoginRequiredMixin, View):
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()
self.template_name = 'chat_contractor.html'

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

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

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

@ -1,3 +1 @@
from django.test import TestCase
# 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'^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.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import Group
from django.core.exceptions import PermissionDenied
from django.core.mail import send_mail, EmailMultiAlternatives
from django.core.mail import EmailMultiAlternatives
from django.core.urlresolvers import reverse, reverse_lazy
from django.http import JsonResponse
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 registration.backends.default.views import RegistrationView
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.mixins import BaseMixin
from common.mixins import NoCsrfMixin
from users.models import ContractorResume
from .forms import PrintOrderForm, CustomRegistrationForm
from .models import PrintDocuments, PrintOrder, Settings, LiveImageUpload
class PrintOrderDetailView(DetailView):
@ -62,7 +59,6 @@ class PrintDocumentCreate(BaseMixin, View):
'files': link_files,
}
settings = Settings.objects.all().first()
subject, from_email, to = 'Заявка на распечатку', settings.noreply_email, settings.document_send_email
text_content = render_to_string('document_email.txt', ctx_dict)
@ -82,7 +78,6 @@ class PrintDocumentCreate(BaseMixin, View):
return render(request, self.template_name, context)
class LiveImageUploadCreateView(NoCsrfMixin, LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
image = request.FILES.get('image')
@ -153,5 +148,4 @@ class CustomRegistrationView(RegistrationView):
return user
# import code; code.interact(local=dict(globals(), **locals()))

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

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

@ -1,10 +1,13 @@
import itertools
import pydash as _;
from django import forms
from django.db.models import Q
from django.forms.models import inlineformset_factory
from mptt.forms import TreeNodeChoiceField
from pprint import pprint, pformat
import itertools
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
from .models import (
Project, ProjectFile, Portfolio, Answer,
@ -14,7 +17,7 @@ from .models import (
from archilance import util
from common.models import Location, LiveImageUpload
from specializations.models import Specialization
from users.models import User, Team
from users.models import Team
class ProjectFilterForm(forms.ModelForm):
@ -85,7 +88,8 @@ class ProjectFilterRealtyForm(forms.ModelForm):
self.fields['construction_type'].required = False
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
@ -184,7 +188,8 @@ class RealtyForm(forms.ModelForm):
self.fields['name'].required = False
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
@ -300,7 +305,8 @@ class ProjectAnswerForm(forms.ModelForm):
# for c in members:
# 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
else:
@ -416,5 +422,4 @@ class ProjectWorkTypeSuggestionForm(forms.ModelForm):
self['username'].field.initial = self.request.user.username
self['email'].field.initial = self.request.user.email
# 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.models import ContentType
from django.db import models
from django.db.models import Q
from django.core.exceptions import ValidationError
from django.utils import timezone
from hitcount.models import HitCountMixin
from mptt.managers import TreeManager
from mptt.models import TreeForeignKey, MPTTModel
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
from users.models import User, Team
from specializations.models import Specialization
CURRENCIES = (
('rur', 'RUR'),
('usd', 'USD'),
@ -36,22 +38,31 @@ TERM_TYPE_MORPHS = {
class BuildingClassfication(MPTTModel):
name = models.CharField(max_length=255)
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):
return self.name
class MPTTMeta:
order_insertion_by = ['order']
class Meta:
ordering = ['order']
verbose_name = 'Тип здания'
verbose_name_plural = 'Типы зданий'
class ConstructionType(models.Model):
name = models.CharField(max_length=255)
order = models.PositiveSmallIntegerField(default=0, null=True)
def __str__(self):
return self.name
class Meta:
ordering = ['order']
verbose_name = 'Вид строительства'
verbose_name_plural = 'Виды строительства'
@ -145,7 +156,9 @@ class Answer(models.Model):
is_archive = 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()
author = GenericForeignKey('content_type', 'object_id')
@ -216,7 +229,8 @@ class Order(models.Model):
('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)
project = models.OneToOneField(Project, related_name='order')
secure = models.BooleanField(default=False)
@ -238,6 +252,7 @@ class Order(models.Model):
else:
return None
class Arbitration(models.Model):
user = models.ForeignKey(User)
text = models.TextField()
@ -264,7 +279,6 @@ STATUSES = (
('completed', 'Завершен'),
)
from .validators import validate_term
class Stage(models.Model):
cost = models.DecimalField(max_digits=10, decimal_places=0)
@ -305,7 +319,8 @@ class Stage(models.Model):
class Candidate(models.Model):
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)
position = models.PositiveIntegerField(default=0)

@ -1,12 +1,13 @@
from rest_framework import serializers
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 specializations.serializers import SpecializationSerializer
from users.models import User, Team
from users.serializers import UserSerializer, TeamSerializer
from .models import Project, Realty, BuildingClassfication, ConstructionType, Order, Stage, Portfolio, PortfolioPhoto, \
Answer, AnswerFile
class AnswerFileSerializer(ModelSerializer):

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

@ -35,15 +35,15 @@
{# </div>#}
{# <input type="submit" value="Submit" />#}
{# </form>#}
<ul class="list-new-new">
<li>
Архитерурное 2.jpg
<span>7мб</span>
<div></div>
</li>
</ul>
</div>
<p class="type-work">Тип работы:</p>
{# <ul class="list-new-new">#}
{# <li>#}
{# Архитерурное 2.jpg#}
{# <span>7мб</span>#}
{# <div></div>#}
{# </li>#}
{# </ul>#}
</div>
<p class="type-work">{% trans 'project_stage0' %}:</p>
<div class="mail-block type-work-inset">
<div class="inset-mb">
<label><input type="radio" value="1" name="{{ project_form.type_work.name }}"><span></span></label>
@ -235,7 +235,6 @@
</div>
</form>
{% endblock %}
@ -247,6 +246,7 @@
}
$.ajax({
url: '/api/specializations?parent=1',
type: 'GET',

@ -53,7 +53,8 @@
</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>
@ -62,7 +63,8 @@
<li><span>{{ cand.answer.author.rating }}</span></li>
<li>
<span>+0</span> 0 <small> - 0</small>
<span>+0</span> 0
<small> - 0</small>
</li>
{% if cand.answer.author.cro %}
@ -82,7 +84,9 @@
<td>
<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 %}
<a href="#" onclick="$(this).closest('form').submit(); return false">

@ -1,11 +1,13 @@
{% extends 'partials/base.html' %}
{% load thumbnail %}
{% load i18n %}
{% block head_css %}
<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 .-live-image-delete {
@ -43,7 +45,7 @@
</div>
<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 class="col-lg-3">
@ -56,22 +58,23 @@
</div>
<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%">
</div>
<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%">
</div>
<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%">
</div>
<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%">
</div>
@ -116,7 +119,6 @@
</div>
<div class="textAreaBlock2 text-nn box-sizing disTab -live-image-upload-container">
<p>Фотографии</p>
@ -130,7 +132,8 @@
{% endthumbnail %}
</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>
{% endfor %}
@ -138,11 +141,13 @@
<% images.forEach(function(image) { %>
<div class="col-lg-3">
<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 %>">
</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>
<% }) %>
</script>
@ -152,20 +157,22 @@
<div class="col-xs-12">
<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>
</div>
</div>
<div class="textAreaBlock2 text-nn box-sizing disTab">
</div>
<div class="searchF1 polsF1 polsFF links-filter">
<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>

@ -1,8 +1,11 @@
{% extends 'partials/base.html' %}
{% load i18n %}
{% block head_css %}
<style>
.-error, .errorlist {color: red}
.-error, .errorlist {
color: red
}
</style>
{% endblock %}
@ -17,7 +20,8 @@
<p class="titleScore">Новый заказ</p>
</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 %}
<input type="hidden" id="extraFields" name="extra_fields" value="">
@ -31,13 +35,23 @@
{% endif %}
<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 }}">
</div>
<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>
<textarea name="{{ form.text.html_name }}" id="text-new" style="margin-top:0;">{{ form.text.value }}</textarea>
<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>
<textarea name="{{ form.text.html_name }}" id="text-new"
style="margin-top:0;">{{ form.text.value }}</textarea>
</div>
</div>
<div class="col-lg-3 wrChat1">
@ -51,14 +65,20 @@
<ul class="list-new-new">
<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>
<div class="file-upload-remove-btn"></div>
</li>
</ul>
</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">
{% for id, text in form.work_type.field.choices %}
<div class="inset-mb">
@ -77,7 +97,8 @@
{% endfor %}
</div>
<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>
@ -85,34 +106,45 @@
<div class="filter clearfix">
<div class="polsF1 disTab">
<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%">
</div>
<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%">
</div>
<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%">
</div>
<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%">
</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 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>
<div class="searchF1 polsF1 polsFF">
<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 }}
</div>
<div class="col-lg-3">
@ -128,7 +160,9 @@
<span></span>
</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 class="searchF1 polsF1 polsFF make-new">
@ -144,7 +178,9 @@
<p>Сделать для исполнителей обязательным для заполнения поля цена и срок</p>
</div>
<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 class="searchF1 polsF1 polsFF radio-afer">
<div class="col-lg-6">
@ -189,14 +225,11 @@
</div>
<div class="resSearchF1">
<div class="col-lg-3">
<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>
</button>
</div>
@ -207,10 +240,28 @@
<div class="slideRes disTab activeSlide">
<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=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 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=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 class="polsF1 polsF2 disTab">
@ -222,7 +273,8 @@
<option value="" {% if not form.realty.value %}selected="selected"{% endif %}>Создать новый</option>
{% 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 %}
</select>
</div>
@ -251,13 +303,18 @@
class="selectpicker"
name="{{ realty_form.construction_type.html_name }}">
{% 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 %}
</select>
</div>
</div>
<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 class="polsF1 polsF2 disTab">
<div>
@ -274,11 +331,14 @@
</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">
<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>
@ -302,7 +362,8 @@
// Project work type suggestion modal ---------------------------------
;(function() {
;
(function () {
var $modal = $('#projectWorkTypeSuggestionModal')
var $form = $modal.find('.-project-work-type-suggestion-form').first()
var workTypeSuggestionUrl = '/projects/suggest-work-type/'
@ -336,8 +397,11 @@
// 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)
window.location.hash = hash

@ -1,8 +1,11 @@
{% extends 'partials/base.html' %}
{% load i18n %}
{% block head_css %}
<style>
.-error, .errorlist {color: red}
.-error, .errorlist {
color: red
}
</style>
{% endblock %}
@ -17,7 +20,8 @@
<p class="titleScore">Изменение проекта</p>
</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 %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=pk %}">
@ -32,12 +36,14 @@
{% endif %}
<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 }}">
</div>
<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>
</div>
</div>
@ -54,21 +60,25 @@
<ul class="list-new-new">
{% for file in form.files.field.queryset.all %}
<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>
<div class="existing-file-remove-btn"></div>
</li>
{% endfor %}
<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>
<div class="file-upload-remove-btn"></div>
</li>
</ul>
</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">
{% for id, text in form.work_type.field.choices %}
<div class="inset-mb">
@ -87,7 +97,8 @@
{% endfor %}
</div>
<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>
@ -95,34 +106,42 @@
<div class="filter clearfix">
<div class="polsF1 disTab">
<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%">
</div>
<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%">
</div>
<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%">
</div>
<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%">
</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 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>
<div class="searchF1 polsF1 polsFF">
<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 }}
</div>
<div class="col-lg-3">
@ -154,7 +173,9 @@
<p>Сделать для исполнителей обязательным для заполнения поля цена и срок</p>
</div>
<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 class="searchF1 polsF1 polsFF radio-afer">
<div class="col-lg-6">
@ -199,10 +220,6 @@
</div>
<div class="resSearchF1">
<div class="col-lg-3">
<p class="titleResF1">Расширенный поиск</p>
@ -216,10 +233,18 @@
</div>
<div class="slideRes disTab activeSlide">
<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" 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 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"
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 class="polsF1 polsF2 disTab">
@ -231,7 +256,8 @@
<option value="" {% if not form.realty.value %}selected="selected"{% endif %}>Создать новый</option>
{% 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 %}
</select>
</div>
@ -249,7 +275,8 @@
class="selectpicker"
name="{{ realty_form.building_classification.html_name }}">
{% 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 %}
</select>
</div>
@ -259,13 +286,16 @@
class="selectpicker"
name="{{ realty_form.construction_type.html_name }}">
{% 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 %}
</select>
</div>
</div>
<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 class="polsF1 polsF2 disTab">
<div class="col-lg-3">
@ -280,7 +310,8 @@
<input type="hidden" class="-location-select -location-select-city" style="width: 100%">
</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">
<label>
@ -315,7 +346,8 @@
// Project work type suggestion modal ---------------------------------
;(function() {
;
(function () {
var $modal = $('#projectWorkTypeSuggestionModal')
var $form = $modal.find('.-project-work-type-suggestion-form').first()
var workTypeSuggestionUrl = '/projects/suggest-work-type/'
@ -352,8 +384,11 @@
// 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)
window.location.hash = hash

@ -7,7 +7,8 @@
</div>
<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 %}
<div>{{ work_type_suggestion_form.non_field_errors }}</div>

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

@ -46,7 +46,8 @@
</div>
</a>
<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 class="navv2">На сайте {{ project.created|naturaltime }}</p>
@ -115,7 +116,8 @@
<p class="textProIn">
{{ project.text|linebreaksbr }}
</p>
</div> br
</div>
br
<div class="col-lg-10 col-lg-offset-1" style="margin-top: 15px;">
@ -124,7 +126,8 @@
{% for file in project.files.all %}
<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>
{% endfor %}
</p>
@ -154,7 +157,8 @@
</div>
{% endif %}
{% 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>
@ -230,7 +234,8 @@
</a>
<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>
{% elif answer.author|class_name == 'Team' %}
<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>
{% csrf_token %}
<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>
{% 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>
{% else %}
{% 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' %}
<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 class="col-xs-12">
<ul>
{% 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 %}
</ul>
</div>
<div class="gallMini disTab">
{% for portf in answer.portfolios.all %}
<div class="col-lg-3">
@ -349,13 +352,11 @@
</div>
<div id="contractor-answers" class="commBlock44 disTab">
{% for message in answer.messages.all %}
<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 %}
<p class="nameComm">
{% firstof project.customer.get_full_name.strip project.customer.username %}
@ -385,10 +386,13 @@
<div class="col-lg-10 col-lg-offset-1">
<form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST" novalidate>
{% 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><button type="submit" class="fr_answer_sen">Отправить</button></div>
<div>
<button type="submit" class="fr_answer_sen">Отправить</button>
</div>
</form>
</div>
</div>
@ -396,7 +400,8 @@
</div>
</div>
{% 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 %}
<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 %}">
@ -411,7 +416,8 @@
<div class="col-lg-4">
<div class="textAreaBlock2 text-nn box-sizing disTab">
<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>
@ -486,12 +492,14 @@
<div class="col-lg-12">
<div id="fileUploadContainer">
<div>
<button type="button" id="fileUploadAddBtn">Добавить файл</button> Не более 10 файлов общим объемом до 500 Мб
<button type="button" id="fileUploadAddBtn">Добавить файл</button>
Не более 10 файлов общим объемом до 500 Мб
</div>
<ul class="list-new-new">
<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>
<a href="#" onclick="return false" class="file-upload-remove-btn">&times;</a>
</li>
@ -604,7 +612,8 @@
</a>
<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>
{% elif answer.author|class_name == 'Team' %}
<a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe">
@ -673,7 +682,8 @@
<div class="col-lg-3 retts">
{% 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>
{% endif %}
@ -683,12 +693,15 @@
{% elif project.order.team and project.order.team == answer.author %}
<a href="/chat/#order{{ project.order.pk }}" class="candLink candLink2">Перейти к обсуждению</a>
{% 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 %}
<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-id="{{ project.order.id }}"
data-order-name="{{ project.name }}"
@ -708,7 +721,8 @@
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<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-project-id="{{ project.pk }}"
class="candLink candLink3 reject-project-link" title="{{ answer.pk }}">отказ</a>
@ -718,7 +732,8 @@
<div class="col-xs-12">
<ul>
{% 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 %}
</ul>
</div>
@ -727,7 +742,8 @@
{% for portf in answer.portfolios.all %}
<div class="col-lg-3">
<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>
</div>
@ -738,7 +754,8 @@
<div class="commBlock44 disTab">
{% for message in answer.messages.all %}
<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 %}
<p class="nameComm nameCommAct">
{% firstof project.customer.get_full_name.strip project.customer.username %}
@ -766,12 +783,16 @@
<div class="comm44 disTab">
<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 %}
<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><button type="submit" class="fr_answer_sen">Отправить</button></div>
<div>
<button type="submit" class="fr_answer_sen">Отправить</button>
</div>
</form>
</div>
</div>
@ -782,9 +803,6 @@
</div>
<div id="candidate-answers" class="tab-pane fade">
<div class="col-lg-12 exNew">
<p>Кандидаты</p>
@ -808,7 +826,8 @@
</a>
<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>
{% elif answer.author|class_name == 'Team' %}
<a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe">
@ -877,7 +896,8 @@
<div class="col-lg-3 retts">
{% 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>
{% endif %}
@ -887,12 +907,15 @@
{% elif project.order.team and project.order.team == answer.author %}
<a href="/chat/#order{{ project.order.pk }}" class="candLink candLink2">Перейти к обсуждению</a>
{% 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 %}
<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-id="{{ project.order.id }}"
data-order-name="{{ project.name }}"
class="candLink candLink2 offer-order-contractor">
@ -912,7 +935,8 @@
<input type="hidden" name="next" value="{{ request.path }}">
<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-project-id="{{ project.pk }}"
class="candLink candLink3 reject-project-link" title="{{ answer.pk }}">отказ
@ -923,7 +947,8 @@
<div class="col-xs-12">
<ul>
{% 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 %}
</ul>
</div>
@ -932,7 +957,8 @@
{% for portf in answer.portfolios.all %}
<div class="col-lg-3">
<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>
</div>
@ -943,7 +969,8 @@
<div class="commBlock44 disTab">
{% for message in answer.messages.all %}
<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 %}
<p class="nameComm nameCommAct">
{% firstof project.customer.get_full_name.strip project.customer.username %}
@ -971,11 +998,16 @@
<div class="comm44 disTab">
<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 %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}#candidate-answers">
<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>
<input type="hidden" name="next"
value="{% url 'projects:detail' pk=project.pk %}#candidate-answers">
<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>
</div>
</div>
@ -986,9 +1018,6 @@
</div>
<div id="rejected-answers" class="tab-pane fade">
<div class="col-lg-12 exNew">
<p>Отказы</p>
@ -1014,7 +1043,8 @@
</a>
<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>
{% elif answer.author|class_name == 'Team' %}
<a href="{% url 'users:team-profile' pk=answer.author.pk %}" class="aLinkExe">
@ -1086,7 +1116,8 @@
<form action="{% url 'projects:restore-project-answer' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %}
<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>
{# {% if answer.author|class_name == 'User' %}#}
@ -1099,7 +1130,8 @@
<div class="col-xs-12">
<ul>
{% 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 %}
</ul>
</div>
@ -1108,7 +1140,8 @@
{% for portf in answer.portfolios.all %}
<div class="col-lg-3">
<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>
</div>
@ -1119,7 +1152,8 @@
<div class="commBlock44 disTab">
{% for message in answer.messages.all %}
<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 %}
<p class="nameComm nameCommAct">
{% firstof project.customer.get_full_name.strip project.customer.username %}
@ -1163,7 +1197,8 @@
<script>
// Persistent Bootstrap tabs --------------------------------------
;(function() {
;
(function () {
var $allTabs = $('a[data-toggle="tab"]');
var $tab = $allTabs.filter('[href="' + window.location.hash + '"]').first();
@ -1185,7 +1220,8 @@
// Toggle project answer form -----------------------------------
;(function() {
;
(function () {
var $projectAnswerForm = $('.-project-answer-form').first();
if ($.cookie('projectAnswerFormVisible')) {
@ -1258,7 +1294,6 @@
}());
// Scroll to answers -------------------------------------
setTimeout(function () {

@ -1,6 +1,6 @@
{% extends 'partials/base.html' %}
{% load common_tags %}
{% load common_tags i18n %}
{% block content %}
{% include 'partials/header.html' %}
@ -18,7 +18,7 @@
<div class="titleF1 disTab">
<div class="col-lg-3">Тип работы</div>
<div class="col-lg-3">{% trans 'project_stage0' %}</div>
</div>
<div class="polsF1 disTab">
<div class="col-lg-3">
@ -32,23 +32,25 @@
<div class="polsF1 disTab">
<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%">
</div>
<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%">
</div>
<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%">
</div>
<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%">
</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>
@ -75,7 +77,6 @@
</div>
<div class="resSearchF1">
<div class="col-lg-3">
<p class="titleResF1">Расширенные поля</p>
@ -89,13 +90,6 @@
</div>
<div class="slideRes disTab activeSlide">
<div class="titleF1 disTab">
<div class="col-lg-3">Классификация здания</div>
@ -115,9 +109,6 @@
</div>
<div class="slideRes disTab activeSlide">
<div class="titleF1 disTab">
<div class="col-lg-3">Местоположение</div>
@ -136,7 +127,8 @@
<input type="hidden" class="-location-select -location-select-city" style="width: 100%">
</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 class="sro">
@ -150,12 +142,6 @@
</div>
<div class="col-lg-12">
<p class="titleScore">{{ display_msg }}</p>
<div class="linkSort">
@ -166,14 +152,13 @@
{% endfor %}
<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>
</form>
<div class="projectsBlock disTab">
{% for project in projects %}
<div class="projectPro clearfix">

@ -1,28 +1,33 @@
import pydash as _;
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.filter
def get_candidates(project):
return tuple(c.answer.author for c in project.candidates.all())
@register.filter
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
def get_candidate_answers(project):
return tuple(c.answer for c in project.candidates.filter(answer__rejected=False))
@register.filter
def get_rejected_answers(project):
return project.answers.filter(rejected=True)
@register.filter
def get_answer(project, contractor):
answer = _.find(project.answers.all(), lambda a: a.author == contractor)
@ -32,5 +37,4 @@ def get_answer(project, contractor):
return answer
# import code; code.interact(local=dict(globals(), **locals()))

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

@ -1,5 +1,4 @@
from django.conf import urls
from django.views.generic import TemplateView
from .views import (
# 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+)/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'^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'^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/(?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+)/trash/$', ContractorPortfolioTrashView.as_view(), name='contractor-portfolio-trash'),
urls.url(r'^portfolio/(?P<pk>\d+)/edit/$', ContractorPortfolioUpdateView.as_view(),
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/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/(?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'),
]

@ -1,26 +1,29 @@
import json
from pprint import pformat
import natsort
import pydash as _;
from django.conf import settings
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.files.base import ContentFile
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
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.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.views import HitCountMixin
from pprint import pprint, pformat
import json
import natsort
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
import re
from .mixins import LastAccessMixin
from archilance import util
from archilance.mixins import BaseMixin
from common.mixins import CustomerRequiredMixin, ContractorRequiredMixin, NoCsrfMixin
from common.mixins import NoCsrfMixin
from users.models import User, Team
from work_sell.models import Picture, WorkSell, WorkSellPhoto
from ratings.models import HistoryRating
@ -36,7 +39,6 @@ from .models import (
PortfolioPhoto,
Project,
ProjectFile,
Realty,
TERM_TYPE_MORPHS,
)
@ -113,7 +115,6 @@ class ProjectDetailWithAnswerView(BaseMixin, View):
if request.POST.get('answer_as_team') == 'on':
answer_as_team = True
# Check for duplicate answers:
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():
raise PermissionDenied('Повторный отклик')
if answer_as_team:
form = self.form_class(request.POST, request=request, answer_as_team=True, project=project)
else:
@ -416,7 +416,8 @@ class CustomerProjectCreateView(BaseMixin, View):
return render(request, self.template_name, context)
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()
realty = form.cleaned_data.get('realty')
@ -525,7 +526,8 @@ class CustomerProjectEditView(BaseMixin, View):
if form.is_valid() and realty_form.is_valid():
project = form.save(commit=False)
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()
form.save_m2m()
@ -566,7 +568,6 @@ class CustomerProjectEditView(BaseMixin, View):
class ContractorAnswerArchiveView(View):
def post(self, request, *args, **kwargs):
project_pk = request.POST.get('project_pk')
user_pk = request.POST.get('user_pk')
@ -691,7 +692,6 @@ def add_candidate(request, answer_id, project_id):
if not candidate:
Candidate.objects.create(answer=answer, project=project, position=count_answers)
redirect_to = '%s%s' % (reverse('projects:detail', kwargs={'pk': project_id}), '#answers')
return redirect(redirect_to)
@ -902,5 +902,4 @@ class ProjectWorkTypeSuggestionView(View):
'form_errors': form_errors,
})
# import code; code.interact(local=dict(globals(), **locals()))

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

@ -1,7 +1,8 @@
from django.db import models
from django.utils import timezone
from users.models import User, Team
from specializations.models import Specialization
from users.models import User, Team
class HistoryRating(models.Model):
@ -32,7 +33,8 @@ class HistoryRating(models.Model):
class SpecializationRating(models.Model):
user = models.ForeignKey(User, 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)
def __str__(self):

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

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

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

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

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

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

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

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

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

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

@ -6,5 +6,13 @@ from .models import Specialization
class SpecializationAdmin(MPTTModelAdmin):
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)

@ -1,6 +1,8 @@
from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter
from .models import Specialization
class SpecializationFilterSet(FilterSet):
id = 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 mptt.models import MPTTModel, TreeForeignKey
from mptt.managers import TreeManager
from mptt.models import MPTTModel, TreeForeignKey
class Specialization(MPTTModel):
name = models.CharField(max_length=500)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
order = models.PositiveIntegerField()
selectable = models.BooleanField(default=True)
objects = TreeManager()
@ -13,8 +15,10 @@ class Specialization(MPTTModel):
return self.name
class Meta:
get_latest_by = 'order'
ordering = ['order']
verbose_name = 'Специализация'
verbose_name_plural = 'Специализации'
class MPTTMeta:
order_insertion_by = ['name']
order_insertion_by = ['order', 'name']

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

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

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

@ -5,4 +5,4 @@ class UsersConfig(AppConfig):
name = 'users'
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 .models import User
class EmailOrUsernameModelBackend(object):
def authenticate(self, username=None, password=None):
if '@' in username:
kwargs = {'email': username}

@ -1,5 +1,8 @@
import pydash as _;
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

@ -1,11 +1,15 @@
import itertools
import pydash as _;
from django import forms
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 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
@ -165,7 +169,6 @@ class ContractorFilterForm(forms.Form):
last_order_by = forms.ChoiceField(required=False, choices=CONTRACTOR_ORDER_CHOICES)
reverse_order = forms.BooleanField(required=False)
try: # TODO: dirty
qs = Specialization.objects.root_nodes()[0].get_descendants()
except:
@ -233,7 +236,6 @@ class ContractorFilterForm(forms.Form):
class CustomerProfileProjectRealtyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
self.customer = kwargs.pop('customer')
@ -252,5 +254,4 @@ class CustomerProfileProjectRealtyForm(forms.Form):
required=False,
)
# import code; code.interact(local=dict(globals(), **locals()))

@ -1,15 +1,19 @@
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:
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:
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:
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:
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):
def dispatch(self, request, *args, **kwargs):
pass

@ -1,3 +1,4 @@
import pydash as _;
from dateutil.relativedelta import relativedelta
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, AbstractUser, Group, PermissionsMixin
from django.contrib.contenttypes.fields import GenericRelation
@ -5,10 +6,13 @@ from django.db import models
from django.db.models import Sum
from django.utils import timezone, formats
from mptt.models import TreeForeignKey, TreeManyToManyField
import pydash as _; _.map = _.map_; _.filter = _.filter_
_.map = _.map_;
_.filter = _.filter_
from archilance import util
from specializations.models import Specialization
# from chat.models import NewMessage
@ -232,7 +236,8 @@ class Team(models.Model):
name = models.CharField(max_length=255)
owner = models.OneToOneField(User, related_name='team', blank=True, null=True)
specializations = TreeManyToManyField(Specialization, related_name='teams', blank=True)
contractors = models.ManyToManyField(User, limit_choices_to={'groups__name': 'Исполнители'}, related_name ='teams', blank=True)
contractors = models.ManyToManyField(User, limit_choices_to={'groups__name': 'Исполнители'}, related_name='teams',
blank=True)
rating = models.FloatField(default=0.0)
def __str__(self):
@ -243,7 +248,6 @@ class Team(models.Model):
verbose_name_plural = 'Команды'
class TeamInvitation(models.Model):
contractor1 = models.ForeignKey(User, related_name='invites')
contractor2 = models.ForeignKey(User, related_name='invited_by')

@ -1,8 +1,9 @@
from django.shortcuts import redirect, render_to_response, render
from django.contrib.auth.models import Group
from django.core.mail import EmailMultiAlternatives
from django.shortcuts import redirect, render_to_response
from django.template.loader import get_template, render_to_string
from social.pipeline.partial import partial
from django.contrib.auth.models import Group
from users.models import ContractorResume
@ -54,4 +55,3 @@ def require_email(strategy, details, user=None, is_new=False, *args, **kwargs):
details['email'] = email
else:
return redirect('require_email')

@ -1,9 +1,7 @@
from rest_framework.serializers import ModelSerializer, ImageField, FileField, SerializerMethodField, ReadOnlyField
from rest_framework.serializers import ModelSerializer, SerializerMethodField, ReadOnlyField
from .models import User, Team, ContractorResumeFiles, ContractorResume
from projects.models import Project
# from projects.serializers import AnswerSerializer
from specializations.serializers import SpecializationSerializer
from .models import User, Team, ContractorResumeFiles, ContractorResume
class ContractorResumeSerializer(ModelSerializer):
@ -119,5 +117,4 @@ class TeamSerializer(ModelSerializer):
def get__type(self, obj):
return 'Team'
# import code; code.interact(local=dict(globals(), **locals()))

@ -1,10 +1,10 @@
import math
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.dispatch import receiver
from ratings.models import HistoryRating
from django.contrib.auth.models import Group
from registration.signals import user_registered
from users.models import ContractorResume, User
from users.models import User
@receiver(post_save, sender=User)
@ -24,7 +24,6 @@ def add_rating_for_user_fields(sender, instance, created, **kwargs):
hs_rating[0].description = 'Заполненные поля в профиле. Баллы за рейтинг'
hs_rating[0].save()
# @receiver(user_registered)
# def user_registered_callback(sender, user, request, **kwargs):
# # import code; code.interact(local=dict(globals(), **locals()))
@ -35,5 +34,3 @@ def add_rating_for_user_fields(sender, instance, created, **kwargs):
# resume = ContractorResume.objects.create(text='')
# user.contractor_resume = resume
# user.save()

@ -3,6 +3,7 @@
{% load common_tags %}
{% load specializtions_tags %}
{% load thumbnail %}
{% load i18n %}
{% block content %}
{% include 'partials/modals/project_selection.html' %}
@ -23,7 +24,7 @@
<div class="titleF1 disTab">
<div class="col-lg-3">Тип работы</div>
<div class="col-lg-3">{% trans 'project_stage0' %}</div>
</div>
<div class="polsF1 disTab">
@ -42,19 +43,19 @@
<div class="polsF1 disTab">
<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%">
</div>
<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%">
</div>
<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%">
</div>
<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%">
</div>

@ -1,5 +1,5 @@
{% load common_tags %}
{% load i18n %}
<div class="modal-body">
<form method="post" id="portfolio-add-form" class="-spec-work-type-combo-container">
@ -22,7 +22,7 @@
</div>
<div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Тип работы</p>
<p>{% trans 'project_stage0' %}</p>
</div>
<div class="polsF1 disTab">
<div class="col-lg-4">
@ -34,22 +34,22 @@
</div>
<div class="col-lg-3 -single-spec-select">
<div class="-bold">Стадия проекта <span style="color: red">{{ portfolio_form.specialization.errors.as_text }}</span></div>
<div class="-bold">{% trans 'project_stage1' %} <span style="color: red">{{ portfolio_form.specialization.errors.as_text }}</span></div>
<input type='hidden' class="-spec-select -spec-select-level-1" style="width: 100%">
</div>
<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%">
</div>
<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%">
</div>
<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%">
</div>

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

Loading…
Cancel
Save