remotes/origin/PR-39
ArturBaybulatov 9 years ago
commit af7fd27064
  1. 2
      api/urls.py
  2. 20
      api/views.py
  3. 2
      archilance/settings/base.py
  4. 1
      assets/css/jquery.jgrowl.min.css
  5. 5
      assets/css/main.css
  6. 171
      assets/js/chat.js
  7. 28
      assets/js/chat_contractor.js
  8. 3
      chat/admin.py
  9. 20
      chat/chat.py
  10. 2
      chat/filters.py
  11. 30
      chat/migrations/0014_newmessage.py
  12. 12
      chat/models.py
  13. 18
      chat/templates/chat_contractor.html
  14. 83
      chat/templates/chat_customer.html
  15. 4
      chat/templates/review_add_modal.html
  16. 35
      projects/migrations/0030_auto_20160912_1912.py
  17. 7
      projects/models.py
  18. 1
      templates/partials/base.html
  19. 4
      templates/partials/header.html
  20. 7
      users/serializers.py
  21. 1
      users/templates/templatetags/user_new_count_orders.html
  22. 18
      users/templatetags/user_tags.py
  23. 30
      wallets/views.py
  24. 20
      work_sell/migrations/0013_auto_20160912_1912.py

@ -30,7 +30,7 @@ router.register(r'contractorresume', ContractorResumeViewSet)
router.register(r'contractorresumefiles', ContractorResumeFilesViewSet)
router.register(r'documents', DocumentViewSet)
router.register(r'locations', LocationViewSet)
router.register(r'message', MessageViewSet)
router.register(r'message', MessageViewSet, base_name='Message')
router.register(r'note', NoteViewSet)
router.register(r'orders', OrderViewSet)
router.register(r'portfolio-photos', PortfolioPhotoViewSet)

@ -28,7 +28,7 @@ from common.models import Location
from common.serializers import LocationSerializer
from common.filters import LocationFilterSet
from chat.models import Message, Notes, Documents
from chat.models import Message, Notes, Documents, NewMessage
from chat.serializers import MessageSerializer, NoteSerializer, DocumentsSerializer
from chat.filters import MessageFilterSet, NoteFilterSet, DocumentFilterSet
@ -112,12 +112,12 @@ class NoteViewSet(ModelViewSet):
class MessageViewSet(ModelViewSet):
queryset = Message.objects.all()
# queryset = Message.objects.all()
serializer_class = MessageSerializer
filter_class = MessageFilterSet
def get_queryset(self):
queryset = Message.objects.filter(is_delete=False)
queryset = Message.objects.all()
search_param = self.request.query_params.get('operand', None)
recipent_id = self.request.query_params.get('recipent_id', None)
sender_id = self.request.query_params.get('sender_id', None)
@ -126,7 +126,15 @@ class MessageViewSet(ModelViewSet):
if search_param == 'in':
queryset = queryset.filter(Q(sender__in=[sender_id,recipent_id]),Q(recipent__in=[sender_id,recipent_id])).\
filter(order__isnull=True).\
filter(~Q(sender=F('recipent'))).order_by('created')
filter(~Q(sender=F('recipent')))
queryset = queryset.order_by('created')
return queryset
def filter_queryset(self, queryset):
queryset = super().filter_queryset(queryset)
qs = NewMessage.objects.filter(message__in=queryset, user=self.request.user).delete()
return queryset
@ -167,13 +175,12 @@ class LocationViewSet(ModelViewSet):
filter_class = LocationFilterSet
class PortfolioPagination(PageNumberPagination):
page_size = settings.API_PAGE_SIZE # Default page size
page_size_query_param = 'page_size' # Provide custom page size through a query param
max_page_size = 1000
class PortfolioViewSet(ModelViewSet):
queryset = Portfolio.objects.all()
serializer_class = PortfolioSerializer
@ -181,7 +188,6 @@ class PortfolioViewSet(ModelViewSet):
pagination_class = PortfolioPagination
class PortfolioPhotoViewSet(ModelViewSet):
queryset = PortfolioPhoto.objects.all()
serializer_class = PortfolioPhotoSerializer

@ -266,7 +266,7 @@ if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
PAGE_SIZE = 10 # Non-api page size (regular views)
API_PAGE_SIZE = 100 # Django REST framework
API_PAGE_SIZE = 1000 # Django REST framework
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [

@ -0,0 +1 @@
.jGrowl{z-index:9999;color:#fff;font-size:12px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;position:fixed}.jGrowl.top-left{left:0;top:0}.jGrowl.top-right{right:0;top:0}.jGrowl.bottom-left{left:0;bottom:0}.jGrowl.bottom-right{right:0;bottom:0}.jGrowl.center{top:0;width:50%;left:25%}.jGrowl.center .jGrowl-closer,.jGrowl.center .jGrowl-notification{margin-left:auto;margin-right:auto}.jGrowl-notification{background-color:#000;opacity:.9;-ms-filter:alpha(90);filter:alpha(90);zoom:1;width:250px;padding:10px;margin:10px;text-align:left;display:none;border-radius:5px;min-height:40px}.jGrowl-notification .ui-state-highlight,.jGrowl-notification .ui-widget-content .ui-state-highlight,.jGrowl-notification .ui-widget-header .ui-state-highlight{border:1px solid #000;background:#000;color:#fff}.jGrowl-notification .jGrowl-header{font-weight:700;font-size:.85em}.jGrowl-notification .jGrowl-close{background-color:transparent;color:inherit;border:none;z-index:99;float:right;font-weight:700;font-size:1em;cursor:pointer}.jGrowl-closer{background-color:#000;opacity:.9;-ms-filter:alpha(90);filter:alpha(90);zoom:1;width:250px;padding:10px;margin:10px;display:none;border-radius:5px;padding-top:4px;padding-bottom:4px;cursor:pointer;font-size:.9em;font-weight:700;text-align:center}.jGrowl-closer .ui-state-highlight,.jGrowl-closer .ui-widget-content .ui-state-highlight,.jGrowl-closer .ui-widget-header .ui-state-highlight{border:1px solid #000;background:#000;color:#fff}@media print{.jGrowl{display:none}}

@ -5983,12 +5983,15 @@ a.linkS2[data-target="#withdraw-money"]{
border-radius: 50px;
border: 1px solid #42B476;
}
input[type="radio"]{
opacity: 0;
opacity: 1;
}
.wr-inset-pluss{
margin-top: 24px;
}
.inset-gp .upload2{
float: left;
margin: -15px 15px 0 12px;

@ -39,8 +39,7 @@ var SocketHandler = function () {
});
setTimeout(function () {
$("#orderBlock" + resOrderId).trigger('click');
}, 2000);
console.log('approve stages');
}, 200);
}
if (inbox) {
@ -77,8 +76,9 @@ function csrfSafeMethod(method) {
var socket = new SocketHandler();
var csrftoken = getCookie('csrftoken');
$(function () {
$(function () {
function dialog(message, yesCallback, notCallback) {
$("#dialog_delete .modal-title").html(message);
var dialog = $("#dialog_delete").modal('show');
@ -93,48 +93,67 @@ $(function () {
}
var currentHash = URI(location.href).hash();
$('a[data-toggle="tab"]').on('show.bs.tab', function (e) {
var activeTab = $(this).attr('href').substring(1);
var liveHash = URI(location.href).hash();
switch(activeTab){
case 'tab1':
setTimeout(function () {
if(liveHash.indexOf("#user") == 0) {
var userHashId = liveHash.replace("#user", "");
$("#userBlock" + userHashId).trigger('click');
} else {
$(".user-block").first().trigger('click');
}
}, 100);
break;
case 'tab2':
setTimeout(function () {
if(liveHash.indexOf("#order") == 0) {
var ordHashId = liveHash.replace("#order", "");
$("#orderBlock" + ordHashId).trigger('click');
} else {
$(".order-block").first().trigger('click');
}
}, 100);
break;
case 'tab3':
setTimeout(function () {
if(liveHash.indexOf("#teamorder") == 0) {
var teamHashId = liveHash.replace("#teamorder", "");
$("#teamOrderBlock" + teamHashId).trigger('click');
} else if(liveHash.indexOf("#myteam") == 0){
var teamHashId = liveHash.replace("#myteam", "");
$("#teamMyBlock" + teamHashId).trigger('click');
} else {
var firstTeamBlock = $(".team-block").first();
var firstTeamOrder = $(".team-order-block").first();
if (firstTeamOrder.length == 1){
firstTeamOrder.trigger('click');
} else if(firstTeamBlock.length == 1){
firstTeamBlock.trigger('click');
}
}
}, 100);
}
});
if (currentHash.indexOf("#order") == 0) {
var ordHashId = currentHash.replace("#order", "");
setTimeout(function () {
$("#orderBlock" + ordHashId).trigger('click');
$("a[href='#tab2']").trigger('click');
}, 100);
$("a[href='#tab2']").trigger('click');
} else if(currentHash.indexOf("#user") == 0){
var userHashId = currentHash.replace("#user", "");
setTimeout(function () {
$("#userBlock" + userHashId).trigger('click');
//$("a[href='#tab1']").trigger('click');
}, 100);
} else if (currentHash.indexOf("#teamorder") == 0) {
var teamHashId = currentHash.replace("#teamorder", "");
$("#teamOrderBlock" + teamHashId).trigger('click');
$("a[href='#tab3']").trigger('click');
} else if (currentHash.indexOf("#myteam") == 0){
var teamHashId = currentHash.replace("#myteam", "");
$("#teamMyBlock" + teamHashId).trigger('click');
$("a[href='#tab3']").trigger('click');
$("a[href='#tab1']").trigger('click');
} else if (currentHash.indexOf("#teamorder") == 0 || currentHash.indexOf("#myteam") == 0) {
$("a[href='#tab3']").trigger('click');
} else {
setTimeout(function () {
$(".user-block").first().trigger('click');
location.hash = '';
}, 10);
setTimeout(function () {
$(".order-block").first().trigger('click');
location.hash = '';
}, 500);
setTimeout(function () {
var firstTeamBlock = $(".team-block").first();
var firstTeamOrder = $(".team-order-block").first();
if (firstTeamOrder.length == 1){
firstTeamOrder.trigger('click');
} else if(firstTeamBlock.length == 1){
firstTeamBlock.trigger('click');
}
location.hash = '';
}, 1000);
$("a[href='#tab1']").trigger('click');
}
// Информация о заказе
$(".full-order-info").click('on', function (e) {
e.preventDefault();
@ -220,12 +239,26 @@ $(function () {
dataType: 'json',
success: function (json) {
if (json.status == 'ok') {
socket.send_stages_approve({
"format_type": "approve_stages",
"data": {
"sender_id": json.sender,
"recipent_id": json.recipent,
"order_id": json.order,
"msg": "Заказчик зарезервировал сумму для этапов " + json.stages,
}
});
$("#reserve-stage-modal").modal('hide');
$("#orderBlock" + orderId).trigger('click');
}else if(json.status == 'error'){
alert(json.message_error);
}
},
error: function (e, jqxhr) {
console.log(e);
console.log(jqxhr);
}
})
});
@ -275,54 +308,54 @@ $(function () {
docList.innerHTML = '';
$.ajax({
url: '/api/documents',
url: '/api/message',
type: 'GET',
data: {
csrfmiddlewaretoken: csrftoken,
'operand': 'in',
'sender_id': userId,
'recipent_id': contactId,
'is_delete': false,
'is_send': true,
'recipent_id': contactId
},
dataType: 'json',
success: function (json) {
console.log(json);
$.each(json.results, function (i, v) {
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="/chat/download/' + v.file + '">' + v.file + '</a><div class="remove-document" data-id="' + v.id + '" style="right:-10px;"></div></li>';
var senderName = 'Вы';
var className = 'youChat';
if (v.sender.id == contactId) {
senderName = v.sender.username;
className = '';
}
inbox.innerHTML += '<div class="col-lg-12 insetCommChat ' + className + '"><div class="topCommChat">' +
'<p class="nameCommChat">' + senderName + '</p> <span>' + v.created + '</span></div>' +
'<p class="textCommChat">' + v.text + '</p></div>';
});
},
error: function (e) {
console.log(e);
var height = inbox.scrollHeight;
inbox.scrollTop = height;
}
});
$.ajax({
url: '/api/message',
url: '/api/documents',
type: 'GET',
data: {
csrfmiddlewaretoken: csrftoken,
'operand': 'in',
'sender_id': userId,
'recipent_id': contactId
'recipent_id': contactId,
'is_delete': false,
'is_send': true,
},
dataType: 'json',
success: function (json) {
console.log(json);
$.each(json.results, function (i, v) {
var senderName = 'Вы';
var className = 'youChat';
if (v.sender.id == contactId) {
senderName = v.sender.username;
className = '';
}
inbox.innerHTML += '<div class="col-lg-12 insetCommChat ' + className + '"><div class="topCommChat">' +
'<p class="nameCommChat">' + senderName + '</p> <span>' + v.created + '</span></div>' +
'<p class="textCommChat">' + v.text + '</p></div>';
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="/chat/download/' + v.file + '">' + v.file + '</a><div class="remove-document" data-id="' + v.id + '" style="right:-10px;"></div></li>';
});
var height = inbox.scrollHeight;
inbox.scrollTop = height;
},
error: function (e) {
console.log(e);
}
});
@ -346,7 +379,6 @@ $(function () {
}
});
});
$('.deleteMess').on('click', function (e) {
@ -634,7 +666,6 @@ $(function () {
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled'); //Загрузка документов
$("#upload-document-contact").bind('fileuploadsubmit', function (e, data) {
data.formData = {
sender: $("#contact-chat-form #senderContactId").val(),
@ -643,7 +674,6 @@ $(function () {
});
$('#upload-document-contact').fileupload({
url: '/chat/create/',
crossDomain: false,
@ -677,6 +707,11 @@ $(function () {
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
$('#review-add').on('show.bs.modal', function (e) {
var related = $(e.relatedTarget);
var relatedType = related.attr('data-review-type');
$('input[name="type"]').filter('[value="'+ relatedType+'"]').prop("checked", true);
});
});

@ -64,7 +64,6 @@ $(function () {
dataType: 'json',
success: function (json) {
console.log(json);
},
error: function (e) {
console.log('error');
@ -74,7 +73,6 @@ $(function () {
});
var orderId = $(this).attr('data-order-id');
socket.send_stages_approve({
"format_type": "approve_stages",
"data": {
@ -132,15 +130,23 @@ $(function () {
});
$(".team-order-block").on('click', function () {
$('.team-order-block, .team-block').each(function () {
$(this).removeClass('orAct');
});
$(this).addClass('orAct');
var teamIds = '';
$.each($(this).find('.team-chat-user'), function(i,v){
teamIds += $(this).attr('data-id') + ";";
});
$("#team-chat-form #teamIds").val(teamIds);
var teamId = $(this).attr('data-team-id');
location.hash = '#teamorder' + teamId;
var orderId = $(this).attr('data-order-id');
location.hash = '#teamorder' + orderId;
$("#team-chat-form #teamId").val(teamId);
$("#team-chat-form #recipentTeamId").val("");
$("#team-chat-form #orderTeamId").val(orderId);
$("#add-form-team-note #teamNote").val(teamId);
@ -219,6 +225,12 @@ $(function () {
});
$(this).addClass('orAct');
var teamIds = '';
$.each($(this).find('.team-chat-user'), function(i,v){
teamIds += $(this).attr('data-id') + ";";
});
$("#team-chat-form #teamIds").val(teamIds);
var inbox = document.getElementById('message-chat-team-space');
inbox.innerHTML = '';
@ -229,6 +241,7 @@ $(function () {
location.hash = '#myteam' + teamId;
$("#team-chat-form #teamId").val(teamId);
$("#add-form-team-note #teamNote").val(teamId);
$("#team-chat-form #recipentTeamId").val("");
$("#team-chat-form #orderTeamId").val("");
$("#add-form-team-note #orderNote").val("");
@ -445,11 +458,12 @@ $(function () {
'</div><div><p>' + statusName + '</p></div></div></div>';
});
if (statusNotAgreed) {
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="'+ userId +'" data-recipent-id="' + recipentId + '"' +
' data-order-id="' + orderId + '" href="#">согласовать</a>' +
'<a id="cancel-stages" data-sender-id="{{ request.user.pk }}" data-recipent-id="' + recipentId + '"' +
'<a id="cancel-stages" data-sender-id="'+ userId +'" data-recipent-id="' + recipentId + '"' +
' data-order-id="' + orderId + '" href="#">отказаться</a>' +
'</div>';
}
@ -473,7 +487,7 @@ $(function () {
'<div><p>Срок сдачи ' + stage.term + ' <span>' + stage.cost + '<i class="fa fa-rub"></i></span></p></div></div></div>';
if (!stage.close_contractor) {
stageWork += '<div class="textAreaBlock2 FFD box-sizing disTab"><a href="#" class="closeStage" data-sender-id="{{ request.user.pk }}" data-recipent-id="' + recipentId + '"' +
stageWork += '<div class="textAreaBlock2 FFD box-sizing disTab"><a href="#" class="closeStage" data-sender-id="'+ userId +'" data-recipent-id="' + recipentId + '"' +
' data-order-id="' + data.id + '" data-stage-id="' + stage.id + '">Завершить этап</a></div>';
} else {
stageWork += '<div><p>Этап ожидает завершения статуса от заказчика</p><div>';
@ -540,6 +554,7 @@ $(function () {
var teamId = $("#team-chat-form #teamId").val();
var orderId = $("#team-chat-form #orderTeamId").val();
var documentSendIds = $("#documentSendIds").val();
var teamIds = $("#team-chat-form #teamIds").val();
if (chatMessage) {
var sendLinks = $("#document-send a");
@ -561,6 +576,7 @@ $(function () {
"recipent_id": recipentId,
"chat_message": chatMessage,
"team_id": teamId,
"team_ids": teamIds,
"order_id": orderId,
"document_send_links": sendLinkIds,
"document_data": {

@ -1,5 +1,5 @@
from django.contrib import admin
from .models import Message, Notes, Documents
from .models import Message, Notes, Documents, NewMessage
class MessageAdmin(admin.ModelAdmin):
@ -17,3 +17,4 @@ class DocumentsAdmin(admin.ModelAdmin):
admin.site.register(Message, MessageAdmin)
admin.site.register(Notes, NotesAdmin)
admin.site.register(Documents, DocumentsAdmin)
admin.site.register(NewMessage)

@ -43,6 +43,9 @@ class ChatHandler(websocket.WebSocketHandler):
@gen.coroutine
def approve_stages(self, data):
print(data)
data['data']['chat_message'] = data['data']['msg']
self.add_message(data)
sender_id = data['data']['sender_id']
recipent_id = data['data']['recipent_id']
order_id = data['data'].get('order_id')
@ -54,11 +57,11 @@ class ChatHandler(websocket.WebSocketHandler):
@gen.coroutine
def add_message(self, message_data):
sender_id = message_data['data']['sender_id']
recipent_id = message_data['data'].get('recipent_id', None)
order_id = message_data['data'].get('order_id', None)
team_id = message_data['data'].get('team_id', None)
team_ids_raw = message_data['data'].get('team_ids', None)
message = message_data['data'].get('chat_message', None)
docs_send_links = message_data['data'].get('document_send_links', None)
if 'document_data' in message_data['data']:
@ -78,7 +81,7 @@ class ChatHandler(websocket.WebSocketHandler):
team_value = "NULL" if team_id is None or not team_id else team_id
if not team_id and not recipent_id:
if not recipent_id:
recipent_id = sender_id
order_value = "NULL" if order_id is None or not order_id else order_id
@ -92,6 +95,19 @@ class ChatHandler(websocket.WebSocketHandler):
cursor = cursor_list.get('cursor')
result = cursor.fetchone()
message_id = result[0]
if team_ids_raw:
team_ids = [t for t in team_ids_raw.rstrip(';').split(';')]
values_str = '';
for t in team_ids:
values_str +='(DEFAULT,{0},{1}),'.format(message_id,t)
values_str = values_str.rstrip(',')
insert_new_messages = "INSERT INTO chat_newmessage (id,message_id, user_id) VALUES{0}".\
format(values_str)
else:
insert_new_messages = "INSERT INTO chat_newmessage (id,message_id, user_id) VALUES(DEFAULT,{0},{1})".\
format(message_id, recipent_id)
yield self.db.execute(insert_new_messages)
if docs_send_links:
is_send = 'true'
docs_send_ids = docs_send_links.rstrip(';').replace(';', ',')

@ -27,6 +27,8 @@ class MessageFilterSet(FilterSet):
model = Message
class DocumentFilterSet(FilterSet):
id = AllLookupsFilter()
# order = RelatedFilter('projects.filters.OrderFilterSet')

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-12 16:12
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('chat', '0013_auto_20160907_1556'),
]
operations = [
migrations.CreateModel(
name='NewMessage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('message', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='new_messages', to='chat.Message')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='new_messages', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name_plural': 'Новые сообщения',
'verbose_name': 'Новые сообщения',
},
),
]

@ -24,6 +24,18 @@ class Message(models.Model):
verbose_name_plural = 'Сообщения'
class NewMessage(models.Model):
user = models.ForeignKey(User, related_name='new_messages')
message = models.ForeignKey(Message, related_name='new_messages')
def __str__(self):
return str(self.id)
class Meta:
verbose_name = 'Новые сообщения'
verbose_name_plural = 'Новые сообщения'
class Notes(models.Model):
text = models.TextField()
created = models.DateTimeField(default=timezone.now)

@ -15,7 +15,7 @@
<div class="profileTabs2">
<ul class="nav nav-tabs nav-justified">
<li role="presentation" class="active">
<li role="presentation">
<a href="#tab1" data-toggle="tab">Личные</a>
</li>
@ -34,7 +34,7 @@
{% include 'dialog_delete.html' %}
<div class="tab-content">
<!-- Tab1 contacts block -->
<div class="chatBlock disTab tab-pane fade in active" id="tab1">
<div class="chatBlock disTab tab-pane fade in" id="tab1">
<div class="col-lg-3 wrMessages">
<div class="messageBlock box-sizing disTab">
<p>Контакты</p>
@ -190,13 +190,20 @@
</div>
</div>
<div class="closeChat closeChat1" id="leaveReview" style="display: none;">
<a href="#" data-toggle="modal" data-target="#review-add">
<div id="leaveReview" style="display: none;">
<div class="closeChat closeChat1">
<a href="#" data-toggle="modal" data-target="#review-add" data-review-type="positive">
Закрыть проект<br>и оставить отзыв
</a>
</div>
<div class="closeChat closeChat2">
<a href="#" data-toggle="modal" data-target="#review-add" data-review-type="negative">
Закрыть проект<br>и оставить отзыв
</a>
</div>
</div>
<!-- Review add -->
{% include 'review_add_modal.html' %}
<!-- -->
@ -311,6 +318,7 @@
<input type="hidden" name="recipent" id="recipentTeamId">
<input type="hidden" name="order" id="orderTeamId">
<input type="hidden" name="team" id="teamId">
<input type="hidden" name="team_ids" id="teamIds">
<input type="hidden" name="document-send" id="documentSendIds">
<textarea id="chatText" class="chat-textarea box-sizing"></textarea>
<div class="bunChat">

@ -6,14 +6,14 @@
<div class="container mainScore">
<div class="row">
<div class="col-lg-12 allProjects">
<h1>Чат</h1>
<h1>Чат {{ request.user.get_score }}</h1>
</div>
<div class="btnReadyBlock disTab">
<div class="triangle1"></div>
<div class="col-lg-6 col-lg-offset-3 tabsChat">
<div class="profileTabs2">
<ul class="nav nav-tabs nav-justified">
<li role="presentation" class="active">
<li role="presentation">
<a href="#tab1" data-toggle="tab">Личные</a>
</li>
<li role="presentation">
@ -26,7 +26,7 @@
{% include 'dialog_delete.html' %}
<div class="tab-content">
<!-- Tab1 (contacts block)-->
<div class="chatBlock disTab tab-pane fade in active" id="tab1">
<div class="chatBlock disTab tab-pane fade in" id="tab1">
<div class="col-lg-3 wrMessages">
<div class="messageBlock box-sizing disTab">
<p>Контакты</p>
@ -162,7 +162,7 @@
</div>
</form>
</div>
<div class="col-lg-3 wrstepschat" id="order-stages-tab">
<div class="col-lg-3 wrstepschat" id="order-stages-tab" data-score="">
<p>Этапы работы</p>
<div class="stepssBlock box-sizing disTab">
<p class="titleStepss">1 / Согласование условий</p>
@ -200,11 +200,18 @@
<div id="stagesWork" class="stages-work"></div>
</div>
<div class="closeChat closeChat1" id="leaveReview" style="display: none;">
<a href="#" data-toggle="modal" data-target="#review-add">
<div id="leaveReview" style="display: none;">
<div class="closeChat closeChat1">
<a href="#" data-toggle="modal" data-target="#review-add" data-review-type="positive">
Закрыть проект<br>и оставить отзыв
</a>
</div>
<div class="closeChat closeChat2">
<a href="#" data-toggle="modal" data-target="#review-add" data-review-type="negative">
Закрыть проект<br>и оставить отзыв
</a>
</div>
</div>
<div class="col-lg-12 documentsChat">
<p>Прикрепленные документы</p>
@ -460,6 +467,7 @@
}else if((stagesResults.length>0) && (data.secure)){
$("#reserveSpace").show();
}
htmlInbox = htmlInboxStage + htmlInbox;
$("#order-stages").html(htmlInbox);
$("#completeWork").hide();
@ -558,6 +566,7 @@
}
$(".new-stages-form").each(function (i, v) {
var _this = $(this);
$.ajax({
url: '/api/stages/',
type: 'POST',
@ -567,8 +576,8 @@
data: $(this).serialize(),
dataType: 'json',
success: function (json) {
_this.removeClass('new-stages-form').addClass('update-stages-form');
console.log(json);
},
error: function (e) {
console.log('error');
@ -608,7 +617,7 @@
"sender_id": userId,
"recipent_id": currentRecipentId,
"order_id": currentOrderId,
"msg": "Этапы для заказа "+ currentOrderId +"изменены",
"msg": "Этапы для заказа "+ currentOrderId +" изменены",
}
});
@ -683,25 +692,6 @@
inbox.innerHTML = '';
docList.innerHTML = '';
$.ajax({
url:'/api/documents',
type: 'GET',
data:{
csrfmiddlewaretoken: csrftoken,
'order': orderId,
'is_delete': false,
'is_send': true,
},
dataType: 'json',
success: function (json){
$.each(json.results, function (i, v) {
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="/chat/download/' + v.file + '">' + v.file+'</a><div class="remove-document" data-id="'+ v.id+'" style="right:-10px;"></div></li>';
});
},
error: function(e){
console.log(e);
}
});
$.ajax({
url: '/api/message',
type: 'GET',
@ -726,6 +716,44 @@
inbox.scrollTop = height;
}
});
$.ajax({
url: '/api/users/{{ request.user.pk }}/',
type: 'GET',
data: {
csrfmiddlewaretoken: csrftoken,
},
dataType:'json',
success: function(json){
var score = json.score;
$("#order-stages-tab").attr('data-score', score);
},
error: function(e,jqxhr){
console.log(jqxhr);
}
})
$.ajax({
url:'/api/documents',
type: 'GET',
data:{
csrfmiddlewaretoken: csrftoken,
'order': orderId,
'is_delete': false,
'is_send': true,
},
dataType: 'json',
success: function (json){
$.each(json.results, function (i, v) {
docList.innerHTML += '<li style="word-break: break-all;"><a class="file-link" href="/chat/download/' + v.file + '">' + v.file+'</a><div class="remove-document" data-id="'+ v.id+'" style="right:-10px;"></div></li>';
});
},
error: function(e){
console.log(e);
}
});
$.ajax({
url: '/api/note/',
type: 'GET',
@ -735,7 +763,6 @@
},
dataType: 'json',
success: function (json) {
console.log(json.results);
var noteHtmlInbox = '';
$.each(json.results, function (i, v) {
noteHtmlInbox += '<li>' + v.text + '<li>';

@ -11,7 +11,8 @@
<form id="review-adds-form" method="POST">
<div class="modal-body">
<div style="height: 250px;">
<div class="searchF1 polsF1 polsFF radio-afer">
{# <div class="searchF1 polsF1 polsFF radio-afer">#}
<div>
<input type="radio" value="positive"
name="type">Положительный
@ -21,6 +22,7 @@
<input type="radio" value="neutral"
name="type">Нейтральный
</div>
<div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Ваш отзыв</p>
<textarea id="text-new" name="text"></textarea>

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-12 16:12
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0029_auto_20160908_1159'),
]
operations = [
migrations.AlterField(
model_name='answer',
name='term_type',
field=models.CharField(blank=True, choices=[('day', 'день'), ('hour', 'час'), ('month', 'месяц'), ('project', 'проект')], max_length=10, null=True),
),
migrations.AlterField(
model_name='portfolio',
name='term_type',
field=models.CharField(blank=True, choices=[('day', 'день'), ('hour', 'час'), ('month', 'месяц'), ('project', 'проект')], default='hour', max_length=20, null=True),
),
migrations.AlterField(
model_name='project',
name='term_type',
field=models.CharField(choices=[('day', 'день'), ('hour', 'час'), ('month', 'месяц'), ('project', 'проект')], default='hour', max_length=20),
),
migrations.AlterField(
model_name='stage',
name='term_type',
field=models.CharField(choices=[('day', 'день'), ('hour', 'час'), ('month', 'месяц'), ('project', 'проект')], default='hour', max_length=10),
),
]

@ -220,6 +220,13 @@ class Order(models.Model):
verbose_name = 'Заказ'
verbose_name_plural = 'Заказы'
def get_contractor_owner(self):
if self.contractor:
return self.contractor.pk
elif self.team:
return self.team.owner.pk
else:
return None
class Arbitration(models.Model):
user = models.ForeignKey(User)

@ -98,7 +98,6 @@
sock.onmessage = function (event) {
var notificationData = JSON.parse(event.data);
console.log(notificationData);
var outMessage = "";
if (notificationData.answer_type == 'add_message_contact'){
outMessage += "<a href='/chat/?user_id=" + notificationData.sender_id + "'>"+ notificationData.msg +"<a>";

@ -27,7 +27,9 @@
{% if request.user.is_contractor %}
<li class="officeList icon_tml">
<a href="{% url 'users:contractor-office' %}">Мой офис</a>
<a href="{% url 'users:contractor-office' %}">
Мой офис {% count_new_message_orders request.user %}
</a>
<span></span>
</li>
{% endif %}

@ -36,7 +36,8 @@ class UserSerializer(ModelSerializer):
_type = SerializerMethodField() # Distinguish when used with generic serializers
id = ReadOnlyField()
fio = SerializerMethodField()
score = SerializerMethodField()
class Meta:
model = User
@ -64,6 +65,7 @@ class UserSerializer(ModelSerializer):
'location',
'patronym',
'phone',
'score',
'skype',
'username',
'website',
@ -74,6 +76,9 @@ class UserSerializer(ModelSerializer):
def get_fio(self, obj):
return obj.get_full_name()
def get_score(self, obj):
return obj.get_score()
# def create(self, validated_data):
# return User.objects.create(**validated_data)

@ -1,7 +1,6 @@
import math
from django import template
register = template.Library()
@ -28,10 +27,23 @@ def has_group(user, group_name):
groups = user.groups.all().values_list('name', flat=True)
return True if group_name in groups else False
@register.inclusion_tag('templatetags/user_new_count.html', takes_context=True)
def count_new_message(context, user):
from chat.models import Message
new_count = Message.objects.filter(is_delete=False, is_new=True, recipent=user).count()
from chat.models import Message, NewMessage
new_count = NewMessage.objects.filter(user=user).count()
return {
'new_count': new_count,
}
@register.inclusion_tag('templatetags/user_new_count_orders.html', takes_context=True)
def count_new_message_orders(context, user):
from chat.models import NewMessage
new_count = NewMessage.objects.filter(user=user, message__order__in=user.orders.all(), message__team__isnull=True).count()
if user.team:
new_count_team = NewMessage.objects.filter(user=user, message__order__in=user.team.orders.all(), message__team__isnull=True).count()
new_count +=new_count_team
return {
'new_count': new_count,
}

@ -13,6 +13,7 @@ from django.views.generic.base import View
import logging
from users.models import User
from projects.models import Stage
from .forms import WithDrawForm, TmpCheckOrderForm, TmpPaymentAvisoForm, PayFromScoreForm
from .models import InvoiceHistory, WithDraw, Transaction, PayFromScore
@ -23,13 +24,28 @@ class PayFromScore(CreateView):
def form_valid(self, form):
if self.request.is_ajax():
self.object = form.save(commit=False)
self.object.customer = self.request.user
self.object.save()
data = {
'pk': self.object.pk,
'status': 'ok',
}
if self.request.user.get_score() >= form.cleaned_data.get('sum'):
stages_pk = [st for st in form.cleaned_data.get('stages_id').split(';') if st]
stages = Stage.objects.filter(pk__in=stages_pk)
st_names = ','.join([st.order.project.name for st in stages]).rstrip(',')
stage = stages.first()
order = stage.order
self.object = form.save(commit=False)
self.object.customer = self.request.user
self.object.save()
data = {
'pk': self.object.pk,
'status': 'ok',
'order': order.pk,
'sender': self.request.user.pk,
'recipent': order.get_contractor_owner(),
'stages': st_names,
}
else:
data = {
'status': 'error',
'message_error': 'У вас недостаточно средств',
}
return JsonResponse(data)
return super().form_valid(form)

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-12 16:12
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('work_sell', '0012_merge'),
]
operations = [
migrations.AlterField(
model_name='worksell',
name='term_type',
field=models.CharField(blank=True, choices=[('day', 'день'), ('hour', 'час'), ('month', 'месяц'), ('project', 'проект')], default='hour', max_length=20, null=True),
),
]
Loading…
Cancel
Save