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. 57
      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. 57
      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. 465
      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. 8
      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'^test/$', TemplateView.as_view(template_name='test.html'), name='test'),
url(r'^projects/', include('projects.urls')),
url(r'^wallets/', include('wallets.urls')),
url(r'^chat/', include('chat.urls')),
url(r'^specializations/', include('specializations.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
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archilance.settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archilance.settings.prod")
application = get_wsgi_application()

File diff suppressed because it is too large Load Diff

@ -237,6 +237,69 @@
var socket = new SocketHandler();
var form = document.getElementById('message_form');
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(){
$(".user-block").first().trigger('click');
}, 10);
@ -245,10 +308,10 @@
$(".order-block").first().trigger('click');
}, 100);
$("#order-stages").on('click', "#addStagesForm", function(){
$("#order-stages").on('click', "#addStagesForm", function(e){
e.preventDefault();
$(".new-stages-form").each(function(i,v){
console.log($(this).serialize());
alert($(this).serialize());
$.ajax({
url: '/api/stages/',
@ -260,6 +323,7 @@
dataType: 'json',
success: function (json) {
console.log(json);
},
error: function(e){
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(){
var countStage = parseInt($(this).val());
var updateFormStages = $(".update-stages-form");
alert(updateFormStages.length);
alert(typeof updateFormStages.length);
var limitCount = countStage + 1;
for (var i = 2; i < limitCount; i++) {
var stageCopy = $("#stage1").clone().attr("id", "stage" + i).addClass("stages_form");
@ -321,65 +412,67 @@
}
});
$.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" id="stage-form-'+ v.pos +'">' +
'<label for="">Название</label><input class="form-control" type="text" value="'+ v.name +'" />' +
'<label for="">Цена</label><input class="form-control" type="text" value="'+ v.cost +'" />' +
'<input class="form-control" type="hidden" value="'+ v.order +'" />' +
'<label for="">Срок</label><input class="form-control" type="text" value="'+ v.term +'" />' +
'<label for="">Результат</label><input class="form-control" type="text" 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="javascript:void()" id="addStagesForm">отправить на согласование</a> </div>';
}
htmlInbox = htmlInboxStage + htmlInbox;
$("#order-stages").html(htmlInbox);
}
});
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="hidden" 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" id="stage-form-'+ v.pos +'">' +#}
{# '<label for="">Название</label><input class="form-control" type="text" value="'+ v.name +'" />' +#}
{# '<label for="">Цена</label><input class="form-control" type="text" value="'+ v.cost +'" />' +#}
{# '<input class="form-control" type="hidden" value="'+ v.order +'" />' +#}
{# '<label for="">Срок</label><input class="form-control" type="text" value="'+ v.term +'" />' +#}
{# '<label for="">Результат</label><input class="form-control" type="text" 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="javascript:void()" data-order-id="'+ orderId +'" id="addStagesForm">отправить на согласование</a> </div>';#}
{# }#}
{# 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 url = 'ws://127.0.0.1:8888/chat/' + userId + '/';
var sock = new WebSocket(url);

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

@ -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,12 +47,14 @@ 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')
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'
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):
time_notification = models.IntegerField(default=180)
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_time_remove = models.IntegerField(default=14)
recalculation_spec_time = models.TimeField()
recalculation_rating_time = models.TimeField()
def __str__(self):
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
text_content = render_to_string('document_email.txt', 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')
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,7 +1,8 @@
{% extends 'partials/base.html' %}
{% load humanize %}
{% load thumbnail %}
{% load specializtions_tags %}
{% block content %}
{% include 'partials/header.html' %}
@ -314,8 +315,7 @@
{# {% elif request.user.is_contractor and not request.user.contractor_answers.exists %}#}
{% if request.user.is_contractor and not request.user.contractor_answers.exists %}
<form action="{% url 'projects:detail' pk=project.pk %}" method="POST" enctype="multipart/form-data" novalidate>
@ -418,11 +418,7 @@
{% elif request.user.is_customer %}
<div class="exBigBlock disTab">
<div class="col-lg-12">
<p class="titleEx">Исполнители</p>
@ -452,62 +448,48 @@
<p>Новые исполнители</p>
</div>
{% for answer_p in project.answers.all %}
<div class="candidateBlock disTab">
<div class="candidate">
<div class="col-lg-4">
<a href="#" class="aLinkExe">
<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>
</a>
<p class="nameExecutor">
<a href="#">Иванов Петр Иванович [ivanov_petr]</a>
<a href="#">{{ answer_p.author.get_full_name }} [{{ answer_p.author.username }}]</a>
</p>
<p class="navv2">На сайте 8 лет и 3 месяца</p>
<div class="statusUser">Свободен</div>
</div>
<div class="col-lg-3 retts">
<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>
{% ratings_widget answer_p.author.pk 'restList2' %}
{% if answer_p.author.cro %}
<div class="sroUser sroExecutor">
<div class="iconSRO"></div>
<p>Есть допуск СРО</p>
</div>
{% endif %}
</div>
<div class="col-lg-2 listCens">
<p>Цена:
<span> 35 000</span>
<span> {{ answer_p.budget }}</span>
<i class="fa fa-rub"></i>
</p>
<p>
Срок: <span>3 недели</span>
Срок: <span>{{ answer_p.term }} of {{ answer_p.term_type }}</span>
</p>
<p>Опубликован: 22.04.2016</p>
<p>Опубликован: {{ answer_p.created | date:"M d, Y" }}</p>
</div>
<div class="col-lg-3 retts">
<a href="javascript:void(0)" class="candLink candLink1">
Кандидат
</a>
<a href="javascript:void(0)" class="candLink candLink2">
<a href="{% url 'chat:chat-user' %}" class="candLink candLink2">
предложить проект
</a>
<a href="javascript:void(0)" class="candLink candLink3">
@ -548,7 +530,7 @@
<div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1">
<p class="nameComm">
Иванов Петр Иванович
Иванов Петр Иванович
</p>
<span class="dateComm44">
13.01.2016 / 21:05
@ -568,7 +550,7 @@
<div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1">
<p class="nameComm nameCommAct">
Иванов Петр Иванович
Иванов Петр Иванович
</p>
<span class="dateComm44">
13.01.2016 / 21:05
@ -584,6 +566,7 @@
</div>
</div>
</div>
{% endfor %}
{% 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,
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,
)
@ -176,7 +177,7 @@ class ProjectFilterView(BaseMixin, View):
'<pre>{realty_form}</pre>'
).format(realty_form=pformat(realty_form.errors)))
# import code; code.interact(local=dict(globals(), **locals()))
paginator = Paginator(projects.all(), settings.PAGE_SIZE)
page = request.GET.get('page')
@ -355,6 +356,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
@ -485,4 +501,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()))

@ -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 specializations.models import Specialization
class HistoryRating(models.Model):
user = models.ForeignKey(User, 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)
def __str__(self):
return self.rating
return '{0}'.format(self.rating)
class Meta:
verbose_name = 'История рейтинга'
@ -25,12 +26,10 @@ class SpecializationRating(models.Model):
position = models.PositiveIntegerField(default=0)
def __str__(self):
return self.position
return '{0}'.format(self.pk)
class Meta:
verbose_name = 'Рейтинг специализаций'
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
natsort
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,
}

@ -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">
@ -91,33 +100,21 @@
</a>
</li>
<li class="icon_mm3">
<a href="#">
Сообщения
<span></span>
</a>
<a href="#">Сообщения<span></span></a>
</li>
<li class="icon_mm4">
<a href="#">
Счет
<span></span>
</a>
<a href="{% url 'wallets:score-detail' pk=request.user.pk %}">Счет<span></span></a>
</li>
<li class="icon_mm5">
<a href="#">
Настройки
<span></span>
</a>
<a href="#">Настройки<span></span></a>
</li>
<li class="icon_mm6">
<a href="#">
FAQ
<span></span>
</a>
<a href="#">FAQ<span></span></a>
</li>
</ul>
</div>
</div>
{% if request.user.is_contractor %}
<div class="rating">
<div class="ratingInset"></div>

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

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

@ -12,3 +12,9 @@ class CheckForUserMixin(object):
else:
return HttpResponseForbidden('403 Forbidden')
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)
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_team_widget contractor.team.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 %}
@ -28,20 +27,8 @@
</a>
<span></span>
</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 %}
{% 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)">
@ -49,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>
@ -159,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>
@ -200,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>
@ -219,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>

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

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

@ -226,13 +226,13 @@ class ContractorFilterView(BaseMixin, View):
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:
teams = teams.filter(
(
Q(users__contractor_specializations__lft__gte=specialization.lft)
& Q(users__contractor_specializations__rght__lte=specialization.rght)
Q(contractors__contractor_specializations__lft__gte=specialization.lft)
& Q(contractors__contractor_specializations__rght__lte=specialization.rght)
) | (
Q(owner__contractor_specializations__lft__gte=specialization.lft)
& Q(owner__contractor_specializations__rght__lte=specialization.rght)
@ -242,8 +242,8 @@ class ContractorFilterView(BaseMixin, View):
if location:
teams = teams.filter(
(
Q(users__location__lft__gte=location.lft)
& Q(users__location__rght__lte=location.rght)
Q(contractors__location__lft__gte=location.lft)
& Q(contractors__location__rght__lte=location.rght)
) | (
Q(owner__location__lft__gte=location.lft)
& Q(owner__location__rght__lte=location.rght)
@ -252,19 +252,19 @@ class ContractorFilterView(BaseMixin, View):
if work_type:
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),
)
if build_classif:
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),
)
if constr_type:
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),
)
@ -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'

@ -1,5 +1,15 @@
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.models import Sum
from django.utils import timezone
from users.models import User
@ -14,13 +15,36 @@ class InvoiceHistory(models.Model):
comment = models.TextField(blank=True)
created = models.DateTimeField(default=timezone.now)
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')
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:
verbose_name = 'Счет(История)'
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
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 = 'Готовая работа'

@ -65,8 +65,8 @@
<div class="arroww next3"></div>
<div class="swiper-container gallery-top">
<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 %}
<div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div>
{% endfor %}
@ -74,7 +74,7 @@
</div>
<div class="swiper-container gallery-thumbs">
<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 %}
<div class="swiper-slide" style="background-image:url('{% static photo.img.url %}')"></div>
{% endfor %}

@ -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