#ARC-10 Add management for ratings

remotes/origin/setup
Mukhtar 10 years ago
parent ed2aabc786
commit 2cb80e7f1d
  1. 2
      archilance/settings/base.py
  2. 4
      chat/testapp.py
  3. 7
      chat/views.py
  4. 29
      common/migrations/0004_auto_20160808_1557.py
  5. 2
      common/models.py
  6. 9
      projects/forms.py
  7. 0
      projects/templatetags/__init__.py
  8. 10
      projects/templatetags/projects_tags.py
  9. 2
      projects/urls.py
  10. 24
      projects/views.py
  11. 17
      ratings/management/commands/recalculation_rating.py
  12. 41
      ratings/management/commands/recalculation_spec.py
  13. 2
      ratings/models.py
  14. 13
      ratings/templates/templatetags/ratings_widget.html
  15. 25
      ratings/templatetags/specializtions_tags.py
  16. 37
      templates/partials/header.html
  17. 11
      users/admin.py
  18. 25
      users/migrations/0007_auto_20160808_1557.py
  19. 3
      users/models.py
  20. 465
      users/templates/contractor_office.html
  21. 33
      users/templates/contractor_profile.html
  22. 4
      users/templates/user_profile_edit.html
  23. 7
      users/templates/worksell_create_form.html
  24. 2
      users/urls.py
  25. 17
      users/views.py
  26. 10
      work_sell/forms.py
  27. 4
      work_sell/models.py
  28. 8
      work_sell/templates/worksells_list.html
  29. 2
      work_sell/urls.py
  30. 46
      work_sell/views.py

@ -111,7 +111,7 @@ WSGI_APPLICATION = 'archilance.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'archilance',
'NAME': 'archilance2',
'USER': 'postgres',
'PASSWORD': 'postgres',
'HOST': 'localhost',

@ -66,7 +66,7 @@ class ChatHandler(websocket.WebSocketHandler):
order_value = "NULL" if order_id is None else order_id
insert_sql = "INSERT INTO chat_message (id,text,created, sender_id,recipent_id, private_type,team_id, order_id) " \
"VALUES (DEFAULT,'{0}',NOW(),{1},{2},{3},{4},{5})".format(message, sender_id, recipent_id, private_type, team_value,order_value)
"VALUES (DEFAULT,'{0}',NOW(),{1},{2},{3},{4},{5})".format(message, sender_id, recipent_id, private_type, team_value,order_value)
yield self.db.execute(insert_sql)
waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id)
@ -92,7 +92,7 @@ if __name__ == '__main__':
ioloop = IOLoop.instance()
application.db = momoko.Pool(
dsn='dbname=archilance user=postgres password=postgres host=localhost',
dsn='dbname=archilance2 user=postgres password=postgres host=localhost',
size=1,
ioloop=ioloop,
)

@ -12,6 +12,8 @@ class ChatUserView(View):
template_name = ''
def get(self, request, *args, **kwargs):
# import code; code.interact(local=dict(globals(), **locals()))
user_id = request.GET.get('user_id',None)
if request.user.is_authenticated() and request.user.is_customer():
customer_contacts = Message.objects.values_list('sender_id', 'recipent_id'). \
filter(Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)).distinct()
@ -23,6 +25,9 @@ class ChatUserView(View):
users_ids.append(a)
if b != request.user.pk:
users_ids.append(b)
if user_id:
users_ids.append(int(user_id))
# import code; code.interact(local=dict(globals(), **locals()))
contacts_users = User.objects.filter(pk__in=users_ids)
chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk))
@ -42,6 +47,8 @@ class ChatUserView(View):
users_ids.append(a)
if b != request.user.pk:
users_ids.append(b)
if user_id:
users_ids.append(int(user_id))
contacts_users = User.objects.filter(pk__in=users_ids)
chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk)).order_by(
'created')

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-08 12:57
from __future__ import unicode_literals
import datetime
from django.db import migrations, models
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('common', '0003_auto_20160729_1747'),
]
operations = [
migrations.AddField(
model_name='settings',
name='recalculation_rating_time',
field=models.TimeField(default=datetime.datetime(2016, 8, 8, 12, 57, 41, 160156, tzinfo=utc)),
preserve_default=False,
),
migrations.AddField(
model_name='settings',
name='recalculation_spec_time',
field=models.TimeField(default=datetime.datetime(2016, 8, 8, 12, 57, 52, 905906, tzinfo=utc)),
preserve_default=False,
),
]

@ -40,6 +40,8 @@ class Settings(models.Model):
document_send_email = models.EmailField(max_length=100, default="muhtarzubanchi05@gmail.com")
document_send_description = models.TextField(blank=True)
document_send_time_remove = models.IntegerField(default=14)
recalculation_spec_time = models.TimeField()
recalculation_rating_time = models.TimeField()
def __str__(self):
return 'Настройки сайта'

@ -235,6 +235,15 @@ class CustomerProjectTrashForm(forms.Form):
self.fields['pk'].queryset = self.req.user.projects.filter(state='active')
class ContractorPortfolioTrashForm(forms.Form):
pk = forms.ModelChoiceField(queryset=Portfolio.objects.none())
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
self.fields['pk'].queryset = self.request.user.portfolios.all()
class CustomerProjectRestoreForm(forms.Form):
pk = forms.ModelChoiceField(queryset=Project.objects.none())

@ -1,10 +0,0 @@
from django import template
register = template.Library()
@register.inclusion_tag("templatetags/ratings_widget.html", takes_context=True)
def ratings_widget(context, user_id, class_name=None):
ratings = user_id
return {
'ratings': ratings,
}

@ -14,6 +14,7 @@ from .views import (
ProjectComparisonView,
ProjectFilterView,
ProjectDetailWithContractorAnswerView,
ContractorPortfolioTrashView,
)
app_name = 'projects'
@ -25,6 +26,7 @@ urlpatterns = [
urls.url(r'^create/$', CustomerProjectCreateView.as_view(), name='customer-project-create'),
urls.url(r'^(?P<pk>\d+)/edit/$', CustomerProjectEditView.as_view(), name='customer-project-edit'),
urls.url(r'^(?P<pk>\d+)/trash/$', CustomerProjectTrashView.as_view(), name='customer-project-trash'),
urls.url(r'^portfolio/(?P<pk>\d+)/trash/$', ContractorPortfolioTrashView.as_view(), name='contractor-portfolio-trash'),
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'),

@ -15,7 +15,7 @@ import pydash as _; _.map = _.map_; _.filter = _.filter_
import re
from .mixins import LastAccessMixin
from .models import Project, ProjectFile, Portfolio, Candidate, Answer, AnswerFile, Realty, Order
from .models import Project, ProjectFile, Portfolio, PortfolioPhoto,Candidate, Answer, AnswerFile, Realty, Order
from archilance.mixins import BaseMixin
from users.models import User
from work_sell.models import Picture
@ -31,6 +31,7 @@ from .forms import (
ProjectFilterForm,
ProjectFilterRealtyForm,
RealtyForm,
ContractorPortfolioTrashForm,
)
@ -353,6 +354,21 @@ class CustomerProjectEditView(BaseMixin, View):
return render(request, self.template_name, context)
class ContractorPortfolioTrashView(View):
form_class = ContractorPortfolioTrashForm
def post(self,request, *args, **kwargs):
form = self.form_class(_.merge({}, request.POST, kwargs), request=request)
if form.is_valid():
portfolio = form.cleaned_data.get('pk')
portfolio.delete()
messages.info(request, 'Портфолио удален')
else:
messages.info(request, 'Произошла ошибка: <pre>{msg}</pre>'.format(msg=pformat(form.errors)))
redirect_to = request.POST.get('next')
return redirect(redirect_to)
class CustomerProjectTrashView(View):
form_class = CustomerProjectTrashForm
@ -483,4 +499,10 @@ class ContractorPortfolioUpdateView(UpdateView):
return reverse('proje')
from django.views.generic import DeleteView
class PortfolioDelete(DeleteView):
model = Portfolio
success_url = reverse_lazy('users:contractor-profile')
# import code; code.interact(local=dict(globals(), **locals()))

@ -1,10 +1,23 @@
from django.core.management import BaseCommand
from django.db.models import Sum
from specializations.models import Specialization
from ratings.models import HistoryRating
from users.models import User
from users.models import User,Team
class Command(BaseCommand):
def handle(self, *args, **options):
contractors = User.contractor_objects.all()
users = User.objects.filter(is_superuser=False)
for user in users:
current_rating_info = HistoryRating.objects.filter(user_id=user.pk).aggregate(Sum('rating'))
current_rating = current_rating_info['rating__sum'] or 0
user.rating = current_rating
user.save()
teams = Team.objects.all()
for team in teams:
current_rating_info = HistoryRating.objects.filter(team_id=team.pk).aggregate(Sum('rating'))
current_rating = current_rating_info['rating__sum'] or 0
team.rating = current_rating
team.save()

@ -1,24 +1,35 @@
from django.core.management import BaseCommand
from specializations.models import Specialization
from ratings.models import SpecializationRating
from users.models import User
from users.models import User, Team
class Command(BaseCommand):
def handle(self, *args, **options):
SpecializationRating.objects.all().delete()
contractors = User.contractor_objects.order_by('-contractor_rating')
specializations = Specialization.objects.all()
for spec in specializations:
i = 0
for contractor in contractors:
if spec in contractor.contractor_specializations.all():
i += 1
spec_rating = SpecializationRating()
spec_rating.position = i
spec_rating.user = contractor
spec_rating.specialization = spec
spec_rating.save()
users = User.objects.values('pk', 'rating').filter(is_superuser=False).order_by('-rating')
teams = Team.objects.values('pk', 'rating').order_by('-rating')
result_list = []
print('The End')
for user in users:
result_list.append([user['rating'], 'user', user['pk']])
for team in teams:
result_list.append([team['rating'], 'team',team['pk'] ])
print(sorted(result_list))
# SpecializationRating.objects.all().delete()
# contractors = User.contractor_objects.order_by('-rating')
# specializations = Specialization.objects.all()
# for spec in specializations:
# i = 0
# for contractor in contractors:
# if spec in contractor.contractor_specializations.all():
# i += 1
# spec_rating = SpecializationRating()
# spec_rating.position = i
# spec_rating.user = contractor
# spec_rating.specialization = spec
# spec_rating.save()
#
# print('The End')

@ -12,7 +12,7 @@ class HistoryRating(models.Model):
description = models.TextField(blank=True)
def __str__(self):
return self.rating
return '{0}'.format(self.rating)
class Meta:
verbose_name = 'История рейтинга'

@ -10,16 +10,3 @@
</a>
</li>
</ul>
{#<ul class="rettList restList2">#}
{# <li>Рейтинг: <span> 1245</span></li>#}
{# <li>Безопасные сделки: <span> 5</span></li>#}
{# <li>#}
{# <a href="javascript:void(0)">Отзывы:#}
{# <span> + 385</span>#}
{# <small> 0</small>#}
{# <mark> - 0</mark>#}
{# </a>#}
{# </li>#}
{# </ul>#}

@ -1,7 +1,7 @@
from django import template
from archilance import util
from users.models import User
from users.models import User, Team
from ratings.models import SpecializationRating
register = template.Library()
@ -14,3 +14,26 @@ def specialization_widget(context, user_id):
'specializations': specializations,
'user_id': user_id,
}
def specialization_team_widget(context, team_id):
team_id = int(team_id)
specializations = []
return {
'specializations': specializations,
}
@register.inclusion_tag("templatetags/ratings_widget.html", takes_context=True)
def ratings_widget(context, user_id, class_name=None):
ratings = User.objects.get(pk=user_id).rating
return {
'ratings': ratings,
}
@register.inclusion_tag("templatetags/ratings_widget.html", takes_context=True)
def ratings_team_widget(context, team_id):
ratings = Team.objects.get(pk=team_id).rating
return {
'ratings': ratings,
}

@ -7,7 +7,7 @@
<div class="col-lg-3">
<div class="logo" onClick="window.location='/'"></div>
</div>
{% if request.user.is_authenticated %}
<div class="col-lg-7">
<ul class="mainMenu">
@ -15,13 +15,13 @@
<a href="{% url 'projects:project-filter' %}">Биржа проектов</a>
<span></span>
</li>
{% if request.user.is_contractor %}
<li class="officeList icon_tml">
<a href="{% url 'users:contractor-office' pk=request.user.pk %}">Мой офис</a>
<span></span>
</li>
{% endif%}
{% endif %}
{% if request.user.is_customer %}
<li class="icon_tm2">
@ -29,7 +29,7 @@
<span></span>
</li>
<li class="icon_tm3">
<a href="#">Работы на продажу</a>
<a href="{% url 'work_sell:list' %}">Работы на продажу</a>
<span></span>
</li>
{% endif %}
@ -53,28 +53,37 @@
</ul>
</div>
{% endif %}
{% if request.user.is_authenticated %}
<div class="col-lg-2">
<div class="imgProfile">
{% if request.user.is_contractor %}
<a href="{% url 'users:contractor-profile' pk=request.user.pk %}">
{% thumbnail request.user.avatar "75x75" crop="center" as im %}
<img src="{{ im.url }}" alt="profile-image">
{% endthumbnail %}
{% if request.user.avatar %}
{% thumbnail request.user.avatar "75x75" crop="center" as im %}
<img src="{{ im.url }}" alt="profile-image">
{% endthumbnail %}
{% else %}
<img src="{% static 'img/profile.jpg' %}" alt="profile-image">
{% endif %}
</a>
{% elif request.user.is_customer %}
<a href="{% url 'users:customer-profile-open-projects' pk=request.user.pk %}">
{% thumbnail request.user.avatar "75x75" crop="center" as im %}
<img src="{{ im.url }}" alt="profile-image">
{% endthumbnail %}
{% if request.user.avatar %}
{% thumbnail request.user.avatar "75x75" crop="center" as im %}
<img src="{{ im.url }}" alt="profile-image">
{% endthumbnail %}
{% else %}
<img src="{% static 'img/profile.jpg' %}" alt="profile-image">
{% endif %}
</a>
{% endif %}
</div>
<div class="infoProfile disTab">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
</button>
<ul class="dropdown-menu menu-drop-new">
@ -117,7 +126,7 @@
</ul>
</div>
</div>
{% if request.user.is_contractor %}
<div class="rating">
<div class="ratingInset"></div>

@ -5,13 +5,20 @@ from .models import User, Team, UserFinancialInfo, ContractorResume, ContractorR
class UserAdmin(admin.ModelAdmin):
readonly_fields = ('pk',)
list_display = ('username', 'email', 'get_groups', 'cro', 'is_active',)
list_display = ('username', 'email', 'get_groups', 'cro', 'is_active', 'rating',)
ordering = ('-rating',)
def get_groups(self, obj):
return ', '.join(g.name for g in obj.groups.all())
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'rating', 'owner',)
ordering = ('-rating',)
admin.site.register(User, UserAdmin)
admin.site.register(UserFinancialInfo)
admin.site.register(Team)
admin.site.register(Team, TeamAdmin)
admin.site.register(ContractorResume)
admin.site.register(ContractorResumeFiles)

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-08 12:57
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0006_auto_20160805_1442'),
]
operations = [
migrations.RenameField(
model_name='user',
old_name='contractor_rating',
new_name='rating',
),
migrations.AddField(
model_name='team',
name='rating',
field=models.FloatField(default=0.0),
),
]

@ -120,7 +120,7 @@ class User(AbstractBaseUser, PermissionsMixin):
avatar = models.ImageField(upload_to='users/avatars/', blank=True)
contractor_answers = GenericRelation('projects.Answer')
contractor_rating = models.FloatField(default=0.0)
rating = models.FloatField(default=0.0)
contractor_resume = models.OneToOneField(ContractorResume, related_name='contractor', blank=True, null=True)
contractor_specializations = TreeManyToManyField(Specialization, related_name='contractors', blank=True)
contractor_status = models.CharField(default='free', max_length=20, choices=STATUSES)
@ -189,6 +189,7 @@ class Team(models.Model):
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)
rating = models.FloatField(default=0.0)
def __str__(self):
return self.name

@ -1,87 +1,98 @@
{% extends 'partials/base.html' %}
{% load staticfiles %}
{% load specializtions_tags %}
{% load thumbnail %}
{% block content %}
{% include 'partials/header.html' %}
<div class="container mainScore">
<div class="row">
<div class="col-lg-12">
<p class="titleScore">Личный кабинет</p>
</div>
<div class="profileTabs">
<ul class="nav nav-tabs nav-justified">
<li role="presentation">
<a href="#">Поиск исполнителей</a>
</li>
<li role="presentation" class="active">
<a href="#">Мои группы</a>
<div class="roundsCount">
<div class="countR">1</div>
<div class="countG">2</div>
</div>
</li>
<li role="presentation">
<a href="#">Открытые проекты</a>
<div class="container mainScore" xmlns="http://www.w3.org/1999/html">
<div class="row">
<div class="col-lg-12">
<p class="titleScore">Личный кабинет</p>
</div>
<div class="profileTabs">
<ul class="nav nav-tabs nav-justified">
<li role="presentation">
<a href="#">Поиск исполнителей</a>
</li>
<li role="presentation" class="active">
<a href="#">Мои группы</a>
<div class="roundsCount">
<div class="countR">1</div>
<div class="countG">2</div>
</div>
</li>
<li role="presentation">
<a href="#">Открытые проекты</a>
<span class="desPresent">
в процессе обсуждения
</span>
<div class="roundsCount">
<div class="countR">1</div>
<div class="countG">2</div>
</div>
</li>
<li role="presentation">
<a href="#">Проекты в работе</a>
<div class="roundsCount">
<div class="countG">2</div>
</div>
</li>
</ul>
</div>
<div class="buttonGP disTab">
<div class="btn-group valProject2 val-pro3" role="group" aria-label="...">
<button type="button" class="btn btn-default">
Группа 1
<span><mark>7</mark></span>
</button>
{% if contractor.is_owner_team %}
<button type="button" class="btn btn-default add-group" data-toggle="modal" data-target="#myModal">
+ Добавить группу
</button>
<div class="roundsCount">
<div class="countR">1</div>
<div class="countG">2</div>
</div>
</li>
<li role="presentation">
<a href="#">Проекты в работе</a>
<div class="roundsCount">
<div class="countG">2</div>
</div>
</li>
</ul>
</div>
<div class="buttonGP disTab">
<div class="btn-group valProject2 val-pro3" role="group" aria-label="...">
<button type="button" class="btn btn-default">
Группа 1
<span><mark>7</mark></span>
</button>
{% if not contractor.is_owner_team %}
<button type="button" class="btn btn-default add-group" data-toggle="modal"
data-target="#myModal">
+ Добавить группу
</button>
{% endif %}
</div>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">Добавление новой группы</h4>
</div>
<div class="modal-body">
{{ form_team }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>
<button type="button" class="btn btn-primary">Сохранить</button>
</div>
</div>
</div>
</div>
</div>
<div class="projectsBlock disTab">
<div class="col-lg-12">
<div class="col-lg-3 divCol3">
</div>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">Добавление новой группы</h4>
</div>
<div class="modal-body">
<form method="post" action="{% url 'users:team-create' %}">{% csrf_token %}
<div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Название <span style="color: red">{{ form_team.name.errors.as_text }}</span></p>
<input type="text" class="box-sizing" name="{{ form_team.name.html_name }}">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>
<button type="submit" class="btn btn-primary">Сохранить</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="projectsBlock disTab">
<div class="col-lg-12">
<div class="col-lg-3 divCol3">
<div class="avatar">
<div class="avatarInset">
{% thumbnail contractor.avatar "265x264" crop="center" as im %}
@ -89,219 +100,183 @@
{% endthumbnail %}
</div>
</div>
<div class="menuUser disTab">
<a href="javascript:void(0)" class="add-man">
добавить участника
</a>
<div class="block-users">
<p>Состав группы</p>
{% for p in participants %}
<div class="message-new">
<div class="imgMess">
{% thumbnail p.avatar "60x60" crop="center" as im %}
<img src="{{ im.url }}" alt="mess-image">
{% endthumbnail %}
</div>
<div class="message-new">
<p class="nameMess">
<a href="#">{{ p.get_full_name }}</a>
</p>
<span>Программист</span>
</div>
<div class="imgMess">
{% thumbnail p.avatar "60x60" crop="center" as im %}
<img src="{{ im.url }}" alt="mess-image">
{% endthumbnail %}
</div>
<p class="nameMess">
<a href="#">{{ p.get_full_name }}</a>
</p>
<span>Программист</span>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="col-lg-9 divCol9">
<div class="col-lg-4">
<p class="nameUser">
{{ contractor.team }}
</p>
<p class="cityUser">Россия, Москва</p>
{# <p class="navv">На сайте 8 лет и 3 месяца</p>#}
<p class="navv">На сайте {{ contractor.team.created }}</p>
<p class="navv">
Кол-во человек: <span>{{participants_count}}</span>
</p>
<p class="navv">
Выполненных проектов: <span>0</span>
</p>
<div class="statusUser st-new">Свободен</div>
<a href="javascript:void(0)" class="new-prop new-prop2 new-prop3">написать сообщение</a>
</div>
<div class="col-lg-4">
<div class="dashedCol4">
<p class="specUser">
Специализации:
</p>
<div class="insetSpec">
<span>Интерьеры</span>
<span>2-й</span>
</div>
<div class="insetSpec">
<span>Визуализация/3D</span>
<span>45-й</span>
</div>
<div class="insetSpec">
<span>Экстерьеры</span>
<span>10-й</span>
</div>
<div class="insetSpec">
<span>Архитектура</span>
<span>3-й</span>
</div>
<div class="insetSpec">
<span>3D Моделирование</span>
<span>100-й</span>
</div>
</div>
</div>
<div class="col-lg-4">
<ul class="rettList">
<li><a href="javascript:void(0)">Рейтинг: <span> 1245</span></a></li>
<li><a href="javascript:void(0)">Безопасные сделки: <span> 5</span></a></li>
<li>
<a href="javascript:void(0)">
Отзывы:
<span> + 385</span>
<small> 0</small>
<mark> - 0</mark>
</a>
</li>
</ul>
<div class="sroUser">
<div class="iconSRO"></div>
<p>Есть допуск СРО</p>
</div>
</div>
</div>
<div class="col-lg-9">
<div class="profileTabs2">
<ul class="nav nav-tabs nav-justified">
<li role="presentation" class="active">
<a href="#tab11" data-toggle="tab">Портфолио</a>
</li>
<li role="presentation">
<a href="#tab12" data-toggle="tab">Готовые проекты</a>
</li>
<li role="presentation">
<a href="#tab13" data-toggle="tab">Отзывы</a>
</li>
</ul>
</div>
</div>
<div class="tab-content">
<div id="tab11" class="tab-pane fade in active">
<div class="galleryWork2 disTab">
{% for p in portfolios %}
<div class="col-lg-9 divCol9">
<div class="col-lg-4">
<div class="insetCol box-sizing disTab">
<div class="imgGal"
style="background:rgba(0, 0, 0, 0) url('{{ p.get_cover }}') no-repeat scroll center center / cover ;">
<div class="imgFigure"></div>
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ p.name }}</p>
<div class="buttonsImg" disTab>
<a href="{% url 'projects:contractor-portfolio-edit' p.pk %}">
<div class="insetBI insetBI1">
<i class="fa fa-pencil"></i>
</div>
</a>
<div class="insetBI insetBI2">
<i class="fa fa-times"></i>
</div>
</div>
</div>
<p class="nameUser">
{{ contractor.team }}
</p>
<p class="cityUser">Россия, Москва</p>
{# <p class="navv">На сайте 8 лет и 3 месяца</p>#}
<p class="navv">На сайте {{ contractor.team.created }}</p>
<p class="navv">
Кол-во человек: <span>{{ participants_count }}</span>
</p>
<p class="navv">
Выполненных проектов: <span>0</span>
</p>
<div class="statusUser st-new">Свободен</div>
<a href="javascript:void(0)" class="new-prop new-prop2 new-prop3">написать сообщение</a>
</div>
{% endfor %}
<div class="col-lg-4">
{% specialization_widget contractor.pk %}
</div>
<div class="col-lg-9 col-lg-offset-3">
<div class="linkElse">
<a href="javascript:void(0)" class="showElse">показать еще</a>
<div class="col-lg-4">
{% if contractor.team %}
{% ratings_team_widget contractor.team.pk %}
{% endif %}
<div class="sroUser">
<div class="iconSRO"></div>
<p>Есть допуск СРО</p>
</div>
</div>
</div>
<div id="tab12" class="tab-pane fade">
<div class="galleryWork2 disTab">
{% for ws in work_sells %}
<div class="col-lg-4">
<div class="insetCol box-sizing disTab">
<div class="imgGal"
style="background:rgba(0, 0, 0, 0) url('/media/{{ ws.img }}') no-repeat scroll center center / cover ;">
<div class="imgFigure"></div>
<div class="col-lg-9">
<div class="profileTabs2">
<ul class="nav nav-tabs nav-justified">
<li role="presentation" class="active">
<a href="#tab11" data-toggle="tab">Портфолио</a>
</li>
<li role="presentation">
<a href="#tab12" data-toggle="tab">Готовые проекты</a>
</li>
<li role="presentation">
<a href="#tab13" data-toggle="tab">Отзывы</a>
</li>
</ul>
</div>
</div>
<div class="tab-content">
<div id="tab11" class="tab-pane fade in active">
<div class="galleryWork2 disTab">
{% for p in portfolios %}
<div class="col-lg-4">
<div class="insetCol box-sizing disTab">
<div class="imgGal"
style="background:rgba(0, 0, 0, 0) url('{{ p.get_cover }}') no-repeat scroll center center / cover ;">
<div class="imgFigure"></div>
</div>
</div>
<div class="cenaImg box-sizing">
<div class="cenaImgInset">
{{ ws.budget }} <i class="fa fa-rub"></i>
<div class="insetCol2 box-sizing disTab">
<p>{{ p.name }}</p>
<div class="buttonsImg" disTab>
<a href="{% url 'projects:contractor-portfolio-edit' p.pk %}">
<div class="insetBI insetBI1">
<i class="fa fa-pencil"></i>
</div>
</a>
<div class="insetBI insetBI2">
<i class="fa fa-times"></i>
</div>
</div>
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ ws }}</p>
{% endfor %}
</div>
</div>
<div class="col-lg-9 col-lg-offset-3">
<div class="linkElse">
<a href="javascript:void(0)" class="showElse">показать еще</a>
</div>
{% endfor %}
</div>
</div>
<div class="col-lg-9 col-lg-offset-3">
<div class="linkElse">
<a href="javascript:void(0)" class="showElse">показать еще</a>
<div id="tab12" class="tab-pane fade">
<div class="galleryWork2 disTab">
{% for ws in work_sells %}
<div class="col-lg-4">
<div class="insetCol box-sizing disTab">
<div class="imgGal"
style="background:rgba(0, 0, 0, 0) url('/media/{{ ws.img }}') no-repeat scroll center center / cover ;">
<div class="imgFigure"></div>
</div>
<div class="cenaImg box-sizing">
<div class="cenaImgInset">
{{ ws.budget }} <i class="fa fa-rub"></i>
</div>
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ ws }}</p>
</div>
</div>
{% endfor %}
</div>
<div class="col-lg-9 col-lg-offset-3">
<div class="linkElse">
<a href="javascript:void(0)" class="showElse">показать еще</a>
</div>
</div>
</div>
</div>
<div id="tab13" class="tab-pane fade">
<div class="new-comm-44">
<div class="col-lg-12">
<p class="nameComm">
<a href="#">Иванов Петр Иванович</a>
</p>
<div id="tab13" class="tab-pane fade">
<div class="new-comm-44">
<div class="col-lg-12">
<p class="nameComm">
<a href="#">Иванов Петр Иванович</a>
</p>
<span class="dateComm44">
Безопасная сделка
</span>
<div class="stars box-sizing">
<span class="glyphicon glyphicon-star starAct" aria-hidden="true"></span>
<span class="glyphicon glyphicon-star starAct" aria-hidden="true"></span>
<span class="glyphicon glyphicon-star starAct" aria-hidden="true"></span>
<span class="glyphicon glyphicon-star" aria-hidden="true"></span>
<span class="glyphicon glyphicon-star" aria-hidden="true"></span>
<a href="#">положительный отзыв</a>
</div>
<p class="textComm44">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum
<div class="stars box-sizing">
<span class="glyphicon glyphicon-star starAct" aria-hidden="true"></span>
<span class="glyphicon glyphicon-star starAct" aria-hidden="true"></span>
<span class="glyphicon glyphicon-star starAct" aria-hidden="true"></span>
<span class="glyphicon glyphicon-star" aria-hidden="true"></span>
<span class="glyphicon glyphicon-star" aria-hidden="true"></span>
<a href="#">положительный отзыв</a>
</div>
<p class="textComm44">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum
</p>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% include 'partials/footer.html' %}
</div>
</div>
</div>
{% include 'partials/footer.html' %}
</div>
</div>
{% endblock %}

@ -1,6 +1,5 @@
{% extends 'partials/base.html' %}
{% load projects_tags %}
{% load specializtions_tags %}
{% load thumbnail %}
@ -29,7 +28,7 @@
<span></span>
</li>
{% endif %}
{% if contractor.pk != user.id %}
{% if contractor.pk != request.user.pk and request.user.is_contractor %}
<li class="icon_um2">
<a href="javascript:void(0)">
@ -37,22 +36,26 @@
</a>
<span></span>
</li>
{% endif %}
{% if contractor.pk != request.user.pk %}
<li class="icon_um3">
<a href="javascript:void(0)">
<a href="{% url 'chat:chat-user' %}?user_id={{ contractor.pk }}">
написать сообщение
</a>
<span></span>
</li>
{% endif %}
{% if request.user.is_customer %}
<li class="icon_um4">
<a href="javascript:void(0)">
предложить заказ
</a>
<span></span>
</li>
{% endif %}
</ul>
</div>
</div>
@ -147,7 +150,12 @@
</div>
</a>
<div class="insetBI insetBI2">
<i class="fa fa-times"></i>
<form action="{% url 'projects:contractor-portfolio-trash' pk=p.pk %}" method="POST" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<a href="#" onclick="$(this).closest('form').submit(); return false"><i class="fa fa-times"></i></a>
</form>
</div>
</div>
</div>
@ -188,13 +196,17 @@
{% for ws in user.work_sell.all %}
<div class="col-lg-4">
<div class="insetCol box-sizing disTab">
<div class="imgGal"
style="background:rgba(0, 0, 0, 0) url('/media/{{ ws.img }}') no-repeat scroll center center / cover ;">
{% thumbnail ws.get_cover "224x224" crop="center" as im %}
<div class="imgGal" style="background:rgba(0, 0, 0, 0) url('{{ im.url }}') no-repeat scroll center center / cover ;">
<div class="imgFigure"></div>
</div>
{% endthumbnail %}
<div class="cenaImg box-sizing">
<div class="cenaImgInset">
{{ ws.budget }} <i class="fa fa-rub"></i>
</div>
</div>
</div>
@ -207,7 +219,12 @@
</a>
</div>
<div class="insetBI insetBI2">
<i class="fa fa-times"></i>
<form action="{% url 'work_sell:contractor-worksell-trash' pk=ws.pk %}" method="POST" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
<a href="#" onclick="$(this).closest('form').submit(); return false"><i class="fa fa-times"></i></a>
</form>
</div>
</div>
</div>

@ -22,7 +22,9 @@
<div class="col-lg-3 divCol3">
<div class="avatar">
<div class="avatarInset">
<img src="{{ form.avatar.value.url }}" alt="profile-image">
{% if form.avatar.value %}
<img src="{{ form.avatar.value.url }}" alt="profile-image">
{% endif %}
</div>
</div>
<div class="menuUser upload-img disTab">

@ -41,7 +41,7 @@
<p>Бюджет{{ worksell_form.budget.errors.as_text }}</p>
<div class="row">
<div class="col-lg-8">
<input type="text" class="box-sizing" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}">
<input type="text" class="box-sizing" name="{{ worksell_form.budget.html_name }}" value="{{ worksell_form.budget.value }}">
</div>
<div class="col-lg-4">
{{ worksell_form.currency}}
@ -53,7 +53,7 @@
<p>Срок выполнения{{ worksell_form.budget.errors.as_text }}</p>
<div class="row">
<div class="col-lg-8">
<input type="text" class="box-sizing" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}">
<input type="text" class="box-sizing" name="{{ worksell_form.term.html_name }}" value="{{ worksell_form.term.value }}">
</div>
<div class="col-lg-4">
{{ worksell_form.term_type }}
@ -76,7 +76,8 @@
</div>
<div class="polsF1 polsF2 disTab">
<input type="text" name="" id="upload-files-worksell-pk" />
<input type="text" name="images-ids" id="upload-files-worksell-pk" />
</div>
<!-- The fileinput-button span is used to style the file input field as button -->

@ -14,6 +14,7 @@ from .views import (
UserFinancialInfoEditView,
UserListView,
UserProfileEditView,
TeamCreateView,
)
@ -31,6 +32,7 @@ urlpatterns = [
urls.url(r'^customers/(?P<pk>\d+)/reviews/$', CustomerProfileReviewsView.as_view(), name='customer-profile-reviews'),
urls.url(r'^contractors/$', ContractorFilterView.as_view(), name='contractor-filter'),
urls.url(r'^contractors/team/create/$', TeamCreateView.as_view(), name='team-create'),
urls.url(r'^contractors/(?P<pk>\d+)/$', ContractorProfileDetailView.as_view(), name='contractor-profile'),
urls.url(r'^contractor-office/(?P<pk>\d+)/$', ContractorOfficeDetailView.as_view(), name='contractor-office'),

@ -365,8 +365,9 @@ class ContractorOfficeDetailView(DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form_team'] = TeamForm
participants = []
if self.object.is_owner_team():
participants = self.object.team.users.all()
participants = self.object.team.contractors.all()
user_ids = [p.pk for p in participants]
context['participants'] = participants
context['participants_count'] = len(participants)
@ -484,6 +485,20 @@ class CustomerProfileCurrentProjectsView(BaseMixin, DetailView):
context_object_name = 'customer'
class TeamCreateView(View):
form_class = TeamForm
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
# import code; code.interact(local=dict(globals(), **locals()))
if form.is_valid():
instance = form.save(commit=False)
instance.owner = request.user
instance.save()
return redirect('users:contractor-office', pk=request.user.pk)
class CustomerProfileReviewsView(BaseMixin, View):
template_name = 'customer_profile_reviews.html'

@ -4,6 +4,16 @@ from common.models import Location
from .models import WorkSell
class ContractorWorkSellTrashForm(forms.Form):
pk = forms.ModelChoiceField(queryset=WorkSell.objects.none())
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
self.fields['pk'].queryset = self.request.user.work_sell.all()
class WorkSellForm(forms.ModelForm):
class Meta:

@ -31,6 +31,10 @@ class WorkSell(models.Model):
def is_author_for_work(self):
pass
def get_cover(self):
photo = self.photos.first()
return photo and photo.img
class Meta:
ordering = ['-created']
verbose_name = 'Готовая работа'

@ -118,7 +118,7 @@
<div class="col-lg-3">
<div class="insetCol box-sizing disTab">
<a href="{% url 'work_sell:detail' work.pk %}">
{% thumbnail work.img "265x265" crop="center" as im %}
{% thumbnail work.get_cover "265x265" crop="center" as im %}
<div class="imgGal" style="background: url('{{ im.url }}') no-repeat center;">
<div class="imgFigure"></div>
</div>
@ -126,13 +126,14 @@
</a>
<div class="cenaImg box-sizing">
<div class="cenaImgInset">
{{ work.budget }} <i class="fa fa-rub"></i>
{{ work.budget }}<i class="fa fa-rub"></i>
</div>
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<p>{{ work }}</p>
{% if request.user.pk == work.contractor.pk %}
<div class="buttonsImg" disTab>
<a href="{% url 'work_sell:edit' work.pk %}">
<div class="insetBI insetBI1">
@ -145,6 +146,7 @@
</div>
</a>
</div>
{% endif %}
</div>
</div>
{% endfor %}

@ -10,6 +10,7 @@ from .views import (
work_sell_create,
BasicCreateView,
PictureCreateView,
ContractorWorkSellTrashView,
)
@ -21,6 +22,7 @@ urlpatterns = [
urls.url(r'^upload/$', UploadView.as_view(), name='upload'),
urls.url(r'^(?P<pk>\d+)/edit/$',WorkSellUpdateView.as_view(), name='edit'),
urls.url(r'^(?P<pk>\d+)/delete/$',WorkSellDeleteView.as_view(), name='delete'),
urls.url(r'^(?P<pk>\d+)/trash/$', ContractorWorkSellTrashView.as_view(), name='contractor-worksell-trash'),
urls.url(r'^test/$', work_sell_create, name='test'),
urls.url(r'^basic/$', BasicCreateView.as_view(), name='upload-basic'),
urls.url(r'^new/$', PictureCreateView.as_view(), name='upload-new'),

@ -1,13 +1,20 @@
import json
from django.shortcuts import render
import pydash as _;
_.map = _.map_;
_.filter = _.filter_
from pprint import pprint, pformat
from django.shortcuts import render, redirect
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.http import JsonResponse, HttpResponse
from django.views.generic import ListView, DetailView, CreateView, View,\
from django.core.files.base import ContentFile
from django.views.generic import ListView, DetailView, CreateView, View, \
UpdateView, DeleteView, TemplateView
from projects.models import BuildingClassfication, ConstructionType
from .models import WorkSell, Picture
from .forms import WorkSellForm
from .models import WorkSell, Picture, WorkSellPhoto
from .forms import WorkSellForm, ContractorWorkSellTrashForm
from .serialize import serialize
from .response import JSONResponse, response_mimetype
@ -37,7 +44,7 @@ class WorkSellsView(ListView):
model = WorkSell
template_name = 'worksells_list.html'
# paginate_by = 20
paginate_by = 1
paginate_by = 18
def get_form_kwargs(self, **kwargs):
kwargs = super().get_form_kwargs
@ -72,6 +79,15 @@ def work_sell_create(request):
if form.is_valid():
instance = form.save(commit=False)
instance.save()
images_ids = request.POST.get('images-ids').split(';')[:-1]
for pk in images_ids:
picture = Picture.objects.get(pk=pk)
temp_file = ContentFile(picture.file.read())
temp_file.name = picture.file.name
w_photo = WorkSellPhoto()
w_photo.img = temp_file
w_photo.worksell = instance
w_photo.save()
data = {'status': 'ok'}
else:
data = {'status': 'no', 'form_errors': form.errors}
@ -101,13 +117,27 @@ class WorkSellDeleteView(DeleteView):
return reverse('work_sell:list')
class ContractorWorkSellTrashView(View):
form_class = ContractorWorkSellTrashForm
def post(self, request, *args, **kwargs):
form = self.form_class(_.merge({}, request.POST, kwargs), request=request)
if form.is_valid():
worksell = form.cleaned_data.get('pk')
worksell.delete()
messages.info(request, 'Готовая работа удалена')
else:
messages.info(request, 'Произошла ошибка: <pre>{msg}</pre>'.format(msg=pformat(form.errors)))
redirect_to = request.POST.get('next')
return redirect(redirect_to)
class UploadView(View):
template_name = 'upload.html'
def get(self, request, *args, **kwargs):
return render(request,self.template_name)
return render(request, self.template_name)
class JSONResponseMixin(object):
@ -125,5 +155,3 @@ class JSONResponseMixin(object):
class JSONView(JSONResponseMixin, TemplateView):
def render_to_response(self, context, **response_kwargs):
return self.render_to_json_response(context, **response_kwargs)

Loading…
Cancel
Save