remotes/origin/PR-39
ArturBaybulatov 9 years ago
commit 6a010ba0ce
  1. 51
      assets/css/extra.css
  2. 100
      assets/css/main.css
  3. 62
      assets/js/chat.js
  4. 9
      assets/js/chat_contractor.js
  5. 54
      assets/js/chat_customer.js
  6. 14
      chat/chat.py
  7. 2
      chat/serializers.py
  8. 14
      chat/templates/chat_contractor.html
  9. 12
      chat/templates/chat_customer.html
  10. 13
      chat/templates/reverse_stage_modal.html
  11. 27
      chat/views.py
  12. 20
      projects/migrations/0037_auto_20160919_1126.py
  13. 2
      projects/serializers.py
  14. 6
      projects/templates/project_detail.html
  15. 20
      ratings/migrations/0002_historyrating_type.py
  16. 10
      ratings/models.py
  17. 8
      users/models.py
  18. 2
      users/templates/templatetags/user_new_count_orders.html
  19. 8
      users/templatetags/user_tags.py
  20. 40
      work_sell/templates/worksell_edit.html

@ -189,3 +189,54 @@
font-style: italic; font-style: italic;
} }
.trashedOrderBlock {
width: 100%;
float: left;
margin-bottom: -1px;
padding: 15px;
background-color: #F7F7F7;
border-top: 1px solid #72767C;
border-bottom: 1px solid #72767C;
position: relative;
cursor: pointer;
-webkit-transition: all 0.3s ease-out;
-moz-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
}
.trashedOrderBlock:hover {
background-color: white;
border-top: 1px solid black;
border-bottom: 1px solid black;
-webkit-transform: scale(1.03);
-moz- transform: scale(1.03);
transform: scale(1.03);
box-shadow: 0 0 10px rgba(0,0,0,0.7);
z-index: 999;
}
.count-tab{
margin-left: 10px;
width: 35px;
height: 35px;
border-radius: 100%;
line-height: 35px;
text-align: center;
font-size: 14px;
font-family: 'Arial-MT-Regular', sans-serif;
position: absolute;
top: 14px;
cursor: pointer;
-webkit-transition: all 0.3s ease-out;
-moz-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
background-color: #ebebeb;
}
li a:active .count-tab, li a:hover .count-tab{
background-color: #FF0027;
color: white;
}

@ -827,9 +827,8 @@ footer:after {
box-shadow: 0 0 10px rgba(0,0,0,0.7); box-shadow: 0 0 10px rgba(0,0,0,0.7);
} }
.projectPro:hover .titlePro { .titlePro a:hover {
color: #fb2c2d; text-decoration: underline !important;
text-decoration: underline;
} }
.projectPro:hover .leftPro:before { .projectPro:hover .leftPro:before {
@ -2279,14 +2278,14 @@ input[type="checkbox"]:checked + span {
height: 22px; height: 22px;
background: url('../img/listExecutor.png') no-repeat left; background: url('../img/listExecutor.png') no-repeat left;
background-size: cover; background-size: cover;
background-position: 0 -18px; background-position: 0 -19px;
} }
.listExecutor li:last-child a:before { .listExecutor li:last-child a:before {
height: 19px; height: 19px;
background: url('../img/listExecutor.png') no-repeat left; background: url('../img/listExecutor.png') no-repeat left;
background-size: cover; background-size: cover;
background-position: 0 -47px; background-position: 0 -48px;
} }
.doneBlock { .doneBlock {
@ -2777,14 +2776,16 @@ input[type="checkbox"]:checked + span {
cursor: move; cursor: move;
} }
.compTable tr:hover:not(:first-child) { .compTable tr:hover {
z-index: 999; z-index: 999;
display: flex; display: table-row;
position: relative; position: relative;
-webkit-transform: scale(1.04); -webkit-transform: scale(1.02);
-moz-transform: scale(1.04); -moz-transform: scale(1.02);
transform: scale(1.04); transform: scale(1.02);
box-shadow: 0 0 10px rgba(0,0,0,0.8); /*box-shadow: 0 0 10px rgba(0,0,0,0.8);*/
outline: 1px solid #DAD9D9;
cursor: move;
} }
.compTable tr:hover td:first-child { .compTable tr:hover td:first-child {
@ -2804,10 +2805,15 @@ input[type="checkbox"]:checked + span {
border-bottom: 1px solid #DAD9D9 !important; border-bottom: 1px solid #DAD9D9 !important;
} }
.compTable tr th, .compTable tr td { /*.compTable tr th, .compTable tr td {
display: block; display: block
float: left; float: left;
text-align: center; text-align: center;
}*/
.compTable tr th, .compTable tr td {
display: table-cell;
vertical-align: middle;
text-align: center;
} }
.compTable tr th:first-child, .compTable tr th:first-child,
@ -2909,7 +2915,7 @@ input[type="checkbox"]:checked + span {
.compTable tr td:nth-child(6) ul { .compTable tr td:nth-child(6) ul {
float: left; float: left;
margin: 29px 0 0 72px; margin: 0px 0 0 72px;
} }
.compTable tr td:nth-child(6) ul li { .compTable tr td:nth-child(6) ul li {
@ -2974,7 +2980,6 @@ input[type="checkbox"]:checked + span {
font-weight: bold; font-weight: bold;
font-family: Arial, Verdana, Helvetica, sans-serif; font-family: Arial, Verdana, Helvetica, sans-serif;
position: relative; position: relative;
margin-bottom: 20px;
position: relative; position: relative;
width: 100%; width: 100%;
float: left; float: left;
@ -3711,7 +3716,7 @@ input[type="checkbox"]:checked + span {
height: 11px; height: 11px;
background: url('../img/delDoc.png') no-repeat center; background: url('../img/delDoc.png') no-repeat center;
background-size: cover; background-size: cover;
right: -40px; right: -20px !important;
top: 2px; top: 2px;
cursor: pointer; cursor: pointer;
} }
@ -4868,6 +4873,7 @@ input[type="checkbox"]:checked + span {
.inset-mb { .inset-mb {
display: table; display: table;
float: left; float: left;
margin-left: 15px;
} }
.inset-mb:first-child { .inset-mb:first-child {
@ -5059,7 +5065,7 @@ input[type="radio"]:checked + span {
.list-summ li:nth-child(3):before { .list-summ li:nth-child(3):before {
width: 22px; width: 22px;
height: 22px; height: 22px;
background: url('../img/chat.png') no-repeat center; background: url('../img/skype.png') no-repeat center;
background-size: cover; background-size: cover;
left: -42px; left: -42px;
top: 0; top: 0;
@ -5998,7 +6004,7 @@ a.linkS2[data-target="#withdraw-money"]{
} }
input[type="radio"]{ input[type="radio"]{
opacity: 1; opacity: 0;
} }
.wr-inset-pluss{ .wr-inset-pluss{
@ -6020,8 +6026,6 @@ input[type="radio"]{
} }
.welcomeMain{ .welcomeMain{
line-height: 48px; line-height: 48px;
font-family: 'pfdintextcomppro-regular', sans-serif;
font-size: 43.5px;
} }
.menuUser > div{ .menuUser > div{
padding: 10px 0; padding: 10px 0;
@ -6048,4 +6052,60 @@ input[type="radio"]{
-moz-transform: scale(1.04); -moz-transform: scale(1.04);
transform: scale(1.04); transform: scale(1.04);
} }
.new-rass2 .btn-submit-link{
display: table;
margin: 15px 0px 15px -15px !important;
}
button[data-id="stagesSelect"], button[data-id="stagesSelect"]:hover{
outline: 1px solid #ccc !important;
margin-top: 13px;
}
.polsF1 .linkS122, .polsF1 .linkS122:hover{
font-family: 'pfdintextcomppro-regular', sans-serif;
letter-spacing: 2px;
text-transform: uppercase;
border: none;
border-radius: 40px;
display: inline-block;
color: #fff;
padding: 12px 30px;
font-size: 15px;
margin-bottom: 20px;
background-color: #FE0029 !important;
width: 300px;
margin-bottom: 0;
}
#paymentfromSite, #paymentfromSite:hover{
font-family: 'pfdintextcomppro-regular', sans-serif;
letter-spacing: 2px;
text-transform: uppercase;
border: 1px solid #BEBEBE;
border-radius: 40px;
display: inline-block;
color: #373737;
padding: 12px 30px;
font-size: 15px;
margin-top: 20px;
margin-bottom: 20px;
background: transparent;
width: 300px;
}
li.officeList.icon_tml > a > p{
display: inline-block;
padding: 5px 7px 3px 7px;
background: #ff0000;
border-radius: 35px;
position: absolute;
right: -34px;
top: -4px;
}
.comm44 > div{
padding: 15px;
}
.logo + .badge{
padding: 7px;
margin-top: 5px;
border-radius: 15px;
background-color: #00BB7B;
}
/*end_new*/ /*end_new*/

@ -64,7 +64,7 @@ var SocketHandler = function () {
} else if (message.answer_type == 'approve_stages') { } else if (message.answer_type == 'approve_stages') {
var resOrderId = message.order_id; var resOrderId = message.order_id;
$.jGrowl(message.msg, { $.jGrowl(message.msg, {
life: 4000 life: 15000
}); });
setTimeout(function () { setTimeout(function () {
$("#orderBlock" + resOrderId).trigger('click'); $("#orderBlock" + resOrderId).trigger('click');
@ -185,51 +185,6 @@ function dialog (message, yesCallback, notCallback) {
} }
$(".messageBlock").on('click','.trashedOrderBlock',function(){
$("#chat-order-add").css("display", "none");
$('.order-block, .trashedOrderBlock').each(function () {
$(this).removeClass('orAct');
});
$(this).addClass('orAct');
var inbox = document.getElementById('message-chat-order-space');
var docList = document.getElementById('documentOrderSpace');
inbox.innerHTML = '';
docList.innerHTML = '';
var orderId = $(this).attr('data-id');
location.hash = '#order' + orderId;
$.ajax({
url: '/api/message',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId, 'team__isnull': 'true'},
dataType: 'json',
success: function (json) {
$.each(json.results, function (i, v) {
var senderName = 'Вы';
var className = 'youChat';
if (v.sender.id !== userId) {
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>';
});
var height = inbox.scrollHeight;
inbox.scrollTop = height;
}
});
$("#order-stages").html("");
$("#completeWork").hide();
$("#add-form-order-note").hide();
});
// Информация о заказе // Информация о заказе
$(".messageBlock").on('click','.full-order-info', function (e) { $(".messageBlock").on('click','.full-order-info', function (e) {
e.preventDefault(); e.preventDefault();
@ -608,15 +563,14 @@ function dialog (message, yesCallback, notCallback) {
var recipentId = $("#chat-order-add #recipentId").val(); var recipentId = $("#chat-order-add #recipentId").val();
var senderId = $("#chat-order-add #senderId").val(); var senderId = $("#chat-order-add #senderId").val();
var orderId = $("#chat-order-add #orderId").val(); var orderId = $("#chat-order-add #orderId").val();
var sendLinks = $("#document-send-order a");
if (chatMessage) { if (chatMessage || sendLinks.length > 0) {
var sendLinks = $("#document-send-order a");
var sendLinkIds = ""; var sendLinkIds = "";
var documentLinks = ""; var documentLinks = "";
var documentAttachFiles = ""; var documentAttachFiles = "";
$.each(sendLinks, function (i, v) { $.each(sendLinks, function (i, v) {
sendLinkIds += $(this).attr('data-id') + ';'; sendLinkIds += $(this).attr('data-id') + ';';
documentLinks += 'Входящий файл: <br> <a href="'+ $(this).attr('href') + '">'+ $(this).text() +'</a><br>'; documentLinks += 'Приложенный файл. скачать: <br> <a href="'+ $(this).attr('href') + '">'+ $(this).text() +'</a><br>';
documentAttachFiles += '<li style="word-break: break-all;">' + documentAttachFiles += '<li style="word-break: break-all;">' +
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' + '<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' +
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>'; '<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>';
@ -650,16 +604,18 @@ function dialog (message, yesCallback, notCallback) {
var chatMessage = $("#chat").val(); var chatMessage = $("#chat").val();
var recipentId = $("#recipentContactId").val(); var recipentId = $("#recipentContactId").val();
var senderId = $("#senderContactId").val(); var senderId = $("#senderContactId").val();
if (chatMessage) { var sendLinks = $("#document-send-contact a");
if (chatMessage || sendLinks.length > 0) {
$("#contact-chat-form .errorEmptyMessage").hide(); $("#contact-chat-form .errorEmptyMessage").hide();
var sendLinks = $("#document-send-contact a");
var sendLinkIds = ""; var sendLinkIds = "";
var documentLinks = ""; var documentLinks = "";
var documentAttachFiles = ""; var documentAttachFiles = "";
$.each(sendLinks, function (i, v) { $.each(sendLinks, function (i, v) {
sendLinkIds += $(this).attr('data-id') + ';'; sendLinkIds += $(this).attr('data-id') + ';';
documentLinks += 'Входящий файл: <br> <a href="'+ $(this).attr('href') + '">'+ $(this).text() +'</a><br>'; documentLinks += 'Приложенный файл. скачать: <br> <a href="'+ $(this).attr('href') + '">'+ $(this).text() +'</a><br>';
documentAttachFiles += '<li style="word-break: break-all;">' + documentAttachFiles += '<li style="word-break: break-all;">' +
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' + '<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' +
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>'; '<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>';

@ -588,15 +588,14 @@ $(function () {
var orderId = $("#team-chat-form #orderTeamId").val(); var orderId = $("#team-chat-form #orderTeamId").val();
var documentSendIds = $("#documentSendIds").val(); var documentSendIds = $("#documentSendIds").val();
var teamIds = $("#team-chat-form #teamIds").val(); var teamIds = $("#team-chat-form #teamIds").val();
var sendLinks = $("#document-send a");
if (chatMessage) { if (chatMessage || sendLinks.length > 0) {
var sendLinks = $("#document-send a");
var sendLinkIds = ""; var sendLinkIds = "";
var documentLinks = ""; var documentLinks = "";
var documentAttachFiles = ""; var documentAttachFiles = "";
$.each(sendLinks, function (i, v) { $.each(sendLinks, function (i, v) {
sendLinkIds += $(this).attr('data-id') + ';'; sendLinkIds += $(this).attr('data-id') + ';';
documentLinks += 'Входящий файл: <br> <a href="' + $(this).attr('href') + '">' + $(this).text() + '</a><br>'; documentLinks += 'Приложенный файл. скачать: <br> <a href="' + $(this).attr('href') + '">' + $(this).text() + '</a><br>';
documentAttachFiles += '<li style="word-break: break-all;">' + documentAttachFiles += '<li style="word-break: break-all;">' +
'<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' + '<a class="file-link" href="' + $(this).attr('href') + '">' + $(this).text() + '</a>' +
'<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>'; '<div class="remove-document" data-id="' + $(this).attr('data-id') + '" style="right:-10px;"></div></li>';
@ -622,6 +621,8 @@ $(function () {
$("#team-chat-form #chatText").val(""); $("#team-chat-form #chatText").val("");
$("#document-send").html(""); $("#document-send").html("");
$("#documentSendIds").val(""); $("#documentSendIds").val("");
} else {
$("#team-chat-form .errorEmptyMessage").show();
} }
}); });

@ -137,7 +137,7 @@ $(function () {
'<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>Название</label><input class="form-control" type="text" name="name" value="' + v.name + '"><p class="error error-name"></p>' + '<label>Название</label><input class="form-control" type="text" name="name" value="' + v.name + '"><p class="error error-name"></p>' +
'<label>Цена</label><input class="form-control" type="text" name="cost" value="' + v.cost + '" ><p class="error error-cost"></p>' + '<label>Цена</label><input class="form-control" type="text" name="cost" value="' + v.cost + '" ><p class="error error-cost"></p>' +
'<label>Позиция</label><input class="form-control" name="pos" type="text" value="' + v.pos + '" ><p class="error error-pos"></p>' + '<input class="form-control" name="pos" type="hidden" value="' + v.pos + '" ><p class="error error-pos"></p>' +
'<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">' + '<input class="form-control" type="hidden" name="status" value="send_approve">' +
'<label>Срок</label><input class="term-picker form-control datepicker" type="text" name="term" value="' + v.term + '" ><p class="error error-term"></p>' + '<label>Срок</label><input class="term-picker form-control datepicker" type="text" name="term" value="' + v.term + '" ><p class="error error-term"></p>' +
@ -303,6 +303,7 @@ $(function () {
$(".new-stages-form").each(function (i, v) { $(".new-stages-form").each(function (i, v) {
var _this = $(this); var _this = $(this);
console.log($(this).serialize());
$.ajax({ $.ajax({
url: '/api/stages/', url: '/api/stages/',
type: 'POST', type: 'POST',
@ -332,7 +333,7 @@ $(function () {
$(".update-stages-form").each(function (i, v) { $(".update-stages-form").each(function (i, v) {
var _this = $(this); var _this = $(this);
var currentStageId = parseInt($(this).attr('data-stage-id')); var currentStageId = parseInt($(this).attr('data-stage-id'));
console.log($(this).serialize());
$.ajax({ $.ajax({
url: '/api/stages/' + currentStageId + '/', url: '/api/stages/' + currentStageId + '/',
type: 'PUT', type: 'PUT',
@ -366,6 +367,7 @@ $(function () {
"msg": "Этапы для заказа " + currentOrderId + " изменены", "msg": "Этапы для заказа " + currentOrderId + " изменены",
} }
}); });
$.jGrowl("Этапы для заказа изменены и отправлены исполнителю", { life: 15000});
}); });
@ -390,7 +392,7 @@ $(function () {
'<input class="form-control" type="hidden" name="status" value="send_approve">' + '<input class="form-control" type="hidden" name="status" value="send_approve">' +
'<label>Срок</label><input class="term-picker form-control datepicker" name="term" type="text"><p class="error error-term"></p>' + '<label>Срок</label><input class="term-picker form-control datepicker" name="term" type="text"><p class="error error-term"></p>' +
'<label>Результат</label><input class="form-control" name="result" type="text"><p class="error error-result"></p>' + '<label>Результат</label><input class="form-control" name="result" type="text"><p class="error error-result"></p>' +
'<input class="form-control" name="pos" value="' + pos + '" type="text"></form></div>'; '<input class="form-control" name="pos" value="' + pos + '" type="hidden"></form></div>';
lastFormStage.after(addFormTemplate); lastFormStage.after(addFormTemplate);
} }
@ -408,7 +410,7 @@ $(function () {
} }
}); });
// Нажимаем на кнопку архивные сообщения
$("#trashed-button").on('click',function(e){ $("#trashed-button").on('click',function(e){
e.preventDefault(); e.preventDefault();
var state = $(this).attr('data-show'); var state = $(this).attr('data-show');
@ -452,6 +454,50 @@ $(function () {
}); });
// Нажимаем на заказ в архмвных заказах
$(".messageBlock").on('click','.trashedOrderBlock',function(){
$("#chat-order-add").css("display", "none");
$('.order-block, .trashedOrderBlock').each(function () {
$(this).removeClass('orAct');
});
$(this).addClass('orAct');
var inbox = document.getElementById('message-chat-order-space');
var docList = document.getElementById('documentOrderSpace');
inbox.innerHTML = '';
docList.innerHTML = '';
var orderId = $(this).attr('data-id');
location.hash = '#order' + orderId;
$.ajax({
url: '/api/message',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId, 'team__isnull': 'true'},
dataType: 'json',
success: function (json) {
$.each(json.results, function (i, v) {
var senderName = 'Вы';
var className = 'youChat';
if (v.sender.id !== userId) {
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>';
});
var height = inbox.scrollHeight;
inbox.scrollTop = height;
}
});
$("#order-stages").html("");
$("#completeWork").hide();
$("#add-form-order-note").hide();
$("#reserveSpace").hide();
});
// Для заказов все вытащить // Для заказов все вытащить
$('.order-block').on('click', function () { $('.order-block').on('click', function () {

@ -24,12 +24,13 @@ class ChatHandler(websocket.WebSocketHandler):
waiters = set() waiters = set()
def open(self, *args, **kwargs): def open(self, *args, **kwargs):
self.user_id = kwargs.get('user_id',1) self.user_id = kwargs.get('user_id', 1)
self.waiters.add((self.user_id, self)) self.waiters.add((self.user_id, self))
# @gen.coroutine # @gen.coroutine
def on_message(self, message): def on_message(self, message):
parsed = escape.json_decode(message) parsed = escape.json_decode(message)
if 'dummy' in parsed: if 'dummy' in parsed:
return return
@ -50,9 +51,10 @@ class ChatHandler(websocket.WebSocketHandler):
# order_id = data['data'].get('order_id') # order_id = data['data'].get('order_id')
# message = data['data'].get('msg', 'Этапы обновлены') # message = data['data'].get('msg', 'Этапы обновлены')
# answer_type = data['format_type'] # answer_type = data['format_type']
# waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id) # waiters = tuple(w for c, w in self.waiters if c == recipent_id)
# for waiter in waiters: # for waiter in waiters:
# waiter.write_message({'msg': message, 'order_id': order_id, 'answer_type': answer_type}) # print(waiter)
# # waiter.write_message({'msg': message, 'order_id': order_id, 'answer_type': answer_type})
@gen.coroutine @gen.coroutine
def add_message(self, message_data): def add_message(self, message_data):
@ -127,7 +129,11 @@ class ChatHandler(websocket.WebSocketHandler):
if docs_links: if docs_links:
message += '<br><br>' + docs_links; message += '<br><br>' + docs_links;
waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id) if message_type:
waiters = tuple(w for c, w in self.waiters if c == recipent_id)
else:
waiters = tuple(w for c, w in self.waiters if c == recipent_id or c == sender_id)
for waiter in waiters: for waiter in waiters:
waiter.write_message({'msg': message, waiter.write_message({'msg': message,
'msg_time': msg_time, 'msg_time': msg_time,

@ -63,7 +63,7 @@ class MessageSerializer(ModelSerializer):
out = obj.text out = obj.text
documents = obj.documents.all() documents = obj.documents.all()
if len(documents)>0: if len(documents)>0:
documents_str = '<br>'.join(['Входящий файл: <br><a target="_blank" href="/chat/download/' + doc.file.name + '">' + doc.file.name + '</a>' for doc in documents]) documents_str = '<br>'.join(['Приложенный файл. скачать: <br><a target="_blank" href="/chat/download/' + doc.file.name + '">' + doc.file.name + '</a>' for doc in documents])
out += '<br><br>' + documents_str out += '<br><br>' + documents_str
return out return out

@ -1,12 +1,13 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load staticfiles %} {% load staticfiles %}
{% load thumbnail %} {% load thumbnail %}
{% load user_tags %}
{% block content %} {% block content %}
{% include 'partials/header.html' %} {% include 'partials/header.html' %}
<div class="container mainScore"> <div class="container mainScore">
<div class="row"> <div class="row">
<div class="col-lg-12 allProjects"> <div class="col-lg-12 allProjects">
<h1>Чат {{ request.user }} {{ request.user.pk }}</h1> <h1>Чат</h1>
</div> </div>
<div class="btnReadyBlock disTab"> <div class="btnReadyBlock disTab">
@ -16,15 +17,15 @@
<ul class="nav nav-tabs nav-justified"> <ul class="nav nav-tabs nav-justified">
<li role="presentation"> <li role="presentation">
<a href="#tab1" data-toggle="tab">Личные</a> <a href="#tab1" data-toggle="tab">Личные<span class="count-tab">{{ contacts_users_count }}</span></a>
</li> </li>
<li role="presentation"> <li role="presentation">
<a href="#tab2" data-toggle="tab">Заказчики</a> <a href="#tab2" data-toggle="tab">Заказчики<span class="count-tab">{{ orders_ms_count }}</span></a>
</li> </li>
<li role="presentation"> <li role="presentation">
<a href="#tab3" data-toggle="tab">Исполнители,Группы</a> <a href="#tab3" data-toggle="tab">Исполнители,Группы<span class="count-tab">{{ teams_ms_count }}</span></a>
</li> </li>
</ul> </ul>
@ -56,8 +57,8 @@
</p> </p>
<a href="#" data-id="{{ contact.id }}" class="conMess">Контакты</a> <a href="#" data-id="{{ contact.id }}" class="conMess">Контакты</a>
<span class="contact-count-{{ contact.pk|add:request.user.pk }}">
<span class="contact-count-{{ contact.pk|add:request.user.pk }}">0</span> {% get_new_count_for_contact contact request.user %}</span>
<a href="#" class="deleteMess" data-recipent-id="{{ contact.pk }}"> <a href="#" class="deleteMess" data-recipent-id="{{ contact.pk }}">
Удалить контакт Удалить контакт
</a> </a>
@ -320,6 +321,7 @@
<input type="hidden" name="team_ids" id="teamIds"> <input type="hidden" name="team_ids" id="teamIds">
<input type="hidden" name="document-send" id="documentSendIds"> <input type="hidden" name="document-send" id="documentSendIds">
<textarea id="chatText" class="chat-textarea box-sizing"></textarea> <textarea id="chatText" class="chat-textarea box-sizing"></textarea>
<p class="errorEmptyMessage" style="color: red;display:none;">Пустое сообщение нельзя отправить</p>
<div class="bunChat"> <div class="bunChat">
<div class="setChat box-sizing upload"> <div class="setChat box-sizing upload">
<input type="file" name="file" id="upload-document-team"> <input type="file" name="file" id="upload-document-team">

@ -1,12 +1,13 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load staticfiles %} {% load staticfiles %}
{% load thumbnail %} {% load thumbnail %}
{% load user_tags %}
{% block content %} {% block content %}
{% include 'partials/header.html' %} {% include 'partials/header.html' %}
<div class="container mainScore"> <div class="container mainScore">
<div class="row"> <div class="row">
<div class="col-lg-12 allProjects"> <div class="col-lg-12 allProjects">
<h1>Чат {{ request.user.get_score }}</h1> <h1>Чат</h1>
</div> </div>
<div class="btnReadyBlock disTab"> <div class="btnReadyBlock disTab">
<div class="triangle1"></div> <div class="triangle1"></div>
@ -14,10 +15,11 @@
<div class="profileTabs2"> <div class="profileTabs2">
<ul class="nav nav-tabs nav-justified"> <ul class="nav nav-tabs nav-justified">
<li role="presentation"> <li role="presentation">
<a href="#tab1" data-toggle="tab">Личные</a> <a href="#tab1" data-toggle="tab">Личные<span class="count-tab">{{ contacts_users_count }}</span></a>
</li> </li>
<li role="presentation"> <li role="presentation">
<a href="#tab2" data-toggle="tab">Исполнители</a> <a href="#tab2" data-toggle="tab">Исполнители<span class="count-tab">{{ orders_ms_count }}</span>
</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -52,7 +54,9 @@
<a href="#" data-id="{{ contact.id }}" class="conMess">Контакты</a> <a href="#" data-id="{{ contact.id }}" class="conMess">Контакты</a>
<span class="contact-count-{{ contact.pk|add:request.user.pk }}">0</span> <span class="contact-count-{{ contact.pk|add:request.user.pk }}">
{% get_new_count_for_contact contact request.user %}
</span>
<a href="#" class="deleteMess" data-recipent-id="{{ contact.pk }}"> <a href="#" class="deleteMess" data-recipent-id="{{ contact.pk }}">
Удалить контакт Удалить контакт
</a> </a>

@ -37,7 +37,7 @@
</div> </div>
<div class="col-lg-6"> <div class="col-lg-6">
<select id="stagesSelect"> <select class="selectpicker -project-work-type-select-field" id="stagesSelect">
</select> </select>
</div> </div>
</div> </div>
@ -45,8 +45,8 @@
<div class="searchF1 polsF1 polsFF radio-afe" style="padding-top: 20px;padding-left: 50px;"> <div class="searchF1 polsF1 polsFF radio-afe" style="padding-top: 20px;padding-left: 50px;">
<p class="titleStepss">Резервирование средств</p> <p class="titleStepss">Резервирование средств</p>
<form id="stages-pay-form" action="{{ YANDEX_MONEY.url }}" method="POST">{% csrf_token %} <form id="stages-pay-form" action="{{ YANDEX_MONEY.url }}" method="POST">{% csrf_token %}
<div class="modal-body">
<div style="height: 150px;"> <div>
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
<input type="hidden" name="sum" id="stageSumPay"> <input type="hidden" name="sum" id="stageSumPay">
<input type='hidden' name='shopId' value='{{ YANDEX_MONEY.shop_id }}'> <input type='hidden' name='shopId' value='{{ YANDEX_MONEY.shop_id }}'>
@ -57,13 +57,8 @@
<input type='hidden' name='stagesId' id='stagesIds' value=''> <input type='hidden' name='stagesId' id='stagesIds' value=''>
<input type='hidden' name='ordermodalId' id='ordermodalId'> <input type='hidden' name='ordermodalId' id='ordermodalId'>
</div> </div>
<button type="submit" class="btn btn-primary btn-lg btn-block">Пополнить</button> <button type="submit" class="btn btn-primary btn-lg btn-block linkS122">Пополнить</button>
</div> </div>
</div>
<div class="modal-footer">
</div>
</form> </form>

@ -9,7 +9,7 @@ from wsgiref.util import FileWrapper
from .response import JSONResponse, response_mimetype from .response import JSONResponse, response_mimetype
from .utils import serialize from .utils import serialize
from .models import Message, Documents from .models import Message, Documents, NewMessage
from projects.models import Order, Project from projects.models import Order, Project
from wallets.models import Transaction from wallets.models import Transaction
from users.models import User, Team from users.models import User, Team
@ -53,14 +53,25 @@ class ChatUserView(LoginRequiredMixin, View):
users_ids.append(b) users_ids.append(b)
if user_id: if user_id:
users_ids.append(int(user_id)) users_ids.append(int(user_id))
contacts_users = User.objects.filter(pk__in=users_ids) contacts_users = User.objects.filter(pk__in=users_ids)
chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk)) chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk))
orders = request.user.customer_projects.select_related('order').filter(state='active').exclude(order__contractor__isnull=True, order__team__isnull=True) orders = request.user.customer_projects.select_related('order').filter(state='active').exclude(order__contractor__isnull=True, order__team__isnull=True)
order_ids = [order.order.pk for order in orders]
transaction = Transaction.objects.get_or_create(customer=request.user, type='reservation', complete=False) transaction = Transaction.objects.get_or_create(customer=request.user, type='reservation', complete=False)
contacts_users_count = request.user.new_messages.filter(message__sender__in=users_ids,
message__order__isnull=True,
message__team__isnull=True
).count()
orders_ms_count = request.user.new_messages.filter(message__order__in=order_ids, message__team__isnull=True).count()
self.template_name = 'chat_customer.html' self.template_name = 'chat_customer.html'
return render(request, self.template_name, {'contacts_users': contacts_users, return render(request, self.template_name, {'contacts_users': contacts_users,
'chat_messages': chat_messages, 'chat_messages': chat_messages,
'contacts_users_count': contacts_users_count,
'orders_ms_count': orders_ms_count,
'orders': orders, 'orders': orders,
'transaction': transaction[0], 'transaction': transaction[0],
'YANDEX_MONEY': settings.YANDEX_MONEY, 'YANDEX_MONEY': settings.YANDEX_MONEY,
@ -88,17 +99,31 @@ class ChatUserView(LoginRequiredMixin, View):
users_ids.append(b) users_ids.append(b)
if user_id: if user_id:
users_ids.append(int(user_id)) users_ids.append(int(user_id))
contacts_users = User.objects.filter(pk__in=users_ids) contacts_users = User.objects.filter(pk__in=users_ids)
contacts_users_count = request.user.new_messages.filter(message__sender__in=users_ids,
message__order__isnull=True,
message__team__isnull=True
).count()
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 = Team.objects.filter(Q(contractors__id=request.user.pk) | Q(owner=request.user)) your_teams = Team.objects.filter(Q(contractors__id=request.user.pk) | Q(owner=request.user))
orders_ms_count = request.user.new_messages.filter(message__order__in=orders, message__team__isnull=True).count()
teams_ms_count = request.user.new_messages.filter(message__team__in=your_teams, message__order__isnull=True).count()
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,
'contacts_users_count': contacts_users_count,
'orders_ms_count': orders_ms_count,
'teams_ms_count': teams_ms_count,
'chat_messages': chat_messages, 'chat_messages': chat_messages,
'team_orders': team_orders, 'team_orders': team_orders,
'your_teams': your_teams, 'your_teams': your_teams,
}) })

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-19 08:26
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0036_auto_20160917_2135'),
]
operations = [
migrations.AlterField(
model_name='project',
name='work_type',
field=models.IntegerField(choices=[(1, 'Проектирование'), (2, 'Проверка документации'), (3, 'Устранение замечаний в проекте')], default=1),
),
]

@ -80,7 +80,7 @@ class StageSerializer(ModelSerializer):
term = serializers.DateField(format="%d.%m.%Y", input_formats=['%d.%m.%Y',]) term = serializers.DateField(format="%d.%m.%Y", input_formats=['%d.%m.%Y',])
def validate(self, data): def validate(self, data):
if hasattr(data, 'pos') and data['pos'] > 1: if 'pos' in data and data['pos'] > 1:
pos = data['pos'] -1 pos = data['pos'] -1
stage_last = Stage.objects.filter(order=data['order'], pos=pos) stage_last = Stage.objects.filter(order=data['order'], pos=pos)
if stage_last: if stage_last:

@ -936,13 +936,13 @@
{% endfor %} {% endfor %}
<div class="comm44 disTab"> <div class="comm44 disTab">
<div class="col-lg-10 col-lg-offset-1"> <div class="col-lg-10 col-lg-offset-1" style="padding:0;">
<form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:create-answer-message' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}"> <input type="hidden" name="next" value="{% url 'projects:detail' pk=project.pk %}">
<div><textarea name="text" class="fr_answer"></textarea></div> <div><textarea style="margin-left:0;" name="text" class="fr_answer"></textarea></div>
<div><button type="submit" class="fr_answer_sen">Отправить</button></div> <div><button style="margin-left:0;" type="submit" class="fr_answer_sen">Отправить</button></div>
</form> </form>
</div> </div>
</div> </div>

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-19 08:26
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ratings', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='historyrating',
name='type',
field=models.CharField(choices=[('OCCUPANCY_PROFILE', 'occupancy_profile'), ('SECURE_DEAL', 'secure_deal'), ('REVIEW', 'review'), ('MONEY_SPENT', 'money_spent'), ('PUBLICATION_PROJECT', 'publication_project'), ('VISIT_SITE', 'visit_site'), ('CHOICE_CONTRACTOR', 'choice_contractor')], default='review', max_length=50),
),
]

@ -5,11 +5,21 @@ from specializations.models import Specialization
class HistoryRating(models.Model): class HistoryRating(models.Model):
TYPES_HISTORY_RATING = (
('OCCUPANCY_PROFILE', 'occupancy_profile'),
('SECURE_DEAL', 'secure_deal'),
('REVIEW', 'review'),
('MONEY_SPENT', 'money_spent'),
('PUBLICATION_PROJECT', 'publication_project'),
('VISIT_SITE', 'visit_site'),
('CHOICE_CONTRACTOR', 'choice_contractor'),
)
user = models.ForeignKey(User, related_name='history_ratings', null=True, blank=True) user = models.ForeignKey(User, related_name='history_ratings', null=True, blank=True)
team = models.ForeignKey(Team, related_name='history_ratings', null=True, blank=True) team = models.ForeignKey(Team, related_name='history_ratings', null=True, blank=True)
rating = models.IntegerField(default=0) rating = models.IntegerField(default=0)
created = models.DateTimeField(default=timezone.now) created = models.DateTimeField(default=timezone.now)
description = models.TextField(blank=True) description = models.TextField(blank=True)
type = models.CharField(max_length=50, choices=TYPES_HISTORY_RATING, default='review')
def __str__(self): def __str__(self):
return '{0}'.format(self.rating) return '{0}'.format(self.rating)

@ -5,8 +5,6 @@ from django.db import models
from django.db.models import Sum from django.db.models import Sum
from django.utils import timezone, formats from django.utils import timezone, formats
from mptt.models import TreeForeignKey, TreeManyToManyField from mptt.models import TreeForeignKey, TreeManyToManyField
from pprint import pprint
import datetime
import pydash as _; _.map = _.map_; _.filter = _.filter_ import pydash as _; _.map = _.map_; _.filter = _.filter_
from archilance import util from archilance import util
@ -171,7 +169,8 @@ class User(AbstractBaseUser, PermissionsMixin):
return self.email return self.email
def get_full_name(self): def get_full_name(self):
return self.first_name + ' ' + self.last_name full_name = self.first_name + ' ' + self.last_name
return full_name or self.username
def get_profile_image(self): def get_profile_image(self):
return self.avatar return self.avatar
@ -215,9 +214,6 @@ class User(AbstractBaseUser, PermissionsMixin):
def has_team(self): def has_team(self):
return self.is_contractor() and bool(util.get_related_or_none(self, 'team')) return self.is_contractor() and bool(util.get_related_or_none(self, 'team'))
def is_owner_profile(self, user_id):
pass
def is_owner_team(self): def is_owner_team(self):
return Team.objects.filter(owner=self.pk).exists() return Team.objects.filter(owner=self.pk).exists()

@ -1 +1 @@
{{ new_count }} <p>{{ new_count }}</p>

@ -60,3 +60,11 @@ def count_new_message_orders(context, user):
def get_new_count_message(team_pk,user=None): def get_new_count_message(team_pk,user=None):
count = NewMessage.objects.filter(user=user, message__team=team_pk, message__order__isnull=True).count() count = NewMessage.objects.filter(user=user, message__team=team_pk, message__order__isnull=True).count()
return count return count
@register.simple_tag
def get_new_count_for_contact(contact, current_user):
count = current_user.new_messages.filter(message__sender=contact, message__order__isnull=True, message__team__isnull=True).count()
return count

@ -70,7 +70,9 @@
<input type="text" class="box-sizing" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}"> <input type="text" class="box-sizing" name="{{ form.budget.html_name }}" value="{{ form.budget.value }}">
</div> </div>
<div class="col-lg-4"> <div class="col-lg-4">
{{ form.currency}} <div class="polsF1" style="padding:0;">
{{ form.currency}}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -82,21 +84,27 @@
<input type="text" class="box-sizing" name="{{ form.term.html_name }}" value="{{ form.term.value }}"> <input type="text" class="box-sizing" name="{{ form.term.html_name }}" value="{{ form.term.value }}">
</div> </div>
<div class="col-lg-4"> <div class="col-lg-4">
{{ form.term_type }} <div class="polsF1" style="padding:0;">
{{ form.term_type }}
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="textAreaBlock2 text-nn box-sizing disTab"> <div class="textAreaBlock2 text-nn box-sizing disTab">
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="col-lg-6">
<p>Вид строительства <span style="color: red">{{ form.construction_type.errors.as_text }}</span></p> <div class="polsF1 disTab" style="padding:0;">
{{ form.construction_type }} <p>Вид строительства <span style="color: red">{{ form.construction_type.errors.as_text }}</span></p>
{{ form.construction_type }}
</div>
</div> </div>
<div class="polsF1 polsF2 disTab"> <div class="col-lg-6">
<p>Классификация здания <span style="color: red">{{ form.building_classification.errors.as_text }}</span></p> <div class="polsF1 disTab" style="padding:0;">
{{ form.building_classification }} <p>Классификация здания <span style="color: red">{{ form.building_classification.errors.as_text }}</span></p>
{{ form.building_classification }}
</div>
</div> </div>
<div class="textAreaBlock2 text-nn box-sizing disTab -live-image-upload-container"> <div class="textAreaBlock2 text-nn box-sizing disTab -live-image-upload-container">
@ -130,13 +138,13 @@
</script> </script>
<div class="-res"></div> <div class="-res"></div>
<div class="row">
<div class="col-xs-12"> <div class="col-xs-12">
<input type="file" name="image" multiple class="-live-image-upload-field" style="display: none"> <input type="file" name="image" multiple class="-live-image-upload-field" style="display: none">
<a href="#" onclick="$(this).closest('.-live-image-upload-container').find('.-live-image-upload-field').first().click(); return false" class="btn btn-default add_file_to_port" style="margin-top:20px;">
<a href="#" onclick="$(this).closest('.-live-image-upload-container').find('.-live-image-upload-field').first().click(); return false" class="btn btn-default add_file_to_port"> Выберите файлы
Выберите файлы </a>
</a> </div>
</div> </div>
</div> </div>
@ -144,7 +152,7 @@
</div> </div>
<div class="searchF1 polsF1 polsFF links-filter"> <div class="links-filter">
<input class="btn-submit-link" type="submit" value="Сохранить проект"> <input class="btn-submit-link" type="submit" value="Сохранить проект">
</div> </div>

Loading…
Cancel
Save