#ARC-18 Add button cancel stages for contractors

remotes/origin/PR-39
Mukhtar 10 years ago
parent a636f4675e
commit 4c2de83645
  1. 4
      api/views.py
  2. 16
      archilance/settings/base.py
  3. 27
      assets/js/chat.js
  4. 2
      chat/admin.py
  5. 29
      chat/filters.py
  6. 2
      chat/serializers.py
  7. 176
      chat/templates/chat_contractor.html
  8. 69
      chat/templates/chat_customer.html
  9. 6
      chat/views.py
  10. 8
      projects/models.py
  11. 13
      projects/serializers.py
  12. 16
      projects/templates/project_detail.html
  13. 2
      templates/partials/base.html
  14. 6
      templates/registration/registration_form.html

@ -30,7 +30,7 @@ from common.filters import LocationFilterSet
from chat.models import Message, Notes, Documents from chat.models import Message, Notes, Documents
from chat.serializers import MessageSerializer, NoteSerializer, DocumentsSerializer from chat.serializers import MessageSerializer, NoteSerializer, DocumentsSerializer
from chat.filters import MessageFilterSet, NoteFilterSet, DocumentsFilterSet from chat.filters import MessageFilterSet, NoteFilterSet, DocumentFilterSet
from reviews.models import Review from reviews.models import Review
from reviews.serializers import ReviewSerializer from reviews.serializers import ReviewSerializer
@ -72,7 +72,7 @@ class ReviewViewSet(ModelViewSet):
class DocumentViewSet(ModelViewSet): class DocumentViewSet(ModelViewSet):
queryset = Documents.objects.all() queryset = Documents.objects.all()
serializer_class = DocumentsSerializer serializer_class = DocumentsSerializer
# filter_class = DocumentsFilterSet filter_class = DocumentFilterSet
permission_classes = (permissions.IsAuthenticatedOrReadOnly,) permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self): def get_queryset(self):

@ -166,6 +166,7 @@ AUTHENTICATION_BACKENDS = (
'social.backends.twitter.TwitterOAuth', 'social.backends.twitter.TwitterOAuth',
'social.backends.vk.VKOAuth2', 'social.backends.vk.VKOAuth2',
'social.backends.odnoklassniki.OdnoklassnikiOAuth2', 'social.backends.odnoklassniki.OdnoklassnikiOAuth2',
'social.backends.mailru.MailruOAuth2',
# 'django.contrib.auth.backends.ModelBackend', # 'django.contrib.auth.backends.ModelBackend',
'users.backend.EmailOrUsernameModelBackend', 'users.backend.EmailOrUsernameModelBackend',
) )
@ -185,8 +186,9 @@ SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_KEY = '1247035904'
SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_SECRET = '9AD83DB399405EEFAE7641BD' SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_SECRET = '9AD83DB399405EEFAE7641BD'
SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_PUBLIC_NAME = 'CBADEFFLEBABABABA' SOCIAL_AUTH_ODNOKLASSNIKI_OAUTH2_PUBLIC_NAME = 'CBADEFFLEBABABABA'
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '499898042244-bt7v18v4f46k8qg98n1ne8u2hjtmj0cn.apps.googleusercontent.com' SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '54397003678-ejfrg1la2vh2jdjq7fb1upc916kd6djo.apps.googleusercontent.com'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 's69NCyhSlwY0OuGGT8_dFI7E' SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'UOLE-UM9bo2UL7i3TXy_WPa5'
# SOCIAL_AUTH_TWITTER_KEY = 'YAe05K4IYYxHhA6J1mTOdDBjq' # SOCIAL_AUTH_TWITTER_KEY = 'YAe05K4IYYxHhA6J1mTOdDBjq'
# SOCIAL_AUTH_TWITTER_SECRET = 'iRuYqRRaoGkCD4ip74NICb8FeZMxvM6MZ8HLMbm1jX99o7pcaL' # SOCIAL_AUTH_TWITTER_SECRET = 'iRuYqRRaoGkCD4ip74NICb8FeZMxvM6MZ8HLMbm1jX99o7pcaL'
@ -197,6 +199,10 @@ SOCIAL_AUTH_TWITTER_SECRET = 'WhXRHP6BzNwFS8x94pcaCBwxCSMkAEVm3Rg82XhzUaIqsf2Ur0
SOCIAL_AUTH_VK_OAUTH2_KEY = '5542865' SOCIAL_AUTH_VK_OAUTH2_KEY = '5542865'
SOCIAL_AUTH_VK_OAUTH2_SECRET = 'BsOSDhmyNiDte7cMJlVq' SOCIAL_AUTH_VK_OAUTH2_SECRET = 'BsOSDhmyNiDte7cMJlVq'
SOCIAL_AUTH_MAILRU_OAUTH2_KEY = 'f7bad5797a375a5eeba6217d64de71f4'
SOCIAL_AUTH_MAILRU_OAUTH2_SECRET = '480fd6d67e9e8625fbc6b6b9a8ec71f0'
SOCIAL_AUTH_VK_OAUTH2_SCOPE = [ SOCIAL_AUTH_VK_OAUTH2_SCOPE = [
'notify', 'notify',
'friends', 'friends',
@ -204,9 +210,9 @@ SOCIAL_AUTH_VK_OAUTH2_SCOPE = [
] ]
# SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/' SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/'
# SOCIAL_AUTH_NEW_USER_REDIRECT_URL = 'http://proekton.com/' SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/'
# SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = 'http://proekton.com/' SOCIAL_AUTH_NEW_ASSOCIATION_REDIRECT_URL = '/'
SOCIAL_AUTH_PIPELINE = ( SOCIAL_AUTH_PIPELINE = (
'social.pipeline.social_auth.social_details', 'social.pipeline.social_auth.social_details',

@ -1,6 +1,6 @@
var SocketHandler = function () { var SocketHandler = function () {
domain = domain.replace(':' + port, ''); domain = domain.replace(':' + port, '');
var url = 'ws://' + domain + ':8888/chat/' + userId + '/'; var url = 'ws://' + domain + '/chat/' + userId + '/';
var sock = new WebSocket(url); var sock = new WebSocket(url);
var intervalId; var intervalId;
sock.onopen = function () { sock.onopen = function () {
@ -192,6 +192,29 @@ $(function () {
}); });
//Удаление документа
$('.tab-content').on('click','.remove-document', function(e){
e.preventDefault();
var dataId = $(this).attr('data-id');
var _this = $(this);
$.ajax({
url: '/api/documents/' + dataId +'/',
type: 'DELETE',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
dataType: 'json',
success: function(json){
_this.parent().remove();
console.log(json);
},
error: function (e, jqxhr) {
console.log(jqxhr);
}
});
});
// Вытащить сообщения для конактов // Вытащить сообщения для конактов
$('.user-block').on('click', function () { $('.user-block').on('click', function () {
@ -228,7 +251,7 @@ $(function () {
console.log(json); console.log(json);
$.each(json.results, function (i, v) { $.each(json.results, function (i, v) {
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="'+ v.file_url +'">' + v.file + '</a><div style="right:-10px;"></divsty></li>'; docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="'+ v.file_url +'">' + v.file + '</a><div class="remove-document" data-id="'+ v.id+'" style="right:-10px;"></div></li>';
}); });
}, },
error: function (e) { error: function (e) {

@ -3,7 +3,7 @@ from .models import Message, Notes, Documents
class MessageAdmin(admin.ModelAdmin): class MessageAdmin(admin.ModelAdmin):
list_display = ('text', 'sender', 'recipent',) list_display = ('text', 'sender', 'recipent', 'is_new',)
class NotesAdmin(admin.ModelAdmin): class NotesAdmin(admin.ModelAdmin):

@ -2,16 +2,16 @@ from rest_framework_filters import FilterSet, RelatedFilter, AllLookupsFilter
from .models import Message, Notes, Documents from .models import Message, Notes, Documents
#
class DocumentsFilterSet(FilterSet): # class DocumentsFilterSet(FilterSet):
file = AllLookupsFilter() # file = AllLookupsFilter()
sender = RelatedFilter('users.filters.UserFilterSet') # # sender = RelatedFilter('users.filters.UserFilterSet')
recipent = RelatedFilter('users.filters.UserFilterSet') # # recipent = RelatedFilter('users.filters.UserFilterSet')
# order = AllLookupsFilter() # # order = RelatedFilter('projects.filters.OrderFilterSet')
# team = AllLookupsFilter() # # order = AllLookupsFilter()
#
class Meta: # class Meta:
model = Documents # model = Documents
class MessageFilterSet(FilterSet): class MessageFilterSet(FilterSet):
@ -26,6 +26,15 @@ class MessageFilterSet(FilterSet):
model = Message model = Message
class DocumentFilterSet(FilterSet):
id = AllLookupsFilter()
# order = RelatedFilter('projects.filters.OrderFilterSet')
class Meta:
model = Documents
class NoteFilterSet(FilterSet): class NoteFilterSet(FilterSet):
text = AllLookupsFilter() text = AllLookupsFilter()
created = AllLookupsFilter() created = AllLookupsFilter()

@ -36,7 +36,6 @@ class DocumentsSerializer(ModelSerializer):
return obj.file.url return obj.file.url
class MessageSerializer(ModelSerializer): class MessageSerializer(ModelSerializer):
sender = UserSerializer() sender = UserSerializer()
recipent = UserSerializer() recipent = UserSerializer()
@ -79,4 +78,3 @@ class NoteSerializer(ModelSerializer):
'sender', 'sender',
'recipent', 'recipent',
) )

@ -23,11 +23,11 @@
<a href="#tab2" data-toggle="tab">Заказчики</a> <a href="#tab2" data-toggle="tab">Заказчики</a>
</li> </li>
{% if team_orders %}
<li role="presentation"> <li role="presentation">
<a href="#tab3" data-toggle="tab">Исполнители</a> <a href="#tab3" data-toggle="tab">Исполнители</a>
</li> </li>
{% endif %}
</ul> </ul>
</div> </div>
</div> </div>
@ -142,9 +142,9 @@
<div class="col-lg-6 commChat"> <div class="col-lg-6 commChat">
<div id="message-chat-order-space"></div> <div id="message-chat-order-space"></div>
<form id="chat-order-add"> <form id="chat-order-add">
<input type="text" id="orderId" name="orderId"> <input type="hidden" id="orderId" name="orderId">
<input type="text" id="senderId" name="senderId" value="{{ request.user.pk }}"> <input type="hidden" id="senderId" name="senderId" value="{{ request.user.pk }}">
<input type="text" id="recipentId" name="recipentId" value=""> <input type="hidden" id="recipentId" name="recipentId" value="">
<textarea id="chat" class="box-sizing"></textarea> <textarea id="chat" class="box-sizing"></textarea>
<p class="errorEmptyMessage" style="color: red;display:none;">Пустое сообщение нельзя отправить</p> <p class="errorEmptyMessage" style="color: red;display:none;">Пустое сообщение нельзя отправить</p>
<div class="bunChat"> <div class="bunChat">
@ -204,6 +204,15 @@
<!-- Arbitration add --> <!-- Arbitration add -->
{% include 'arbitration_modal.html' %} {% include 'arbitration_modal.html' %}
<!-- --> <!-- -->
<div class="col-lg-12 documentsChat">
<p>Входящие документы</p>
<ul id="documentOrderSpace"></ul>
{# <a href="javascript:void(0)">#}
{# Распечатать с помощью ресурса#}
{# </a>#}
</div>
<div class="textAreaBlock2 box-sizing disTab"> <div class="textAreaBlock2 box-sizing disTab">
<ul class="notes-block"> <ul class="notes-block">
</ul> </ul>
@ -220,7 +229,7 @@
</div> </div>
<!-- End block Tab2--> <!-- End block Tab2-->
{% if team_orders %}
<!-- Tab3 groups block --> <!-- Tab3 groups block -->
<div class="chatBlock disTab tab-pane fade" id="tab3"> <div class="chatBlock disTab tab-pane fade" id="tab3">
<div class="col-lg-3 wrMessages"> <div class="col-lg-3 wrMessages">
@ -262,13 +271,47 @@
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
{% for yteam in your_teams %}
<div class="team-block orderBlock box-sizing" data-id="{{ yteam.pk }}">
<span class="dimovChat"></span>
<p class="titleOB">
{{ yteam }}
</p>
<div class="hideOBB disTab">
<p class="pOB">
<span>Владелец группы:</span> {{ yteam.owner }}
</p>
<ul class="listChat1">
{% for tuser in yteam.contractors.all %}
<li>{{ tuser }}</li>
{% endfor %}
</ul>
<p class="pOB">
<span>Чаты:</span>
{% if request.user.pk != torder.team.owner.pk %}
<span class="team-chat-user"
data-id="{{ torder.team.owner.pk}}">{{ torder.team.owner.username }},</span>
{% endif %}
{% for tuser in yteam.contractors.all %}
{% if request.user.pk != tuser.pk %}
<span class="team-chat-user"
data-id="{{ tuser.pk }}">{{ tuser.username }},</span>
{% endif %}
{% endfor %}
</p>
</div>
</div>
{% endfor %}
</div> </div>
</div> </div>
<div class="col-lg-6 commChat"> <div class="col-lg-6 commChat">
<div id="message-chat-team-space"></div> <div id="message-chat-team-space"></div>
<form id="team-chat-form"> <form id="team-chat-form">
<input type="hidden" name="sender" id="senderTeamId" value="{{ request.user.pk }}"/> <input type="hidden" name="sender" id="senderTeamId" value="{{ request.user.pk }}"/>
<input type="hidden" name="recipent" id="recipenTeamtId" value=""/> <input type="hidden" name="recipent" id="recipentTeamId" value=""/>
<input type="hidden" name="order" id="orderTeamId"> <input type="hidden" name="order" id="orderTeamId">
<input type="hidden" name="team" id="teamId" value=""/> <input type="hidden" name="team" id="teamId" value=""/>
<input type="hidden" name="document-send" id="documentSendIds"/> <input type="hidden" name="document-send" id="documentSendIds"/>
@ -292,7 +335,7 @@
</div> </div>
</div> </div>
<!-- End block Tab3--> <!-- End block Tab3-->
{% endif %}
<!-- order-info --> <!-- order-info -->
{% include 'order_info.html' %} {% include 'order_info.html' %}
@ -322,15 +365,20 @@
}, 1000); }, 1000);
var url = '/chat/create/'; var url = '/chat/create/';
$("#upload-document-team").bind('fileuploadsubmit', function (e, data) {
data.formData = {
sender: $("#team-chat-form #senderTeamId").val(),
recipent: $("#team-chat-form #recipentTeamId").val(),
order: $("#team-chat-form #orderTeamId").val(),
team: $("#team-chat-form #teamId").val(),
}
console.log(data.formData);
});
//Загрузка документов //Загрузка документов
$('#upload-document-team').fileupload({ $('#upload-document-team').fileupload({
url: url, url: url,
formData: {
sender: $("#team-chat-form #senderId").val(),
recipent: $("#team-chat-form #recipentId").val(),
team: $("#team-chat-form #teamId").val(),
order: $("#team-chat-form #orderId").val(),
},
crossDomain: false, crossDomain: false,
beforeSend: function (xhr, settings) { beforeSend: function (xhr, settings) {
$('#progress .progress-bar').css( $('#progress .progress-bar').css(
@ -402,10 +450,48 @@
}); });
// Согласование этапов
$("#order-stages").on('click', "#cancel-stages", function (e) {
e.preventDefault();
$(".stage-block-approve").each(function () {
var stageId = $(this).attr('data-id');
$.ajax({
url: '/api/stages/' + stageId + '/',
type: 'PATCH',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
data: "status=cancel_approve",
dataType: 'json',
success: function (json) {
console.log(json);
},
error: function (e) {
console.log('error');
console.log(e);
}
});
});
var orderId = $(this).attr('data-order-id');
socket.send_stages_approve({
"format_type": "approve_stages",
"data": {
"sender_id": $(this).attr('data-sender-id'),
"recipent_id": $(this).attr('data-recipent-id'),
"order_id": orderId,
"msg": "Исполнитель отказался от текущих этапов " + orderId,
}
});
});
$(".team-chat-user").on('click', function (e) { $(".team-chat-user").on('click', function (e) {
e.stopPropagation(); e.stopPropagation();
var recipentId = $(this).attr('data-id'); var recipentId = $(this).attr('data-id');
$("#team-chat-form #recipentId").val(recipentId); $("#team-chat-form #recipentTeamId").val(recipentId);
}); });
$(".team-order-block").on('click', function () { $(".team-order-block").on('click', function () {
@ -418,7 +504,7 @@
var teamId = $(this).attr('data-team-id'); var teamId = $(this).attr('data-team-id');
var orderId = $(this).attr('data-order-id'); var orderId = $(this).attr('data-order-id');
$("#team-chat-form #teamId").val(teamId); $("#team-chat-form #teamId").val(teamId);
$("#team-chat-form #orderId").val(orderId); $("#team-chat-form #orderTeamId").val(orderId);
var inbox = document.getElementById('message-chat-team-space'); var inbox = document.getElementById('message-chat-team-space');
inbox.innerHTML = ''; inbox.innerHTML = '';
@ -464,6 +550,7 @@
$("#targetCustomerId").val(recipentId); $("#targetCustomerId").val(recipentId);
$("#add-form-order-note #recipentNote").val(recipentId); $("#add-form-order-note #recipentNote").val(recipentId);
var docList = document.getElementById('documentOrderSpace');
var inbox = document.getElementById('message-chat-order-space'); var inbox = document.getElementById('message-chat-order-space');
inbox.innerHTML = ''; inbox.innerHTML = '';
@ -487,6 +574,24 @@
} }
}); });
$.ajax({
url:'/api/documents',
type: 'GET',
data:{
csrfmiddlewaretoken: csrftoken,
'order': orderId
},
dataType: 'json',
success: function (json){
$.each(json.results, function (i, v) {
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="'+ v.file_url +'">'+ v.file+'</a><div class="remove-document" data-id="'+ v.id+'" style="right:-10px;"></div></li>';
});
},
error: function(e){
console.log(e);
}
});
$.ajax({ $.ajax({
url: '/api/note/', url: '/api/note/',
type: 'GET', type: 'GET',
@ -508,7 +613,6 @@
type: 'GET', type: 'GET',
data:{csrfmiddlewaretoken: csrftoken}, data:{csrfmiddlewaretoken: csrftoken},
dataType: 'json', dataType: 'json',
}).then(function(data){ }).then(function(data){
var htmlInbox = ""; var htmlInbox = "";
var stagesReservedHtml = ""; var stagesReservedHtml = "";
@ -522,7 +626,7 @@
if (v.status == "completed"){ if (v.status == "completed"){
stagesCompleted.push(v); stagesCompleted.push(v);
} }
if(v.status == "not_agreed"){ if(v.status == "not_agreed" || v.status == "send_approve"){
statusNotAgreed = true; statusNotAgreed = true;
} }
if(!data.secure){ if(!data.secure){
@ -544,6 +648,23 @@
} }
var statusName = ''; var statusName = '';
switch(v.status){
case 'not_agreed':
statusName = 'Не согласован';
break;
case 'send_approve':
statusName = 'На согласовании';
break;
case 'cancel_approve':
statusName = 'Исполнитель отказался';
break;
case 'in_process':
statusName = 'В процессе';
break;
case 'completed':
statusName = 'Завершен';
break;
}
if (v.status == 'completed'){ if (v.status == 'completed'){
statusName = 'Завершен'; statusName = 'Завершен';
} }
@ -557,7 +678,10 @@
if (statusNotAgreed) { if (statusNotAgreed) {
htmlInbox += '<div class="textAreaBlock2 FFD box-sizing disTab">' + htmlInbox += '<div class="textAreaBlock2 FFD box-sizing disTab">' +
'<a id="approve-stages" data-sender-id="{{ request.user.pk }}" data-recipent-id="' + recipentId + '"' + '<a id="approve-stages" data-sender-id="{{ request.user.pk }}" data-recipent-id="' + recipentId + '"' +
' data-order-id="' + orderId + '" href="#">согласовать</a></div>'; ' data-order-id="' + orderId + '" href="#">согласовать</a>' +
'<a id="cancel-stages" data-sender-id="{{ request.user.pk }}" data-recipent-id="' + recipentId + '"' +
' data-order-id="' + orderId + '" href="#">отказаться</a>' +
'</div>';
} }
} }
@ -661,18 +785,17 @@
}); });
//Добавить сообщение для исполнителей в группе //Добавить сообщение для исполнителей в группе
$("#add-team-chat-message").on('click', function () { $("#add-team-chat-message").on('click', function (e) {
e.preventDefault();
var chatMessage = $("#team-chat-form #chatText").val(); var chatMessage = $("#team-chat-form #chatText").val();
var recipentId = $("#team-chat-form #recipentId").val(); var recipentId = $("#team-chat-form #recipentTeamId").val();
var senderId = $("#team-chat-form #senderId").val(); var senderId = $("#team-chat-form #senderTeamId").val();
var teamId = $("#team-chat-form #teamId").val(); var teamId = $("#team-chat-form #teamId").val();
var orderId = $("#team-chat-form #orderId").val(); var orderId = $("#team-chat-form #orderTeamId").val();
var documentSendIds = $("#documentSendIds").val(); var documentSendIds = $("#documentSendIds").val();
console.log(documentSendIds);
var teamDocumentIds = documentSendIds.split(';'); var teamDocumentIds = documentSendIds.split(';');
teamDocumentIds.pop(); teamDocumentIds.pop();
console.log(teamDocumentIds);
socket.add_team_message({ socket.add_team_message({
"format_type": "add_message_team", "format_type": "add_message_team",
"data": { "data": {
@ -686,6 +809,7 @@
$("#team-chat-form #chatText").val(""); $("#team-chat-form #chatText").val("");
$("#document-send").html(""); $("#document-send").html("");
$("#documentSendIds").val("");
}); });

@ -89,8 +89,10 @@
{# <a href="javascript:void(0)">#} {# <a href="javascript:void(0)">#}
{# Распечатать с помощью ресурса#} {# Распечатать с помощью ресурса#}
{# </a>#} {# </a>#}
</div> </div>
<div class="textAreaBlock2 box-sizing disTab"> <div class="textAreaBlock2 box-sizing disTab">
<p>Заметки</p>
<ul class="contractor-notes-block"> <ul class="contractor-notes-block">
</ul> </ul>
<form id="add-form-contractor-note"> <form id="add-form-contractor-note">
@ -337,6 +339,7 @@
data:{csrfmiddlewaretoken: csrftoken}, data:{csrfmiddlewaretoken: csrftoken},
dataType: 'json', dataType: 'json',
}).then(function(data){ }).then(function(data){
var isReviewLeave = data.has_user_review;
var stagesResults = data.stages; var stagesResults = data.stages;
var stageCount = stagesResults.length; var stageCount = stagesResults.length;
if (stageCount == 0) { if (stageCount == 0) {
@ -352,12 +355,13 @@
if (stageCount == 0) { if (stageCount == 0) {
htmlInboxStage += '<div class="numberStepp box-sizing" id="stage1">' + 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">' + '<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="name" type="text">' +
'<label for="">Цена</label><input class="form-control" name="cost" type="text" />' + '<label for="">Цена</label><input class="form-control" name="cost" type="text">' +
'<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '"/>' + '<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '">' +
'<label for="">Срок</label><input class="term-picker form-control datepicker" name="term" type="text" />' + '<input class="form-control" type="hidden" name="status" value="send_approve">' +
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' + '<label for="">Срок</label><input class="term-picker form-control datepicker" name="term" type="text">' +
'<input class="form-control" name="pos" value="1" type="hidden" />' + '<label for="">Результат</label><input class="form-control" name="result" type="text">' +
'<input class="form-control" name="pos" value="1" type="hidden">' +
'</form></div>'; '</form></div>';
} }
var statusNotAgreed = true; var statusNotAgreed = true;
@ -384,19 +388,20 @@
stagePaidCount +=1; stagePaidCount +=1;
} }
if (v.status == "not_agreed") { if (v.status == "not_agreed" || v.status == 'cancel_approve' || v.status == 'send_approve') {
htmlInbox += '<div class="numberStepp box-sizing">' + htmlInbox += '<div class="numberStepp box-sizing">' +
'<p>Этап</p><form class="update-stages-form" data-stage-id="' + v.id + '" id="stage-form-' + v.pos + '">' + '<p>Этап</p><form class="update-stages-form" data-stage-id="' + v.id + '" 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="name" value="' + v.name + '">' +
'<label for="">Цена</label><input class="form-control" type="text" name="cost" value="' + v.cost + '" />' + '<label for="">Цена</label><input class="form-control" type="text" name="cost" value="' + v.cost + '" >' +
'<input class="form-control orderStagesInput" type="hidden" name="order" value="' + v.order + '"/>' + '<input class="form-control orderStagesInput" type="hidden" name="order" value="' + v.order + '">' +
'<input class="form-control" type="hidden" name="status" value="send_approve">' +
'<label for="">Срок</label><input class="term-picker form-control datepicker" type="text" name="term" value="' + v.term + '" />' + '<label for="">Срок</label><input class="term-picker form-control datepicker" type="text" name="term" value="' + v.term + '" />' +
'<label for="">Результат</label><input class="form-control" type="text" name="result" value="' + v.result + '" />' + '<label for="">Результат</label><input class="form-control" type="text" name="result" value="' + v.result + '" >' +
'</form></div>'; '</form></div>';
} else { } else {
statusNotAgreed = false; statusNotAgreed = false;
htmlInboxStage = ""; htmlInboxStage = "";
var statusName = ''; var statusName = "";
if (v.status == 'completed'){ if (v.status == 'completed'){
statusName = 'Завершен'; statusName = 'Завершен';
} }
@ -464,17 +469,12 @@
$("#reserveSpace").hide(); $("#reserveSpace").hide();
} }
if((stagesCompleted.length == stagesResults.length) && (stagesCompleted.length > 0)){ if((stagesCompleted.length == stagesResults.length) && (stagesCompleted.length > 0) && (!isReviewLeave)){
$("#leaveReview").show(); $("#leaveReview").show();
console.log("Все этапы завершены");
}else { }else {
$("#leaveReview").hide(); $("#leaveReview").hide();
} }
if (data.status == 'completed'){
$("#leaveReview").hide();
}
$(".stages-paid").html(stagesReservedHtml); $(".stages-paid").html(stagesReservedHtml);
}); });
@ -593,17 +593,12 @@
} }
}); });
{# setTimeout(function () {#}
{# getStages(currentOrderId,userId,currentRecipentId,secureOrder);#}
{##}
{# }, 1000);#}
}); });
//Изменение счетчика //Изменение счетчика
$('#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 currentCountStage = $(".numberStepp").length; var currentCountStage = $("#order-stages .numberStepp").length;
if ((countStage<1) || isNaN(countStage)) { if ((countStage<1) || isNaN(countStage)) {
countStage = 1; countStage = 1;
$('#order-stages-tab #countStage').val(currentCountStage); $('#order-stages-tab #countStage').val(currentCountStage);
@ -611,23 +606,23 @@
if (countStage > currentCountStage) { if (countStage > currentCountStage) {
for (var jj = currentCountStage; jj < countStage; jj++) { for (var jj = currentCountStage; jj < countStage; jj++) {
var pos = jj + 1; var pos = jj + 1;
var lastFormStage = $(".numberStepp").last(); var lastFormStage = $("#order-stages .numberStepp").last();
var orderId = lastFormStage.find('.orderStagesInput').val(); var orderId = lastFormStage.find('.orderStagesInput').val();
var addFormTemplate = '<div class="numberStepp box-sizing" id="stage1">' + var addFormTemplate = '<div class="numberStepp box-sizing" id="stage1">' +
'<p>Этап <span class="stage-span-id">' + pos + '</span></p><form class="new-stages-form" id="stage-form">' + '<p>Этап <span class="stage-span-id">' + pos + '</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="name" type="text">' +
'<label for="">Цена</label><input class="form-control" name="cost" type="text" />' + '<label for="">Цена</label><input class="form-control" name="cost" type="text">' +
'<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '" />' + '<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '">' +
'<label for="">Срок</label><input class="term-picker form-control datepicker" name="term" type="text" />' + '<input class="form-control" type="hidden" name="status" value="send_approve">' +
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' + '<label for="">Срок</label><input class="term-picker form-control datepicker" name="term" type="text">' +
'<input class="form-control" name="pos" value="' + pos + '" type="hidden" />' '<label for="">Результат</label><input class="form-control" name="result" type="text">' +
'</form></div>'; '<input class="form-control" name="pos" value="' + pos + '" type="hidden"></form></div>';
lastFormStage.after(addFormTemplate); lastFormStage.after(addFormTemplate);
} }
} else if (countStage < currentCountStage) { } else if (countStage < currentCountStage) {
var ii = currentCountStage; var ii = currentCountStage;
$($(".numberStepp").get().reverse()).each(function () { $($("#order-stages .numberStepp").get().reverse()).each(function () {
var currenFormName = ($(this).find('form').attr('class')); var currenFormName = ($(this).find('form').attr('class'));
if (ii > countStage) { if (ii > countStage) {
$(this).remove(); $(this).remove();
@ -639,6 +634,8 @@
} }
}); });
// Для заказов все вытащить // Для заказов все вытащить
$('.order-block').on('click', function () { $('.order-block').on('click', function () {
$("#chat-order-add").css("display", "block"); $("#chat-order-add").css("display", "block");
@ -675,10 +672,8 @@
}, },
dataType: 'json', dataType: 'json',
success: function (json){ success: function (json){
console.log(json);
$.each(json.results, function (i, v) { $.each(json.results, function (i, v) {
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="'+ v.file_url +'">'+ v.file+'</a></li>'; docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="'+ v.file_url +'">'+ v.file+'</a><div class="remove-document" data-id="'+ v.id+'" style="right:-10px;"></div></li>';
}); });
}, },
error: function(e){ error: function(e){

@ -69,6 +69,7 @@ class ChatUserView(LoginRequiredMixin, View):
if request.user.is_owner_team(): if request.user.is_owner_team():
team_ids.append(request.user.team.pk) team_ids.append(request.user.team.pk)
team_orders = request.user.team.orders.all() team_orders = request.user.team.orders.all()
teams = Team.objects.filter(contractors__id=request.user.pk).all()
else: else:
teams = Team.objects.filter(contractors__id=request.user.pk).all() teams = Team.objects.filter(contractors__id=request.user.pk).all()
team_orders = Order.objects.filter(team_id__in=[team.pk for team in teams]).all() team_orders = Order.objects.filter(team_id__in=[team.pk for team in teams]).all()
@ -89,14 +90,13 @@ class ChatUserView(LoginRequiredMixin, View):
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')
your_teams = teams
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,
'contacts_users': contacts_users, 'contacts_users': contacts_users,
'chat_messages': chat_messages, 'chat_messages': chat_messages,
'team_orders': team_orders, 'team_orders': team_orders,
'your_teams': your_teams,
}) })

@ -237,9 +237,11 @@ class Arbitration(models.Model):
STATUSES = ( STATUSES = (
('not_agreed','Не согласован'), ('not_agreed', 'Не согласован'),
('in_process','В процессе'), ('send_approve', 'На согласовании'),
('completed','Завершен'), ('cancel_approve', 'Исполнитель отказался'),
('in_process', 'В процессе'),
('completed', 'Завершен'),
) )

@ -123,9 +123,16 @@ class OrderSerializer(ModelSerializer):
) )
def get_has_user_review(self,obj): def get_has_user_review(self,obj):
# obj.project. curr_user = self.context['request'].user
print(self.context['request'].user) if curr_user.is_customer():
return "yes" return curr_user.customer_reviews.filter(project=obj.project).exists()
elif curr_user.is_contractor():
if obj.team is None and obj.contractor:
return curr_user.contractor_reviews.filter(project=obj.project).exists()
elif curr_user.team:
return curr_user.team.team_reviews.filter(project=obj.project).exists()
else:
return False
class PortfolioPhotoSerializer(ModelSerializer): class PortfolioPhotoSerializer(ModelSerializer):

@ -27,7 +27,9 @@
<a href="#" class="aLinkExe"> <a href="#" class="aLinkExe">
<div class="imgExecutor"> <div class="imgExecutor">
{% if project.customer.avatar %} {% if project.customer.avatar %}
<img src="{{ project.customer.avatar.url }}" alt="execitor-image"> {% thumbnail project.customer.avatar "125x125" crop="center" as im %}
<img src="{{ im.url }}" alt="execitor-image">
{% endthumbnail %}
{% else %} {% else %}
<img src="{% static 'img/profile.jpg' %}" alt="execitor-image"> <img src="{% static 'img/profile.jpg' %}" alt="execitor-image">
{% endif %} {% endif %}
@ -517,7 +519,9 @@
<a href="#" class="aLinkExe"> <a href="#" class="aLinkExe">
<div class="imgExecutor"> <div class="imgExecutor">
{% if answer.author.avatar %} {% if answer.author.avatar %}
<img src="{{ answer.author.avatar.url }}" alt="execitor-image"> {% thumbnail answer.author.avatar "125x125" crop="center" as im %}
<img src="{{ im.url }}" alt="execitor-image">
{% endthumbnail %}
{% else %} {% else %}
<img src="{% static 'img/profile.jpg' %}" alt="execitor-image"> <img src="{% static 'img/profile.jpg' %}" alt="execitor-image">
{% endif %} {% endif %}
@ -677,7 +681,9 @@
<a href="#" class="aLinkExe"> <a href="#" class="aLinkExe">
<div class="imgExecutor"> <div class="imgExecutor">
{% if answer.author.avatar %} {% if answer.author.avatar %}
<img src="{{ answer.author.avatar.url }}" alt="execitor-image"> {% thumbnail answer.author.avatar "125x125" crop="center" as im %}
<img src="{{ im.url }}" alt="execitor-image">
{% endthumbnail %}
{% else %} {% else %}
<img src="{% static 'img/profile.jpg' %}" alt="execitor-image"> <img src="{% static 'img/profile.jpg' %}" alt="execitor-image">
{% endif %} {% endif %}
@ -839,7 +845,9 @@
<a href="#" class="aLinkExe"> <a href="#" class="aLinkExe">
<div class="imgExecutor"> <div class="imgExecutor">
{% if answer.author.avatar %} {% if answer.author.avatar %}
<img src="{{ answer.author.avatar.url }}" alt="execitor-image"> {% thumbnail answer.author.avatar "125x125" crop="center" as im %}
<img src="{{ im.url }}" alt="execitor-image">
{% endthumbnail %}
{% else %} {% else %}
<img src="{% static 'img/profile.jpg' %}" alt="execitor-image"> <img src="{% static 'img/profile.jpg' %}" alt="execitor-image">
{% endif %} {% endif %}

@ -88,7 +88,7 @@
if ((queryString.indexOf('/chat') != 0) && (queryString.indexOf('/users/contractor-office/510/work-projects') != 0)) { if ((queryString.indexOf('/chat') != 0) && (queryString.indexOf('/users/contractor-office/510/work-projects') != 0)) {
domain = domain.replace(':' + port, ''); domain = domain.replace(':' + port, '');
var url = 'ws://' + domain + ':8888/chat/' + userId + '/'; var url = 'ws://' + domain + '/chat/' + userId + '/';
var sock = new WebSocket(url); var sock = new WebSocket(url);
var intervalId; var intervalId;
sock.onopen = function () { sock.onopen = function () {

@ -78,6 +78,12 @@
</a> </a>
</div> </div>
{# <div class="pull-left -social -vk">#}
{# <a href="{% url 'social:begin' 'mailru-oauth2' %}">#}
{# <img src="http://nepesh.com/static/img/social/vk.png" alt="vk">#}
{# </a>#}
{# </div>#}
<div class="pull-left -social -ok"> <div class="pull-left -social -ok">
<a href="{% url 'social:begin' 'odnoklassniki-oauth2' %}"> <a href="{% url 'social:begin' 'odnoklassniki-oauth2' %}">
<img src="http://nepesh.com/static/img/social/ok.gif" alt="yt"> <img src="http://nepesh.com/static/img/social/ok.gif" alt="yt">

Loading…
Cancel
Save