remotes/origin/setup
ArturBaybulatov 10 years ago
commit ddc57455b4
  1. 9
      archilance/settings/gunicorn.conf.py
  2. 1
      archilance/urls.py
  3. 2
      archilance/wsgi.py
  4. 1366
      chat/templates/chat.js
  5. 226
      chat/templates/chat_customer.html
  6. 2
      chat/testapp.py
  7. 9
      chat/views.py
  8. 29
      common/migrations/0004_auto_20160808_1557.py
  9. 20
      common/migrations/0005_settings_accountant_send_email.py
  10. 3
      common/models.py
  11. 2
      common/views.py
  12. 9
      projects/forms.py
  13. 47
      projects/templates/project_detail.html
  14. 25
      projects/templates/templatetags/ratings_widget.html
  15. 10
      projects/templatetags/projects_tags.py
  16. 2
      projects/urls.py
  17. 26
      projects/views.py
  18. 1
      ratings/__init__.py
  19. 0
      ratings/management/__init__.py
  20. 0
      ratings/management/commands/__init__.py
  21. 23
      ratings/management/commands/recalculation_rating.py
  22. 43
      ratings/management/commands/recalculation_spec.py
  23. 7
      ratings/models.py
  24. 12
      ratings/templates/templatetags/ratings_widget.html
  25. 9
      ratings/templates/templatetags/specializations_widget.html
  26. 0
      ratings/templatetags/__init__.py
  27. 41
      ratings/templatetags/specializtions_tags.py
  28. 1
      requirements/base.txt
  29. 21
      specializations/templates/templatetags/specializations_widget.html
  30. 20
      specializations/templatetags/specializtions_tags.py
  31. 47
      templates/partials/header.html
  32. 44
      templates/registration/login.html
  33. 11
      users/admin.py
  34. 25
      users/migrations/0007_auto_20160808_1557.py
  35. 6
      users/mixins.py
  36. 3
      users/models.py
  37. 449
      users/templates/contractor_office.html
  38. 45
      users/templates/contractor_profile.html
  39. 4
      users/templates/partials/customer_profile_info_block.html
  40. 4
      users/templates/user_profile_edit.html
  41. 7
      users/templates/worksell_create_form.html
  42. 2
      users/urls.py
  43. 33
      users/views.py
  44. 14
      wallets/admin.py
  45. 13
      wallets/forms.py
  46. 20
      wallets/migrations/0004_invoicehistory_balance.py
  47. 43
      wallets/migrations/0005_auto_20160809_1727.py
  48. 28
      wallets/models.py
  49. 20
      wallets/signals.py
  50. 126
      wallets/templates/score-detail.html
  51. 1
      wallets/templates/send_for_accountant.html
  52. 2
      wallets/templates/send_for_accountant.txt
  53. 10
      wallets/urls.py
  54. 70
      wallets/views.py
  55. 10
      work_sell/forms.py
  56. 4
      work_sell/models.py
  57. 6
      work_sell/templates/worksell_detail.html
  58. 6
      work_sell/templates/worksells_list.html
  59. 2
      work_sell/urls.py
  60. 46
      work_sell/views.py

@ -0,0 +1,9 @@
bind = '127.0.0.1:8046'
workers = 3
user = "www-data"
reload = True
try:
from local_gunicorn import *
except ImportError:
pass

@ -15,6 +15,7 @@ urlpatterns = [
url(r'^work_sell/', include('work_sell.urls')), url(r'^work_sell/', include('work_sell.urls')),
url(r'^test/$', TemplateView.as_view(template_name='test.html'), name='test'), url(r'^test/$', TemplateView.as_view(template_name='test.html'), name='test'),
url(r'^projects/', include('projects.urls')), url(r'^projects/', include('projects.urls')),
url(r'^wallets/', include('wallets.urls')),
url(r'^chat/', include('chat.urls')), url(r'^chat/', include('chat.urls')),
url(r'^specializations/', include('specializations.urls')), url(r'^specializations/', include('specializations.urls')),
url(r'^users/', include('users.urls')), url(r'^users/', include('users.urls')),

@ -11,7 +11,7 @@ from django.core.wsgi import get_wsgi_application
from django.template.base import Variable from django.template.base import Variable
import os import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archilance.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archilance.settings.prod")
application = get_wsgi_application() application = get_wsgi_application()

File diff suppressed because it is too large Load Diff

@ -237,6 +237,69 @@
var socket = new SocketHandler(); var socket = new SocketHandler();
var form = document.getElementById('message_form'); var form = document.getElementById('message_form');
var csrftoken = getCookie('csrftoken'); var csrftoken = getCookie('csrftoken');
function getStages(orderId){
$.ajax({
url: '/api/stages/',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
dataType: 'json',
success: function (json) {
var stageCount = json.results.length;
if (stageCount == 0){
stageCountVal = 1;
}else{
stageCountVal = stageCount;
}
var htmlInbox = "";
var htmlInboxStage = '<p class="textStepss">Какое кол-во этапов подразумевает работа? ' +
'<input type="text" id="countStage" value="'+ stageCountVal +'"size="3"/></p>';
if (stageCount == 0){
htmlInboxStage += '<div class="numberStepp box-sizing" id="stage1">' +
'<p>Этап <span class="stage-span-id">1</span></p><form class="new-stages-form" id="stage-form">' +
'<label for="">Название</label><input class="form-control" name="name" type="text" />' +
'<label for="">Цена</label><input class="form-control" name="cost" type="text" />' +
'<input class="form-control" name="order" type="text" value="'+ orderId +'" class="orderStagesInput"/> />' +
'<label for="">Срок</label><input class="form-control" name="term" type="text" />' +
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' +
'</form></div>';
}
var statusNotAgreed = true;
$.each(json.results, function (i, v) {
if (v.status == "not_agreed") {
htmlInbox += '<div class="numberStepp box-sizing">' +
'<p>Этап</p><form class="update-stages-form" data-order-id="'+ v.order +'" id="stage-form-'+ v.pos +'">' +
'<label for="">Название</label><input class="form-control" type="text" name="name" value="'+ v.name +'" />' +
'<label for="">Цена</label><input class="form-control" type="text" name="cost" value="'+ v.cost +'" />' +
'<input class="form-control" type="hidden" name="order" value="'+ v.order +'" />' +
'<label for="">Срок</label><input class="form-control" type="text" name="term" value="'+ v.term +'" />' +
'<label for="">Результат</label><input class="form-control" type="text" name="result" value="'+ v.result +'" />' +
'</form></div>';
} else {
statusNotAgreed = false;
htmlInboxStage = "";
htmlInbox += '<div class="numberStepp box-sizing"><div class="insetNumStepp">' +
'<p class="titleNumStepp"><span>Этап ' + v.pos + '</span>' + v.name + '</p>' +
'<p class="textNumStepp">Результаты этапа:' + v.result + '</p><div>' +
'<p>до 16.03.2015</p><span>' + v.cost + '<i class="fa fa-rub"></i></span></div></div></div>';
}
});
if (statusNotAgreed) {
htmlInbox += '<div class="box-sizing disTab" style="text-align:center;"><div class="checkbox"><input type="checkbox" style="opacity:1">Перейти в режим безопасной сделки' +
'</div></div><div class="textAreaBlock2 box-sizing disTab">' +
'<a href="#" data-order-id="' + orderId + '" id="addStagesForm">отправить на согласование</a> </div>';
}
htmlInbox = htmlInboxStage + htmlInbox;
$("#order-stages").html(htmlInbox);
}
});
}
setTimeout(function(){ setTimeout(function(){
$(".user-block").first().trigger('click'); $(".user-block").first().trigger('click');
}, 10); }, 10);
@ -245,10 +308,10 @@
$(".order-block").first().trigger('click'); $(".order-block").first().trigger('click');
}, 100); }, 100);
$("#order-stages").on('click', "#addStagesForm", function(){ $("#order-stages").on('click', "#addStagesForm", function(e){
e.preventDefault();
$(".new-stages-form").each(function(i,v){ $(".new-stages-form").each(function(i,v){
console.log($(this).serialize()); console.log($(this).serialize());
alert($(this).serialize());
$.ajax({ $.ajax({
url: '/api/stages/', url: '/api/stages/',
@ -260,6 +323,7 @@
dataType: 'json', dataType: 'json',
success: function (json) { success: function (json) {
console.log(json); console.log(json);
}, },
error: function(e){ error: function(e){
console.log('error'); console.log('error');
@ -268,14 +332,41 @@
}); });
}); });
$(".update-stages-form").each(function(i,v){
var currentStageId = parseInt($(this).attr('data-order-id'));
alert(currentStageId);
$.ajax({
url: '/api/stages/' + currentStageId + '/',
type: 'PUT',
beforeSend: function(xhr){
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
data: $(this).serialize(),
dataType:'json',
success: function(json){
console.log(json);
},
error: function(e){
console.log('error');
console.log(e);
}
});
});
var currentOrderId = $(this).attr('data-order-id');
currentOrderId = parseInt(currentOrderId);
getStages(currentOrderId);
}); });
$('#order-stages-tab').on('change', '#countStage', function(){ $('#order-stages-tab').on('change', '#countStage', function(){
var countStage = parseInt($(this).val()); var countStage = parseInt($(this).val());
var updateFormStages = $(".update-stages-form"); var updateFormStages = $(".update-stages-form");
alert(updateFormStages.length);
alert(typeof updateFormStages.length);
var limitCount = countStage + 1; var limitCount = countStage + 1;
for (var i = 2; i < limitCount; i++) { for (var i = 2; i < limitCount; i++) {
var stageCopy = $("#stage1").clone().attr("id", "stage" + i).addClass("stages_form"); var stageCopy = $("#stage1").clone().attr("id", "stage" + i).addClass("stages_form");
@ -321,65 +412,67 @@
} }
}); });
$.ajax({ getStages(orderId);
url: '/api/stages/',
type: 'GET', {# $.ajax({#}
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId}, {# url: '/api/stages/',#}
dataType: 'json', {# type: 'GET',#}
success: function (json) { {# data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},#}
var stageCount = json.results.length; {# dataType: 'json',#}
if (stageCount == 0){ {# success: function (json) {#}
stageCountVal = 1; {# var stageCount = json.results.length;#}
}else{ {# if (stageCount == 0){#}
stageCountVal = stageCount; {# stageCountVal = 1;#}
} {# }else{#}
{# stageCountVal = stageCount;#}
var htmlInbox = ""; {# }#}
{##}
var htmlInboxStage = '<p class="textStepss">Какое кол-во этапов подразумевает работа? ' + {# var htmlInbox = "";#}
'<input type="text" id="countStage" value="'+ stageCountVal +'"size="3"/></p>'; {##}
{# var htmlInboxStage = '<p class="textStepss">Какое кол-во этапов подразумевает работа? ' +#}
if (stageCount == 0){ {# '<input type="text" id="countStage" value="'+ stageCountVal +'"size="3"/></p>';#}
htmlInboxStage += '<div class="numberStepp box-sizing" id="stage1">' + {##}
'<p>Этап <span class="stage-span-id">1</span></p><form class="new-stages-form" id="stage-form">' + {# if (stageCount == 0){#}
'<label for="">Название</label><input class="form-control" name="name" type="text" />' + {# htmlInboxStage += '<div class="numberStepp box-sizing" id="stage1">' +#}
'<label for="">Цена</label><input class="form-control" name="cost" type="text" />' + {# '<p>Этап <span class="stage-span-id">1</span></p><form class="new-stages-form" id="stage-form">' +#}
'<input class="form-control" name="order" type="text" value="'+ orderId +'" class="orderStagesInput"/> />' + {# '<label for="">Название</label><input class="form-control" name="name" type="text" />' +#}
'<label for="">Срок</label><input class="form-control" name="term" type="text" />' + {# '<label for="">Цена</label><input class="form-control" name="cost" type="text" />' +#}
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' + {# '<input class="form-control" name="order" type="hidden" value="'+ orderId +'" class="orderStagesInput"/> />' +#}
'</form></div>'; {# '<label for="">Срок</label><input class="form-control" name="term" type="text" />' +#}
} {# '<label for="">Результат</label><input class="form-control" name="result" type="text" />' +#}
var statusNotAgreed = true; {# '</form></div>';#}
$.each(json.results, function (i, v) { {# }#}
if (v.status == "not_agreed") { {# var statusNotAgreed = true;#}
htmlInbox += '<div class="numberStepp box-sizing">' + {# $.each(json.results, function (i, v) {#}
'<p>Этап</p><form class="update-stages-form" id="stage-form-'+ v.pos +'">' + {# if (v.status == "not_agreed") {#}
'<label for="">Название</label><input class="form-control" type="text" value="'+ v.name +'" />' + {# htmlInbox += '<div class="numberStepp box-sizing">' +#}
'<label for="">Цена</label><input class="form-control" type="text" value="'+ v.cost +'" />' + {# '<p>Этап</p><form class="update-stages-form" id="stage-form-'+ v.pos +'">' +#}
'<input class="form-control" type="hidden" value="'+ v.order +'" />' + {# '<label for="">Название</label><input class="form-control" type="text" value="'+ v.name +'" />' +#}
'<label for="">Срок</label><input class="form-control" type="text" value="'+ v.term +'" />' + {# '<label for="">Цена</label><input class="form-control" type="text" value="'+ v.cost +'" />' +#}
'<label for="">Результат</label><input class="form-control" type="text" value="'+ v.result +'" />' + {# '<input class="form-control" type="hidden" value="'+ v.order +'" />' +#}
'</form></div>'; {# '<label for="">Срок</label><input class="form-control" type="text" value="'+ v.term +'" />' +#}
} else { {# '<label for="">Результат</label><input class="form-control" type="text" value="'+ v.result +'" />' +#}
statusNotAgreed = false; {# '</form></div>';#}
htmlInboxStage = ""; {# } else {#}
htmlInbox += '<div class="numberStepp box-sizing"><div class="insetNumStepp">' + {# statusNotAgreed = false;#}
'<p class="titleNumStepp"><span>Этап ' + v.pos + '</span>' + v.name + '</p>' + {# htmlInboxStage = "";#}
'<p class="textNumStepp">Результаты этапа:' + v.result + '</p><div>' + {# htmlInbox += '<div class="numberStepp box-sizing"><div class="insetNumStepp">' +#}
'<p>до 16.03.2015</p><span>' + v.cost + '<i class="fa fa-rub"></i></span></div></div></div>'; {# '<p class="titleNumStepp"><span>Этап ' + v.pos + '</span>' + v.name + '</p>' +#}
{# '<p class="textNumStepp">Результаты этапа:' + v.result + '</p><div>' +#}
} {# '<p>до 16.03.2015</p><span>' + v.cost + '<i class="fa fa-rub"></i></span></div></div></div>';#}
}); {##}
{# }#}
if (statusNotAgreed) { {# });#}
htmlInbox += '<div class="box-sizing disTab" style="text-align:center;"><div class="checkbox"><input type="checkbox" style="opacity:1">Перейти в режим безопасной сделки' + {##}
'</div></div><div class="textAreaBlock2 box-sizing disTab">' + {# if (statusNotAgreed) {#}
'<a href="javascript:void()" id="addStagesForm">отправить на согласование</a> </div>'; {# htmlInbox += '<div class="box-sizing disTab" style="text-align:center;"><div class="checkbox"><input type="checkbox" style="opacity:1">Перейти в режим безопасной сделки' +#}
} {# '</div></div><div class="textAreaBlock2 box-sizing disTab">' +#}
htmlInbox = htmlInboxStage + htmlInbox; {# '<a href="javascript:void()" data-order-id="'+ orderId +'" id="addStagesForm">отправить на согласование</a> </div>';#}
$("#order-stages").html(htmlInbox); {# }#}
} {# htmlInbox = htmlInboxStage + htmlInbox;#}
}); {# $("#order-stages").html(htmlInbox);#}
{# }#}
{# });#}
}); });
@ -456,8 +549,11 @@
}); });
var userId = '{{ request.user.pk }}';
var userId = '{{ request.user.pk }}';
var SocketHandler = function () { var SocketHandler = function () {
var url = 'ws://127.0.0.1:8888/chat/' + userId + '/'; var url = 'ws://127.0.0.1:8888/chat/' + userId + '/';
var sock = new WebSocket(url); var sock = new WebSocket(url);

@ -66,7 +66,7 @@ class ChatHandler(websocket.WebSocketHandler):
order_value = "NULL" if order_id is None else order_id 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) " \ 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) yield self.db.execute(insert_sql)
waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id) waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id)

@ -12,6 +12,8 @@ class ChatUserView(View):
template_name = '' template_name = ''
def get(self, request, *args, **kwargs): 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(): if request.user.is_authenticated() and request.user.is_customer():
customer_contacts = Message.objects.values_list('sender_id', 'recipent_id'). \ customer_contacts = Message.objects.values_list('sender_id', 'recipent_id'). \
filter(Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)).distinct() 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) users_ids.append(a)
if b != request.user.pk: if b != request.user.pk:
users_ids.append(b) 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) contacts_users = User.objects.filter(pk__in=users_ids)
chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk)) chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk))
@ -42,12 +47,14 @@ class ChatUserView(View):
users_ids.append(a) users_ids.append(a)
if b != request.user.pk: if b != request.user.pk:
users_ids.append(b) users_ids.append(b)
if user_id:
users_ids.append(int(user_id))
contacts_users = User.objects.filter(pk__in=users_ids) 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( chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk)).order_by(
'created') 'created')
if request.user.is_owner_team(): if request.user.is_owner_team():
team_orders = request.user.team.team_orders.all() team_orders = request.user.team.orders.all()
self.template_name = 'chat_contractor.html' self.template_name = 'chat_contractor.html'
return render(request, self.template_name, {'orders': orders, return render(request, self.template_name, {'orders': orders,

@ -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,
),
]

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-09 16:56
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('common', '0004_auto_20160808_1557'),
]
operations = [
migrations.AddField(
model_name='settings',
name='accountant_send_email',
field=models.EmailField(default='muhtarzubanchi05@gmail.com', max_length=100),
),
]

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

@ -46,7 +46,7 @@ class PrintDocumentCreate(BaseMixin, View):
} }
settings = Settings.objects.all().first().doc settings = Settings.objects.all().first()
subject, from_email, to = 'Заявка на распечатку', 'mukhtar@mukhtar', settings.document_send_email subject, from_email, to = 'Заявка на распечатку', 'mukhtar@mukhtar', settings.document_send_email
text_content = render_to_string('document_email.txt', ctx_dict) text_content = render_to_string('document_email.txt', ctx_dict)
html_content = get_template('document_email.html').render(ctx_dict) html_content = get_template('document_email.html').render(ctx_dict)

@ -235,6 +235,15 @@ class CustomerProjectTrashForm(forms.Form):
self.fields['pk'].queryset = self.req.user.projects.filter(state='active') 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): class CustomerProjectRestoreForm(forms.Form):
pk = forms.ModelChoiceField(queryset=Project.objects.none()) pk = forms.ModelChoiceField(queryset=Project.objects.none())

@ -1,7 +1,8 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load humanize %} {% load humanize %}
{% load thumbnail %}
{% load specializtions_tags %}
{% block content %} {% block content %}
{% include 'partials/header.html' %} {% include 'partials/header.html' %}
@ -317,7 +318,6 @@
<form action="{% url 'projects:detail' pk=project.pk %}" method="POST" enctype="multipart/form-data" novalidate> <form action="{% url 'projects:detail' pk=project.pk %}" method="POST" enctype="multipart/form-data" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}"> <input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}">
@ -419,10 +419,6 @@
{% elif request.user.is_customer %} {% elif request.user.is_customer %}
<div class="exBigBlock disTab"> <div class="exBigBlock disTab">
<div class="col-lg-12"> <div class="col-lg-12">
<p class="titleEx">Исполнители</p> <p class="titleEx">Исполнители</p>
@ -453,61 +449,47 @@
</div> </div>
{% for answer_p in project.answers.all %}
<div class="candidateBlock disTab"> <div class="candidateBlock disTab">
<div class="candidate"> <div class="candidate">
<div class="col-lg-4"> <div class="col-lg-4">
<a href="#" class="aLinkExe"> <a href="#" class="aLinkExe">
<div class="imgExecutor"> <div class="imgExecutor">
<img src="img/profile.jpg" alt="execitor-image"> {% thumbnail answer_p.author.avatar "126x125" crop="center" as im %}
<img src="{{ im.url }}" alt="execitor-image">
{% endthumbnail %}
</div> </div>
</a> </a>
<p class="nameExecutor"> <p class="nameExecutor">
<a href="#">Иванов Петр Иванович [ivanov_petr]</a> <a href="#">{{ answer_p.author.get_full_name }} [{{ answer_p.author.username }}]</a>
</p> </p>
<p class="navv2">На сайте 8 лет и 3 месяца</p> <p class="navv2">На сайте 8 лет и 3 месяца</p>
<div class="statusUser">Свободен</div> <div class="statusUser">Свободен</div>
</div> </div>
<div class="col-lg-3 retts"> <div class="col-lg-3 retts">
<ul class="rettList restList2"> {% ratings_widget answer_p.author.pk 'restList2' %}
<li>Рейтинг: <span> 1245</span></li> {% if answer_p.author.cro %}
<li>Безопасные сделки: <span> 5</span></li>
<li>
<a href="javascript:void(0)">Отзывы:
<span> + 385</span>
<small> 0</small>
<mark> - 0</mark>
</a>
</li>
</ul>
<div class="sroUser sroExecutor"> <div class="sroUser sroExecutor">
<div class="iconSRO"></div> <div class="iconSRO"></div>
<p>Есть допуск СРО</p> <p>Есть допуск СРО</p>
</div> </div>
{% endif %}
</div> </div>
<div class="col-lg-2 listCens"> <div class="col-lg-2 listCens">
<p>Цена: <p>Цена:
<span> 35 000</span> <span> {{ answer_p.budget }}</span>
<i class="fa fa-rub"></i> <i class="fa fa-rub"></i>
</p> </p>
<p> <p>
Срок: <span>3 недели</span> Срок: <span>{{ answer_p.term }} of {{ answer_p.term_type }}</span>
</p> </p>
<p>Опубликован: 22.04.2016</p> <p>Опубликован: {{ answer_p.created | date:"M d, Y" }}</p>
</div> </div>
<div class="col-lg-3 retts"> <div class="col-lg-3 retts">
<a href="javascript:void(0)" class="candLink candLink1"> <a href="javascript:void(0)" class="candLink candLink1">
Кандидат Кандидат
</a> </a>
<a href="javascript:void(0)" class="candLink candLink2"> <a href="{% url 'chat:chat-user' %}" class="candLink candLink2">
предложить проект предложить проект
</a> </a>
<a href="javascript:void(0)" class="candLink candLink3"> <a href="javascript:void(0)" class="candLink candLink3">
@ -584,6 +566,7 @@
</div> </div>
</div> </div>
</div> </div>
{% endfor %}
{% endif %} {% endif %}

@ -1,25 +0,0 @@
<ul class="rettList">
<li><a href="javascript:void(0)">Рейтинг: <span> {{ ratings }}</span></a></li>
<li><a href="javascript:void(0)">Безопасные сделки: <span> 0</span></a></li>
<li>
<a href="javascript:void(0)">
Отзывы:
<span> + 0</span>
<small> 0</small>
<mark> - 0</mark>
</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,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, ProjectComparisonView,
ProjectFilterView, ProjectFilterView,
ProjectDetailWithContractorAnswerView, ProjectDetailWithContractorAnswerView,
ContractorPortfolioTrashView,
) )
app_name = 'projects' app_name = 'projects'
@ -25,6 +26,7 @@ urlpatterns = [
urls.url(r'^create/$', CustomerProjectCreateView.as_view(), name='customer-project-create'), 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+)/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'^(?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+)/restore/$', CustomerProjectRestoreView.as_view(), name='customer-project-restore'),
urls.url(r'^(?P<pk>\d+)/delete/$', CustomerProjectDeleteView.as_view(), name='customer-project-delete'), urls.url(r'^(?P<pk>\d+)/delete/$', CustomerProjectDeleteView.as_view(), name='customer-project-delete'),

@ -15,7 +15,7 @@ import pydash as _; _.map = _.map_; _.filter = _.filter_
import re import re
from .mixins import LastAccessMixin 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 archilance.mixins import BaseMixin
from users.models import User from users.models import User
from work_sell.models import Picture from work_sell.models import Picture
@ -31,6 +31,7 @@ from .forms import (
ProjectFilterForm, ProjectFilterForm,
ProjectFilterRealtyForm, ProjectFilterRealtyForm,
RealtyForm, RealtyForm,
ContractorPortfolioTrashForm,
) )
@ -176,7 +177,7 @@ class ProjectFilterView(BaseMixin, View):
'<pre>{realty_form}</pre>' '<pre>{realty_form}</pre>'
).format(realty_form=pformat(realty_form.errors))) ).format(realty_form=pformat(realty_form.errors)))
# import code; code.interact(local=dict(globals(), **locals()))
paginator = Paginator(projects.all(), settings.PAGE_SIZE) paginator = Paginator(projects.all(), settings.PAGE_SIZE)
page = request.GET.get('page') page = request.GET.get('page')
@ -355,6 +356,21 @@ class CustomerProjectEditView(BaseMixin, View):
return render(request, self.template_name, context) 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): class CustomerProjectTrashView(View):
form_class = CustomerProjectTrashForm form_class = CustomerProjectTrashForm
@ -485,4 +501,10 @@ class ContractorPortfolioUpdateView(UpdateView):
return reverse('proje') 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())) # import code; code.interact(local=dict(globals(), **locals()))

@ -0,0 +1 @@
default_app_config = 'ratings.apps.RatingsConfig'

@ -0,0 +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,Team
class Command(BaseCommand):
def handle(self, *args, **options):
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()

@ -0,0 +1,43 @@
from django.core.management import BaseCommand
from specializations.models import Specialization
from ratings.models import SpecializationRating
from users.models import User, Team
class Command(BaseCommand):
def handle(self, *args, **options):
users = User.objects.values('pk', 'rating').filter(is_superuser=False).order_by('-rating')
teams = Team.objects.values('pk', 'rating').order_by('-rating')
result_list = []
for user in users:
result_list.append([user['rating'], 'user', user['pk']])
for team in teams:
result_list.append([team['rating'], 'team', team['pk'] ])
result_list = list(reversed(sorted(result_list)))
SpecializationRating.objects.all().delete()
specializations = Specialization.objects.all()
for spec in specializations:
i = 0
for res in result_list:
if 'user' in res[1]:
user = User.objects.get(pk=res[2])
team = None
specializations_current = user.contractor_specializations.all()
else:
team = Team.objects.get(pk=res[2])
user = None
specializations_current = team.specializations.all()
if spec in specializations_current:
i += 1
spec_rating = SpecializationRating()
spec_rating.position = i
spec_rating.user = user
spec_rating.team = team
spec_rating.specialization = spec
spec_rating.save()
print('The end')

@ -3,6 +3,7 @@ from django.utils import timezone
from users.models import User, Team from users.models import User, Team
from specializations.models import Specialization from specializations.models import Specialization
class HistoryRating(models.Model): class HistoryRating(models.Model):
user = models.ForeignKey(User, related_name='history_ratings', null=True, blank=True) user = models.ForeignKey(User, related_name='history_ratings', null=True, blank=True)
team = models.ForeignKey(Team, related_name='history_ratings', null=True, blank=True) team = models.ForeignKey(Team, related_name='history_ratings', null=True, blank=True)
@ -11,7 +12,7 @@ class HistoryRating(models.Model):
description = models.TextField(blank=True) description = models.TextField(blank=True)
def __str__(self): def __str__(self):
return self.rating return '{0}'.format(self.rating)
class Meta: class Meta:
verbose_name = 'История рейтинга' verbose_name = 'История рейтинга'
@ -25,12 +26,10 @@ class SpecializationRating(models.Model):
position = models.PositiveIntegerField(default=0) position = models.PositiveIntegerField(default=0)
def __str__(self): def __str__(self):
return self.position return '{0}'.format(self.pk)
class Meta: class Meta:
verbose_name = 'Рейтинг специализаций' verbose_name = 'Рейтинг специализаций'
verbose_name_plural = 'Рейтинги специализаций' verbose_name_plural = 'Рейтинги специализаций'

@ -0,0 +1,12 @@
<ul class="rettList {{ class_name }}">
<li><a href="javascript:void(0)">Рейтинг: <span> {{ ratings }}</span></a></li>
<li><a href="javascript:void(0)">Безопасные сделки: <span> 0</span></a></li>
<li>
<a href="javascript:void(0)">
Отзывы:
<span> + 0</span>
<small> 0</small>
<mark> - 0</mark>
</a>
</li>
</ul>

@ -0,0 +1,9 @@
<div class="dashedCol4">
<p class="specUser">Специализации:</p>
{% for spec in specializations %}
<div class="insetSpec">
<span>{{ spec.specialization.name }}</span>
<span>{{ spec.position }}-й</span>
</div>
{% endfor %}
</div>

@ -0,0 +1,41 @@
from django import template
from archilance import util
from users.models import User, Team
from ratings.models import SpecializationRating
register = template.Library()
@register.inclusion_tag('templatetags/specializations_widget.html', takes_context=True)
def specialization_widget(context, user_id):
user_id = int(user_id)
specializations = SpecializationRating.objects.select_related('specialization').filter(user_id=user_id)
return {
'specializations': specializations,
'user_id': user_id,
}
@register.inclusion_tag('templatetags/specializations_widget.html', takes_context=True)
def specialization_team_widget(context, team_id):
team_id = int(team_id)
specializations = SpecializationRating.objects.select_related('specialization').filter(team_id=team_id)
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,
'class_name': class_name
}
@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,
}

@ -38,3 +38,4 @@ sqlparse==0.1.19
tornado==4.3 tornado==4.3
natsort natsort
django-mathfilters django-mathfilters
gunicorn==19.6.0

@ -1,21 +0,0 @@
<div class="dashedCol4">
<p class="specUser">Специализации:</p>
{% for spec in specializations %}
<div class="insetSpec">
<span>{{ spec }}</span>
<span>2-й</span>
</div>
{% endfor %}
</div>
{# <div class="dashedCol4 dashedCol44 dashedColColor">#}
{# <p class="specUser">#}
{# Специализации:#}
{# </p>#}
{# <div class="insetSpec">#}
{# <span>Интерьеры</span>#}
{# </div>#}
{# #}
{# <div class="insetSpec">#}
{# <span>Визуализация/3D</span>#}
{# </div>#}
{# </div>#}

@ -1,20 +0,0 @@
from django import template
from archilance import util
from users.models import User
register = template.Library()
@register.inclusion_tag('templatetags/specializations_widget.html', takes_context=True)
def specialization_widget(context, user_id):
user_id = int(user_id)
user = util.get_or_none(User, pk=user_id)
if user:
specializations = user.contractor_specializations.all()
else:
specializations = None
return {
'specializations': specializations,
'user_id': user_id,
}

@ -21,7 +21,7 @@
<a href="{% url 'users:contractor-office' pk=request.user.pk %}">Мой офис</a> <a href="{% url 'users:contractor-office' pk=request.user.pk %}">Мой офис</a>
<span></span> <span></span>
</li> </li>
{% endif%} {% endif %}
{% if request.user.is_customer %} {% if request.user.is_customer %}
<li class="icon_tm2"> <li class="icon_tm2">
@ -29,7 +29,7 @@
<span></span> <span></span>
</li> </li>
<li class="icon_tm3"> <li class="icon_tm3">
<a href="#">Работы на продажу</a> <a href="{% url 'work_sell:list' %}">Работы на продажу</a>
<span></span> <span></span>
</li> </li>
{% endif %} {% endif %}
@ -59,22 +59,31 @@
<div class="imgProfile"> <div class="imgProfile">
{% if request.user.is_contractor %} {% if request.user.is_contractor %}
<a href="{% url 'users:contractor-profile' pk=request.user.pk %}"> <a href="{% url 'users:contractor-profile' pk=request.user.pk %}">
{% thumbnail request.user.avatar "75x75" crop="center" as im %} {% if request.user.avatar %}
<img src="{{ im.url }}" alt="profile-image"> {% thumbnail request.user.avatar "75x75" crop="center" as im %}
{% endthumbnail %} <img src="{{ im.url }}" alt="profile-image">
{% endthumbnail %}
{% else %}
<img src="{% static 'img/profile.jpg' %}" alt="profile-image">
{% endif %}
</a> </a>
{% elif request.user.is_customer %} {% elif request.user.is_customer %}
<a href="{% url 'users:customer-profile-open-projects' pk=request.user.pk %}"> <a href="{% url 'users:customer-profile-open-projects' pk=request.user.pk %}">
{% thumbnail request.user.avatar "75x75" crop="center" as im %} {% if request.user.avatar %}
<img src="{{ im.url }}" alt="profile-image"> {% thumbnail request.user.avatar "75x75" crop="center" as im %}
{% endthumbnail %} <img src="{{ im.url }}" alt="profile-image">
{% endthumbnail %}
{% else %}
<img src="{% static 'img/profile.jpg' %}" alt="profile-image">
{% endif %}
</a> </a>
{% endif %} {% endif %}
</div> </div>
<div class="infoProfile disTab"> <div class="infoProfile disTab">
<div class="btn-group" role="group"> <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> <span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
</button> </button>
<ul class="dropdown-menu menu-drop-new"> <ul class="dropdown-menu menu-drop-new">
@ -91,28 +100,16 @@
</a> </a>
</li> </li>
<li class="icon_mm3"> <li class="icon_mm3">
<a href="#"> <a href="#">Сообщения<span></span></a>
Сообщения
<span></span>
</a>
</li> </li>
<li class="icon_mm4"> <li class="icon_mm4">
<a href="#"> <a href="{% url 'wallets:score-detail' pk=request.user.pk %}">Счет<span></span></a>
Счет
<span></span>
</a>
</li> </li>
<li class="icon_mm5"> <li class="icon_mm5">
<a href="#"> <a href="#">Настройки<span></span></a>
Настройки
<span></span>
</a>
</li> </li>
<li class="icon_mm6"> <li class="icon_mm6">
<a href="#"> <a href="#">FAQ<span></span></a>
FAQ
<span></span>
</a>
</li> </li>
</ul> </ul>
</div> </div>

@ -1,24 +1,32 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% block content %} {% block content %}
<div class="col-lg-12"> {% include 'partials/header.html' %}
<p class="titleScore">Вход на сайт</p> <div class="container mainScore">
</div> <div class="row">
<div class="form-regestration"> <div class="col-lg-12">
{{ form.errors }} <p class="titleScore">Вход на сайт</p>
<form method="post">{% csrf_token %} </div>
<div class="col-lg-12 select-reg"> <div class="form-regestration">
<input type="text" name="{{ form.username.name }}" class="box-sizing email-reg" placeholder="Электронная почта"> {{ form.errors }}
</div> <form method="post">{% csrf_token %}
<div class="col-lg-12 select-reg"> <div class="col-lg-12 select-reg">
<input type="password" name="{{ form.password.name }}" class="box-sizing pass-reg" placeholder="Пароль"> <input type="text" name="{{ form.username.name }}" class="box-sizing email-reg"
</div> placeholder="Электронная почта">
<div class="col-lg-12 select-reg"> </div>
<button class="reg-sub">Вход</button> <div class="col-lg-12 select-reg">
</div> <input type="password" name="{{ form.password.name }}" class="box-sizing pass-reg" placeholder="Пароль">
</div>
<div class="col-lg-12 select-reg">
<button class="reg-sub">Вход</button>
</div>
</form> </form>
</div>
{% include 'partials/footer.html' %}
</div>
</div>
</div>
{% endblock %} {% endblock %}
a

@ -5,13 +5,20 @@ from .models import User, Team, UserFinancialInfo, ContractorResume, ContractorR
class UserAdmin(admin.ModelAdmin): class UserAdmin(admin.ModelAdmin):
readonly_fields = ('pk',) 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): def get_groups(self, obj):
return ', '.join(g.name for g in obj.groups.all()) 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(User, UserAdmin)
admin.site.register(UserFinancialInfo) admin.site.register(UserFinancialInfo)
admin.site.register(Team) admin.site.register(Team, TeamAdmin)
admin.site.register(ContractorResume) admin.site.register(ContractorResume)
admin.site.register(ContractorResumeFiles) 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),
),
]

@ -12,3 +12,9 @@ class CheckForUserMixin(object):
else: else:
return HttpResponseForbidden('403 Forbidden') return HttpResponseForbidden('403 Forbidden')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class OwnershipMixin(object):
def dispatch(self, request, *args, **kwargs):
pass

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

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

@ -1,6 +1,5 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load projects_tags %}
{% load specializtions_tags %} {% load specializtions_tags %}
{% load thumbnail %} {% load thumbnail %}
@ -28,20 +27,8 @@
</a> </a>
<span></span> <span></span>
</li> </li>
<li class="icon_um1">
<a href="{% url 'users:user-profile-edit' pk=contractor.pk %}">
редактировать профиль
</a>
<span></span>
</li>
<li class="icon_um1">
<a href="{% url 'users:user-profile-edit' pk=contractor.pk %}">
редактировать профиль
</a>
<span></span>
</li>
{% endif %} {% endif %}
{% if contractor.pk != user.id %} {% if contractor.pk != request.user.pk and request.user.is_contractor %}
<li class="icon_um2"> <li class="icon_um2">
<a href="javascript:void(0)"> <a href="javascript:void(0)">
@ -49,22 +36,26 @@
</a> </a>
<span></span> <span></span>
</li> </li>
{% endif %}
{% if contractor.pk != request.user.pk %}
<li class="icon_um3"> <li class="icon_um3">
<a href="javascript:void(0)"> <a href="{% url 'chat:chat-user' %}?user_id={{ contractor.pk }}">
написать сообщение написать сообщение
</a> </a>
<span></span> <span></span>
</li> </li>
{% endif %}
{% if request.user.is_customer %}
<li class="icon_um4"> <li class="icon_um4">
<a href="javascript:void(0)"> <a href="javascript:void(0)">
предложить заказ предложить заказ
</a> </a>
<span></span> <span></span>
</li> </li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
</div> </div>
@ -159,7 +150,12 @@
</div> </div>
</a> </a>
<div class="insetBI insetBI2"> <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> </div>
</div> </div>
@ -200,13 +196,17 @@
{% for ws in user.work_sell.all %} {% for ws in user.work_sell.all %}
<div class="col-lg-4"> <div class="col-lg-4">
<div class="insetCol box-sizing disTab"> <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 class="imgFigure"></div>
</div> </div>
{% endthumbnail %}
<div class="cenaImg box-sizing"> <div class="cenaImg box-sizing">
<div class="cenaImgInset"> <div class="cenaImgInset">
{{ ws.budget }} <i class="fa fa-rub"></i> {{ ws.budget }} <i class="fa fa-rub"></i>
</div> </div>
</div> </div>
</div> </div>
@ -219,7 +219,12 @@
</a> </a>
</div> </div>
<div class="insetBI insetBI2"> <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> </div>
</div> </div>

@ -1,6 +1,4 @@
{% load projects_tags %} {% load specializtions_tags %}
<div class="col-lg-12"> <div class="col-lg-12">
<div class="col-lg-3 divCol3"> <div class="col-lg-3 divCol3">
<div class="avatar new-mar"> <div class="avatar new-mar">

@ -22,7 +22,9 @@
<div class="col-lg-3 divCol3"> <div class="col-lg-3 divCol3">
<div class="avatar"> <div class="avatar">
<div class="avatarInset"> <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> </div>
<div class="menuUser upload-img disTab"> <div class="menuUser upload-img disTab">

@ -41,7 +41,7 @@
<p>Бюджет{{ worksell_form.budget.errors.as_text }}</p> <p>Бюджет{{ worksell_form.budget.errors.as_text }}</p>
<div class="row"> <div class="row">
<div class="col-lg-8"> <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>
<div class="col-lg-4"> <div class="col-lg-4">
{{ worksell_form.currency}} {{ worksell_form.currency}}
@ -53,7 +53,7 @@
<p>Срок выполнения{{ worksell_form.budget.errors.as_text }}</p> <p>Срок выполнения{{ worksell_form.budget.errors.as_text }}</p>
<div class="row"> <div class="row">
<div class="col-lg-8"> <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>
<div class="col-lg-4"> <div class="col-lg-4">
{{ worksell_form.term_type }} {{ worksell_form.term_type }}
@ -76,7 +76,8 @@
</div> </div>
<div class="polsF1 polsF2 disTab"> <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> </div>
<!-- The fileinput-button span is used to style the file input field as button --> <!-- The fileinput-button span is used to style the file input field as button -->

@ -14,6 +14,7 @@ from .views import (
UserFinancialInfoEditView, UserFinancialInfoEditView,
UserListView, UserListView,
UserProfileEditView, 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'^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/$', 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'^contractors/(?P<pk>\d+)/$', ContractorProfileDetailView.as_view(), name='contractor-profile'),
urls.url(r'^contractor-office/(?P<pk>\d+)/$', ContractorOfficeDetailView.as_view(), name='contractor-office'), urls.url(r'^contractor-office/(?P<pk>\d+)/$', ContractorOfficeDetailView.as_view(), name='contractor-office'),

@ -226,13 +226,13 @@ class ContractorFilterView(BaseMixin, View):
if get_teams: if get_teams:
teams = Team.objects.filter(Q(users__cro=cro) | Q(owner__cro=cro)) teams = Team.objects.filter(Q(contractors__cro=cro) | Q(owner__cro=cro))
if specialization: if specialization:
teams = teams.filter( teams = teams.filter(
( (
Q(users__contractor_specializations__lft__gte=specialization.lft) Q(contractors__contractor_specializations__lft__gte=specialization.lft)
& Q(users__contractor_specializations__rght__lte=specialization.rght) & Q(contractors__contractor_specializations__rght__lte=specialization.rght)
) | ( ) | (
Q(owner__contractor_specializations__lft__gte=specialization.lft) Q(owner__contractor_specializations__lft__gte=specialization.lft)
& Q(owner__contractor_specializations__rght__lte=specialization.rght) & Q(owner__contractor_specializations__rght__lte=specialization.rght)
@ -242,8 +242,8 @@ class ContractorFilterView(BaseMixin, View):
if location: if location:
teams = teams.filter( teams = teams.filter(
( (
Q(users__location__lft__gte=location.lft) Q(contractors__location__lft__gte=location.lft)
& Q(users__location__rght__lte=location.rght) & Q(contractors__location__rght__lte=location.rght)
) | ( ) | (
Q(owner__location__lft__gte=location.lft) Q(owner__location__lft__gte=location.lft)
& Q(owner__location__rght__lte=location.rght) & Q(owner__location__rght__lte=location.rght)
@ -252,19 +252,19 @@ class ContractorFilterView(BaseMixin, View):
if work_type: if work_type:
teams = teams.filter( teams = teams.filter(
Q(users__orders__project__work_type=work_type) Q(contractors__orders__project__work_type=work_type)
| Q(owner__orders__project__work_type=work_type), | Q(owner__orders__project__work_type=work_type),
) )
if build_classif: if build_classif:
teams = teams.filter( teams = teams.filter(
Q(users__orders__project__realty__building_classification=build_classif) Q(contractors__orders__project__realty__building_classification=build_classif)
| Q(owner__orders__project__realty__building_classification=build_classif), | Q(owner__orders__project__realty__building_classification=build_classif),
) )
if constr_type: if constr_type:
teams = teams.filter( teams = teams.filter(
Q(users__orders__project__realty__construction_type=constr_type) Q(contractors__orders__project__realty__construction_type=constr_type)
| Q(owner__orders__project__realty__construction_type=constr_type), | Q(owner__orders__project__realty__construction_type=constr_type),
) )
@ -365,8 +365,9 @@ class ContractorOfficeDetailView(DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['form_team'] = TeamForm context['form_team'] = TeamForm
participants = []
if self.object.is_owner_team(): 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] user_ids = [p.pk for p in participants]
context['participants'] = participants context['participants'] = participants
context['participants_count'] = len(participants) context['participants_count'] = len(participants)
@ -484,6 +485,20 @@ class CustomerProfileCurrentProjectsView(BaseMixin, DetailView):
context_object_name = 'customer' 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): class CustomerProfileReviewsView(BaseMixin, View):
template_name = 'customer_profile_reviews.html' template_name = 'customer_profile_reviews.html'

@ -1,5 +1,15 @@
from django.contrib import admin from django.contrib import admin
from .models import InvoiceHistory from .models import InvoiceHistory, WithDraw
admin.site.register(InvoiceHistory)
class InvoiceHistoryAdmin(admin.ModelAdmin):
list_display = ('comment', 'sum', 'user','balance',)
class WithDrawAdmin(admin.ModelAdmin):
list_display = ('sum','created','user',)
admin.site.register(InvoiceHistory, InvoiceHistoryAdmin)
admin.site.register(WithDraw, WithDrawAdmin)

@ -0,0 +1,13 @@
from django import forms
from .models import WithDraw
class WithDrawForm(forms.ModelForm):
class Meta:
model = WithDraw
fields = (
'sum',
'yandex_card',
'user',
)

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-09 09:22
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wallets', '0003_auto_20160729_1209'),
]
operations = [
migrations.AddField(
model_name='invoicehistory',
name='balance',
field=models.DecimalField(decimal_places=0, default=0, max_digits=10),
),
]

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-09 14:27
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('wallets', '0004_invoicehistory_balance'),
]
operations = [
migrations.CreateModel(
name='WithDraw',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sum', models.DecimalField(decimal_places=0, max_digits=10)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('yandex_card', models.CharField(max_length=30)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='with_draw', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name_plural': 'Заявки на вывод средств',
'ordering': ('-created',),
'verbose_name': 'Заявка на вывод средств',
},
),
migrations.AlterModelOptions(
name='invoicehistory',
options={'ordering': ('-created',), 'verbose_name': 'Счет(История)', 'verbose_name_plural': 'Счет(История)'},
),
migrations.AlterField(
model_name='invoicehistory',
name='type',
field=models.CharField(blank=True, max_length=20, null=True),
),
]

@ -1,4 +1,5 @@
from django.db import models from django.db import models
from django.db.models import Sum
from django.utils import timezone from django.utils import timezone
from users.models import User from users.models import User
@ -14,13 +15,36 @@ class InvoiceHistory(models.Model):
comment = models.TextField(blank=True) comment = models.TextField(blank=True)
created = models.DateTimeField(default=timezone.now) created = models.DateTimeField(default=timezone.now)
sum = models.DecimalField(max_digits=10, decimal_places=0, default=0, null=True, blank=True) sum = models.DecimalField(max_digits=10, decimal_places=0, default=0, null=True, blank=True)
type = models.CharField(max_length=20) balance = models.DecimalField(max_digits=10, decimal_places=0, default=0)
type = models.CharField(max_length=20, blank=True, null=True)
user = models.ForeignKey(User, related_name='invoice_history') user = models.ForeignKey(User, related_name='invoice_history')
def __str__(self): def __str__(self):
return self.pk return self.comment
def save(self, *args, **kwargs):
if self.pk is None:
current_sum_info = InvoiceHistory.objects.filter(user=self.user).aggregate(Sum('sum'))
current_sum = current_sum_info['sum__sum'] or 0
self.balance = current_sum + self.sum
super().save(*args, **kwargs)
class Meta: class Meta:
verbose_name = 'Счет(История)' verbose_name = 'Счет(История)'
verbose_name_plural = 'Счет(История)' verbose_name_plural = 'Счет(История)'
ordering = ('-created',)
class WithDraw(models.Model):
sum = models.DecimalField(max_digits=10, decimal_places=0)
created = models.DateTimeField(default=timezone.now)
yandex_card = models.CharField(max_length=30)
user = models.ForeignKey(User, related_name='with_draw')
def __str__(self):
return self.yandex_card
class Meta:
verbose_name = 'Заявка на вывод средств'
verbose_name_plural = 'Заявки на вывод средств'
ordering = ('-created',)

@ -0,0 +1,20 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.mail import send_mail, EmailMultiAlternatives
from django.template.loader import get_template, render_to_string
from .models import WithDraw
@receiver(post_save, sender=WithDraw)
def send_for_accountant(sender, instance, created, **kwargs):
if created:
ctx_dict = {
'username': instance.user.username,
}
subject, from_email, to = 'Заявка на распечатку', 'mukhtar@mukhtar', 'muhtarzubanchi05@gmail.com'
text_content = render_to_string('send_for_accountant.txt', ctx_dict)
html_content = get_template('send_for_accountant.html').render(ctx_dict)
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.send()

@ -0,0 +1,126 @@
{% extends 'partials/base.html' %}
{% load staticfiles %}
{% 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="col-lg-12">
<div class="scoreButtons disTab">
<div class="triangle1"></div>
<p>{{ user_score_balance }} <i class="fa fa-rub"></i></p>
{% if user_score.is_customer %}
<div class="col-lg-6">
<a href="javascript:void(0)" class="linkS linkS1">пополнить</a>
</div>
{% endif %}
<div class="col-lg-6">
<a href="javascript:void(0)" data-toggle="modal" data-target="#withdraw-money"
class="linkS linkS2">вывести средства</a>
</div>
<div id="withdraw-money" class="modal fade" role="dialog">
<div class="modal-dialog" role="document" style="width:900px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×
</button>
<h4 class="modal-title">Вывод денег</h4>
</div>
<form id="withdraw-form" action="{% url 'wallets:withdraw-create' %}" method="POST">{% csrf_token %}
<div class="modal-body">
<div style="height: 150px;">
<div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Кол-во денег</p>
<input type="text" name="{{ form.sum.html_name }}">
</div>
<div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Номер Яндекс кошелька</p>
<input type="text" name="{{ form.yandex_card.html_name }}">
<input type="hidden" name="{{ form.user.html_name }}" value="{{ user_score.pk }}">
</div>
</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>
<table>
<tr>
<th>Дата</th>
<th>Описание</th>
<th>Поступление/Списание</th>
<th>Баланс</th>
</tr>
{% for history in user_score.invoice_history.all %}
<tr>
<td>{{ history.created }}</td>
<td>
{{ history.comment }}
</td>
<td>
{{ history.sum }}
<i class="fa fa-rub"></i>
</td>
<td>
{{ history.balance }}
<i class="fa fa-rub"></i>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% include 'partials/footer.html' %}
</div>
</div>
{% endblock %}
{% block js_block %}
<script type="text/javascript">
$(function () {
$('#withdraw-form').on('submit', function (e) {
e.preventDefault();
var dataSerializer = $(this).serialize()
$.ajax({
url: '/wallets/withdraw/create/',
method: 'POST',
data: dataSerializer,
dataType: 'json',
success: function (data) {
console.log(data);
if (data.status == 'ok') {
location.reload();
}
},
error: function (jqXHR, exception) {
console.log(jqXHR);
console.log(exception);
console.log(jqXHR.statusCode);
}
})
});
});
</script>
{% endblock %}

@ -0,0 +1 @@
Заявка на вывод средств от {{ username }}!

@ -0,0 +1,2 @@
Заявка на распечатку от {{ username }}!

@ -0,0 +1,10 @@
from django.conf import urls
from .views import ScoreDetailView, WithDrawCreate
app_name = 'wallets'
urlpatterns = [
urls.url(r'^score/(?P<pk>\d+)/$', ScoreDetailView.as_view(), name='score-detail'),
urls.url(r'^withdraw/create/$', WithDrawCreate.as_view(), name='withdraw-create'),
]

@ -1,3 +1,69 @@
from django.shortcuts import render from django.http import JsonResponse
from django.contrib import messages
from django.db.models import Sum
from django.views.generic import DetailView, CreateView
from users.models import User
from users.mixins import CheckForUserMixin
from .models import InvoiceHistory, WithDraw
from .forms import WithDrawForm
# Create your views here.
class ScoreDetailView(CheckForUserMixin, DetailView):
model = User
template_name = 'score-detail.html'
context_object_name = 'user_score'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_score_balance = InvoiceHistory.objects.filter(user=self.get_object()).aggregate(Sum('sum'))
context['user_score_balance'] = user_score_balance['sum__sum'] or 0
context['form'] = WithDrawForm
return context
class AjaxableResponseMixin(object):
def form_invalid(self, form):
response = super().form_invalid(form)
if self.request.is_ajax():
return JsonResponse(form.errors, status=400)
else:
return response
def form_valid(self, form):
# import code; code.interact(local=dict(globals(), **locals()))
response = super(AjaxableResponseMixin, self).form_valid(form)
if self.request.is_ajax():
messages.info(self.request, 'Ваша заявка на вывод средств принята!')
data = {
'pk': self.object.pk,
'status': 'ok',
}
return JsonResponse(data)
else:
return response
# class WithDrawCreate(AjaxableResponseMixin, CreateView):
# model = WithDraw
# form_class = WithDrawForm
# success_url = '/'
class WithDrawCreate(CreateView):
model = WithDraw
form_class = WithDrawForm
def form_valid(self, form):
if self.request.is_ajax():
self.object = form.save()
messages.info(self.request, 'Ваша заявка на вывод средств принята!')
data = {
'pk': self.object.pk,
'status': 'ok',
}
return JsonResponse(data)
return super().form_valid(form)
def form_invalid(self, form):
if self.request.is_ajax():
return JsonResponse(form.errors, status=400)
return super().form_invalid(form)

@ -4,6 +4,16 @@ from common.models import Location
from .models import WorkSell 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 WorkSellForm(forms.ModelForm):
class Meta: class Meta:

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

@ -65,8 +65,8 @@
<div class="arroww next3"></div> <div class="arroww next3"></div>
<div class="swiper-container gallery-top"> <div class="swiper-container gallery-top">
<div class="swiper-wrapper"> <div class="swiper-wrapper">
шь
<div class="swiper-slide" style="background-image:url('{% static object.img.url %}')"></div> <div class="swiper-slide" style="background-image:url('{% static object.get_cover.url %}')"></div>
{% for photo in object.photos.all %} {% for photo in object.photos.all %}
<div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div> <div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div>
{% endfor %} {% endfor %}
@ -74,7 +74,7 @@
</div> </div>
<div class="swiper-container gallery-thumbs"> <div class="swiper-container gallery-thumbs">
<div class="swiper-wrapper"> <div class="swiper-wrapper">
<div class="swiper-slide is-selected" style="background-image:url('{% static object.img.url %}')"></div> <div class="swiper-slide is-selected" style="background-image:url('{% static object.get_cover.url %}')"></div>
{% for photo in object.photos.all %} {% for photo in object.photos.all %}
<div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div> <div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div>
{% endfor %} {% endfor %}

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

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

@ -1,13 +1,20 @@
import json 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.core.urlresolvers import reverse
from django.http import JsonResponse, HttpResponse 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 UpdateView, DeleteView, TemplateView
from projects.models import BuildingClassfication, ConstructionType from projects.models import BuildingClassfication, ConstructionType
from .models import WorkSell, Picture from .models import WorkSell, Picture, WorkSellPhoto
from .forms import WorkSellForm from .forms import WorkSellForm, ContractorWorkSellTrashForm
from .serialize import serialize from .serialize import serialize
from .response import JSONResponse, response_mimetype from .response import JSONResponse, response_mimetype
@ -37,7 +44,7 @@ class WorkSellsView(ListView):
model = WorkSell model = WorkSell
template_name = 'worksells_list.html' template_name = 'worksells_list.html'
# paginate_by = 20 # paginate_by = 20
paginate_by = 1 paginate_by = 18
def get_form_kwargs(self, **kwargs): def get_form_kwargs(self, **kwargs):
kwargs = super().get_form_kwargs kwargs = super().get_form_kwargs
@ -72,6 +79,15 @@ def work_sell_create(request):
if form.is_valid(): if form.is_valid():
instance = form.save(commit=False) instance = form.save(commit=False)
instance.save() 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'} data = {'status': 'ok'}
else: else:
data = {'status': 'no', 'form_errors': form.errors} data = {'status': 'no', 'form_errors': form.errors}
@ -101,13 +117,27 @@ class WorkSellDeleteView(DeleteView):
return reverse('work_sell:list') 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): class UploadView(View):
template_name = 'upload.html' template_name = 'upload.html'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
return render(request,self.template_name) return render(request, self.template_name)
class JSONResponseMixin(object): class JSONResponseMixin(object):
@ -125,5 +155,3 @@ class JSONResponseMixin(object):
class JSONView(JSONResponseMixin, TemplateView): class JSONView(JSONResponseMixin, TemplateView):
def render_to_response(self, context, **response_kwargs): def render_to_response(self, context, **response_kwargs):
return self.render_to_json_response(context, **response_kwargs) return self.render_to_json_response(context, **response_kwargs)

Loading…
Cancel
Save