diff --git a/api/views.py b/api/views.py index 27d998f..7fa861a 100755 --- a/api/views.py +++ b/api/views.py @@ -91,6 +91,7 @@ class ProjectViewSet(ModelViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer filter_class = ProjectFilterSet + # permission_classes = (permissions.IsAuthenticatedOrReadOnly,) class NoteViewSet(ModelViewSet): diff --git a/assets/css/extra.css b/assets/css/extra.css index ff82042..c01a8ac 100644 --- a/assets/css/extra.css +++ b/assets/css/extra.css @@ -164,3 +164,28 @@ top: 1px; } + + +.deleteOrder:after { + content: ''; + position: absolute; + width: 13px; + height: 13px; + background: url('../img/btn3.png') no-repeat center; + background-size: cover; + left: -30px; + top: 2px; +} + + +.deleteOrder, .deleteOrder:link, .deleteOrder:visited { + color: #5a5a5a; + font-size: 14px; + font-family: Arial, Verdana, Helvetica, sans-serif; + text-decoration: underline; + position: relative; + float: left; + margin: 0 0 0 35px; + font-style: italic; +} + diff --git a/assets/css/main.css b/assets/css/main.css index 1302101..46f23b6 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -3416,6 +3416,19 @@ input[type="checkbox"]:checked + span { margin: 10px 0 20px 0; } +.textAreaBlock2 a, .textAreaBlock2 a:link, .textAreaBlock2 a:visited { + border: 1px solid #bebebe; + border-radius: 40px; + color: #373737; + display: inline-block; + font-family: "pfdintextcomppro-regular",sans-serif; + font-size: 15px; + letter-spacing: 2px; + margin-bottom: 20px; + padding: 12px 30px; + text-transform: uppercase; +} + .textAreaBlock2 a:not(.cke_button, .cke_combo_button, .cke_path_item), .textAreaBlock2 a:link:not(.cke_button, .cke_combo_button, .cke_path_item), .textAreaBlock2 a:visited:not(.cke_button, .cke_combo_button, .cke_path_item) { @@ -3692,7 +3705,7 @@ input[type="checkbox"]:checked + span { top: 0; } -.documentsChat ul li div { +.documentsChat ul li div , .remove-document{ position: absolute; width: 11px; height: 11px; diff --git a/assets/js/chat.js b/assets/js/chat.js index 5ee15de..b4f47b1 100644 --- a/assets/js/chat.js +++ b/assets/js/chat.js @@ -1,3 +1,34 @@ +window.confirm = function (message, callback, caption) { + caption = caption || '' + + $(document.createElement('div')).attr({ + title: caption, + 'class': 'dialog' + }).html(message).dialog({ + modal: true, + resizable: false, + height: "auto", + width: 400, + + buttons: { + "Отмена": function () { + $(this).dialog('close'); + return false; + }, + "OK": function () { + $(this).dialog('close'); + callback() + return true; + } + + }, + close: function () { + $(this).remove(); + }, + + }); +}; + var SocketHandler = function () { domain = domain.replace(':' + port, ''); var url = 'ws://' + domain + '/chat/' + userId + '/'; @@ -78,30 +109,47 @@ var socket = new SocketHandler(); var csrftoken = getCookie('csrftoken'); + +function test_dialog(message){ + var resStatus; + $("#dialog_delete .modal-title").html(message); + $("#dialog_delete").modal('show'); + $("#btnYes").click(function (e) { + $("#dialog_delete").modal('hide'); + resStatus = true; + }); + $("#btnNot").click(function (e) { + $("#dialog_delete").modal('hide'); + resStatus = false; + }); + return resStatus; +} + $(function () { - function dialog(message, yesCallback, notCallback) { +function dialog (message, yesCallback, notCallback) { $("#dialog_delete .modal-title").html(message); - var dialog = $("#dialog_delete").modal('show'); - $("#btnYes").click(function () { + $("#dialog_delete").modal('show'); + $("#btnYes").click(function (e) { + e.preventDefault(); yesCallback(); $("#dialog_delete").modal('hide'); }); - $("#btnNot").click(function () { + $("#btnNot").click(function (e) { + e.preventDefault(); notCallback(); $("#dialog_delete").modal('hide'); }); - } - +} 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){ + switch (activeTab) { case 'tab1': setTimeout(function () { - if(liveHash.indexOf("#user") == 0) { + if (liveHash.indexOf("#user") == 0) { var userHashId = liveHash.replace("#user", ""); $("#userBlock" + userHashId).trigger('click'); } else { @@ -112,7 +160,7 @@ $(function () { case 'tab2': setTimeout(function () { - if(liveHash.indexOf("#order") == 0) { + if (liveHash.indexOf("#order") == 0) { var ordHashId = liveHash.replace("#order", ""); $("#orderBlock" + ordHashId).trigger('click'); } else { @@ -123,18 +171,18 @@ $(function () { case 'tab3': setTimeout(function () { - if(liveHash.indexOf("#teamorder") == 0) { + if (liveHash.indexOf("#teamorder") == 0) { var teamHashId = liveHash.replace("#teamorder", ""); $("#teamOrderBlock" + teamHashId).trigger('click'); - } else if(liveHash.indexOf("#myteam") == 0){ + } 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){ + if (firstTeamOrder.length == 1) { firstTeamOrder.trigger('click'); - } else if(firstTeamBlock.length == 1){ + } else if (firstTeamBlock.length == 1) { firstTeamBlock.trigger('click'); } } @@ -146,7 +194,7 @@ $(function () { if (currentHash.indexOf("#order") == 0) { $("a[href='#tab2']").trigger('click'); - } else if(currentHash.indexOf("#user") == 0){ + } else if (currentHash.indexOf("#user") == 0) { $("a[href='#tab1']").trigger('click'); } else if (currentHash.indexOf("#teamorder") == 0 || currentHash.indexOf("#myteam") == 0) { $("a[href='#tab3']").trigger('click'); @@ -154,6 +202,33 @@ $(function () { $("a[href='#tab1']").trigger('click'); } + $("#trashed-button").on('click',function(e){ + e.preventDefault(); + var trashedOrderHtml = ""; + $.ajax({ + url: '/api/orders/', + type: 'GET', + dataType: 'json', + success: function(json){ + console.log(json.results); + $.each(json.results, function(i, v){ + var temp = '
' + + '

'+ v.project.name +'

' + + 'Исполнитель:

' + + '' + + 'Полное описание заказа
'; + + trashedOrderHtml += temp; + }); + $("#trashed-orders").html(trashedOrderHtml); + }, + error: function(e, jqxhr){ + console.log(e); + } + }) + }); + // Информация о заказе $(".full-order-info").click('on', function (e) { e.preventDefault(); @@ -251,7 +326,7 @@ $(function () { $("#reserve-stage-modal").modal('hide'); $("#orderBlock" + orderId).trigger('click'); - }else if(json.status == 'error'){ + } else if (json.status == 'error') { alert(json.message_error); } }, @@ -390,8 +465,8 @@ $(function () { var _this = $(this); dialog("Вы действительно хотите удалить сообщения этого пользователя?", - function(){ - $.ajax({ + function () { + $.ajax({ url: '/chat/messages_delete/', type: 'POST', beforeSend: function (xhr) { @@ -412,11 +487,48 @@ $(function () { console.log(e); } }); - }.bind(null, senderId, recipentId, _this), + }.bind(null, senderId, recipentId, _this), function () { }); + }); + + $('.deleteOrder').on('click', function (e) { + e.preventDefault(); + e.stopPropagation(); + var senderId = userId; + var projectId = $(this).attr('data-project-id'); + var _this = $(this); + + dialog("Вы действительно хотите удалить этот заказ?", + function () { + $.ajax({ + url: '/chat/project/trashed/', + type: 'POST', + beforeSend: function (xhr) { + xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) + }, + data: {'project_id': projectId}, + dataType: 'json', + success: function (json) { + if (json.status == 'ok') { + _this.parent().parent().remove(); + $("#message-chat-space").html(""); + } + + }, + error: function (e) { + console.log('error'); + console.log(e); + } + }); + }.bind(null, senderId, projectId), + function () { + + }); + + }); $('#add-note-contractor').on('click', function (e) { @@ -649,7 +761,7 @@ $(function () { dataType: 'json', done: function (e, data) { $.each(data.result.files, function (index, file) { - var htmlImg = '' + file.name + '
'; + var htmlImg = '' + file.name + '

'; var document_send = $(htmlImg).appendTo("#document-send-order"); }); }, diff --git a/assets/js/chat_contractor.js b/assets/js/chat_contractor.js index 00fb855..5e86dc0 100644 --- a/assets/js/chat_contractor.js +++ b/assets/js/chat_contractor.js @@ -1,4 +1,20 @@ $(function () { + + function dialog(message, yesCallback, notCallback) { + $("#dialog_delete .modal-title").html(message); + $("#dialog_delete").modal('show'); + $("#btnYes").click(function (e) { + e.preventDefault(); + yesCallback(); + $("#dialog_delete").modal('hide'); + }); + $("#btnNot").click(function (e) { + e.preventDefault(); + notCallback(); + $("#dialog_delete").modal('hide'); + }); + } + var form = document.getElementById('message_form'); var url = '/chat/create/'; @@ -52,74 +68,91 @@ $(function () { // Согласование этапов $("#order-stages").on('click', "#approve-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=in_process", - dataType: 'json', - success: function (json) { - console.log(json); - }, - error: function (e) { - console.log('error'); - console.log(e); + var orderId = $(this).attr('data-order-id'); + var senderId = $(this).attr('data-sender-id'); + var recipentId = $(this).attr('data-recipent-id'); + var caption = "Вы действительно хотите согласовать этапы?"; + + confirm(caption, function () { + $(".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=in_process", + data: "status=send_approve", + dataType: 'json', + done: function (json) { + console.log(json); + }, + fail: function (e) { + console.log('error'); + console.log(e); + } + }); + }); + + $('.btns-approve-stages').hide(); + + socket.send_stages_approve({ + "format_type": "approve_stages", + "data": { + "sender_id": senderId, + "recipent_id": recipentId, + "order_id": orderId, + "msg": "Исполнитель согласовал этапы для заказа " + orderId, } }); - }); - 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, - } - }); + }.bind(orderId, senderId, recipentId), caption); }); - // Согласование этапов + // Отказаться от этапов $("#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 senderId = $(this).attr('data-sender-id'); + var recipentId = $(this).attr('data-recipent-id'); var orderId = $(this).attr('data-order-id'); + var caption = "Вы действительно хотите отказаться от этапов?"; + confirm(caption,function() { + $(".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", + data: "status=send_approve", + dataType: 'json', + done: function (json) { + console.log(json); + + }, + fail: function (e) { + console.log('error'); + console.log(e); + } + }); - 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, - } - }); + }); + $('.btns-approve-stages').hide(); + + socket.send_stages_approve({ + "format_type": "approve_stages", + "data": { + "sender_id": senderId, + "recipent_id": recipentId, + "order_id": orderId, + "msg": "Исполнитель отказался от текущих этапов " + orderId, + } + }); + }.bind(),caption); }); @@ -137,14 +170,14 @@ $(function () { $(this).addClass('orAct'); var teamIds = ''; - $.each($(this).find('.team-chat-user'), function(i,v){ + $.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'); var orderId = $(this).attr('data-order-id'); - location.hash = '#teamorder' + orderId; + location.hash = '#teamorder' + orderId; $("#team-chat-form #teamId").val(teamId); $("#team-chat-form #recipentTeamId").val(""); $("#team-chat-form #orderTeamId").val(orderId); @@ -226,7 +259,7 @@ $(function () { $(this).addClass('orAct'); var teamIds = ''; - $.each($(this).find('.team-chat-user'), function(i,v){ + $.each($(this).find('.team-chat-user'), function (i, v) { teamIds += $(this).attr('data-id') + ";"; }); $("#team-chat-form #teamIds").val(teamIds); @@ -401,6 +434,7 @@ $(function () { var stagesInWork = []; var stagesResults = data.stages; var statusNotAgreed = false; + var statusSendApprove = false; var stagesCompleted = []; if (stagesResults.length > 0) { $.each(stagesResults, function (i, v) { @@ -460,10 +494,10 @@ $(function () { if (statusNotAgreed) { - htmlInbox += '
' + - 'согласовать' + - 'отказаться' + '
'; } @@ -487,7 +521,7 @@ $(function () { '

Срок сдачи ' + stage.term + ' ' + stage.cost + '

'; if (!stage.close_contractor) { - stageWork += '
Завершить этап
'; } else { stageWork += '

Этап ожидает завершения статуса от заказчика

'; @@ -563,7 +597,7 @@ $(function () { var documentAttachFiles = ""; $.each(sendLinks, function (i, v) { sendLinkIds += $(this).attr('data-id') + ';'; - documentLinks += 'Входящий файл:
'+ $(this).text() +'
'; + documentLinks += 'Входящий файл:
' + $(this).text() + '
'; documentAttachFiles += '
  • ' + '' + $(this).text() + '' + '
  • '; diff --git a/assets/js/chat_customer.js b/assets/js/chat_customer.js new file mode 100644 index 0000000..2132ff1 --- /dev/null +++ b/assets/js/chat_customer.js @@ -0,0 +1,523 @@ +$(function () { + + var form = document.getElementById('message_form'); + + $('body').on('focus', ".term-picker", function () { + $(this).datepicker({ + minDate: 0, + }); + }) + + $("#reserve-button").on("click", function (e) { + e.preventDefault(); + $("#reserve-stage-modal").modal('show'); + var orderId = $(this).attr('data-order-id'); + $.ajax({ + url: '/api/stages/', + type: 'GET', + data: {csrfmiddlewaretoken: csrftoken, 'order': orderId}, + dataType: 'json', + success: function (json) { + var outputValues = ''; + var totalSum = 0; + var stagesIds = ''; + var notPaidCount = 0; + $.each(json.results, function (i, v) { + if ((v.status == 'in_process') && (!v.is_paid)) { + totalSum += parseInt(v.cost); + notPaidCount += 1; + outputValues += ''; + stagesIds += v.id + ';' + } + }); + + $("#stagesSelect").html(outputValues); + $(".totalSum").text(totalSum); + + if (json.results.length > notPaidCount && notPaidCount > 0) { + $("#choiceWayOrder").hide(); + } + + $("#choiceWayOrder").val(totalSum); + $("#ordermodalId").val(orderId); + + $("#stages-pay-form #stageSumPay").val(totalSum); + $("#stages-pay-form #stagesIds").val(stagesIds); + + $("#choiceWayOrder").attr('data-stages-ids', stagesIds); + + } + }); + + }); + + $("#tab2").on("change", "input[name=choice_way]:radio", function (e) { + var sumStage = $("#stagesSelect").find('option:selected').attr('data-stage-sum'); + var currIdStage = $("#stagesSelect").find('option:selected').val(); + $("#choiceWayStage").val(sumStage); + var currValue = $(this).val(); + $("#stages-pay-form #stageSumPay").val(currValue); + var selectId = ($(this).attr('id')); + if (selectId == 'choiceWayOrder') { + $("#stages-pay-form #stagesIds").val($(this).attr('data-stages-ids')); + $("#stagesSelect").prop('disabled', 'disabled'); + } else { + $("#stages-pay-form #stagesIds").val(currIdStage); + $("#stagesSelect").prop('disabled', false); + } + }); + + $("#tab2").on("change", "#stagesSelect", function (e) { + var sumStage = $(this).find('option:selected').attr("data-stage-sum"); + $("#choiceWayStage").val(sumStage); + $("#stages-pay-form #stageSumPay").val(sumStage); + $(".stageSum").text(sumStage); + $("#stages-pay-form #stagesIds").val($(this).val()); + }); + + //Получить заказы + function getStages(orderId, senderId, recipentId, secureOrder) { + $.ajax({ + url: '/api/orders/' + orderId + '/', + type: 'GET', + data: {csrfmiddlewaretoken: csrftoken}, + dataType: 'json', + }).then(function (data) { + var isReviewLeave = data.has_user_review; + var stagesResults = data.stages; + var stageCount = stagesResults.length; + if (stageCount == 0) { + $("#reserveSpace").hide(); + stageCountVal = 1; + } else { + stageCountVal = stageCount; + } + var htmlInbox = ""; + var htmlInboxStage = '

    Какое кол-во этапов подразумевает работа? ' + + '

    '; + + if (stageCount == 0) { + htmlInboxStage += '
    ' + + '

    Этап 1

    ' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
    '; + } + var statusNotAgreed = true; + var stagesInWork = []; + var stagesPaidProcess = []; + var stagesCompleted = []; + var stagePaidCount = 0; + var stagesReservedHtml = ""; + + $.each(stagesResults, function (i, v) { + if (v.status == "completed") { + stagesCompleted.push(v); + } + if (!data.secure) { + if (v.status == "in_process") { + stagesInWork.push(v); + } + } else if ((v.status == "in_process") && (v.is_paid)) { + stagesInWork.push(v); + stagesPaidProcess.push(v); + } + + if (v.is_paid) { + stagePaidCount += 1; + } + + if (v.status == "not_agreed" || v.status == 'cancel_approve' || v.status == 'send_approve') { + htmlInbox += '
    ' + + '

    Этап

    ' + + '' + + '' + + '' + + '' + + '' + + '' + + '
    '; + } else { + statusNotAgreed = false; + htmlInboxStage = ""; + var statusName = ""; + switch (v.status) { + case 'completed': + statusName = 'Завершен'; + break; + case 'in_process': + statusName = 'Согласовано'; + break; + default: + statusName = ''; + break; + } + if (v.status == 'completed') { + statusName = 'Завершен'; + } + htmlInbox += '
    ' + + '

    Этап ' + v.pos + '' + v.name + '

    ' + + '

    Результаты этапа:' + v.result + '

    ' + + '

    Срок до ' + v.term + '

    ' + v.cost + '' + + '

    Cрок заказа рассчитывается с момента резервирования средств

    ' + + '

    ' + statusName + '

    '; + + } + if (data.secure) { + if (v.is_paid) { + stagesReservedHtml += '
  • Сумма за этап ' + v.pos + '.Зарезервирована.
  • '; + } else { + stagesReservedHtml += '
  • Сумма за этап ' + v.pos + '.Не зарезервирована.
  • '; + } + } + }); + + if (stagesResults.length == stagePaidCount && data.secure) { + $("#reserve-button").parent().hide(); + } else { + $("#reserve-button").parent().show(); + } + + if (statusNotAgreed) { + if (!data.secure) { + htmlInbox += '
    ' + + '
    ' + + 'Перейти в режим безопасной сделки
    '; + } + + htmlInbox += ''; + } else if ((stagesResults.length > 0) && (data.secure)) { + $("#reserveSpace").show(); + } + + htmlInbox = htmlInboxStage + htmlInbox; + $("#order-stages").html(htmlInbox); + $("#completeWork").hide(); + + if (stagesInWork.length > 0) { + $("#completeWork").show(); + var stage = stagesInWork[0]; + var stageWork = '
    ' + + '

    В работе ' + stage.name + '

    ' + + '

    Результат этапа : ' + stage.result + '

    ' + + '

    Срок сдачи ' + stage.term + '

    ' + stage.cost + '
    ' + + '
    '; + + if (stage.close_contractor) { + stageWork += ''; + } + + if (data.secure) { + stageWork += ''; + } + $("#stagesWork").html(stageWork); + } + + if (!data.secure) { + $("#reserveSpace").hide(); + } + + if ((stagesCompleted.length == stagesResults.length) && (stagesCompleted.length > 0) && (!isReviewLeave)) { + $("#leaveReview").show(); + } else { + $("#leaveReview").hide(); + } + + $(".stages-paid").html(stagesReservedHtml); + + }); + } + + //Закрыть этап + $('#tab2').on('click', '.closeStage', function (e) { + e.preventDefault(); + var stageId = $(this).attr('data-stage-id'); + var _this = $(this); + $.ajax({ + url: '/api/stages/' + stageId + '/', + type: 'PATCH', + beforeSend: function (xhr) { + xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) + }, + data: {close_customer: true, status: 'completed'}, + dataType: 'json', + success: function (json) { + 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": _this.attr('data-order-id'), + "msg": "Заказчик закрыл этап " + json.name, + } + }); + console.log(json); + }, + error: function (e) { + console.log('error'); + console.log(e); + } + }); + }); + + // Добавление этапов + $("#order-stages").on('click', "#addStagesForm", function (e) { + e.preventDefault(); + var currentOrderId = $(this).attr('data-order-id'); + var secureOrderEl = $("#secureOrder"); + if (secureOrderEl.length > 0) { + var secOrderVal = false; + if (secureOrderEl.prop('checked')) { + secOrderVal = true; + } + $.ajax({ + url: '/api/orders/' + currentOrderId + '/', + type: 'PATCH', + beforeSend: function (xhr) { + xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) + }, + data: {secure: secOrderVal}, + dataType: 'json', + success: function (json) { + }, + error: function (e) { + console.log(e); + } + }); + } + + var callbacks = []; + + + $(".new-stages-form").each(function (i, v) { + var _this = $(this); + callbacks.push($.ajax({ + url: '/api/stages/', + type: 'POST', + beforeSend: function (xhr) { + xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) + }, + data: $(this).serialize(), + dataType: 'json', + done: function (json) { + _this.removeClass('new-stages-form').addClass('update-stages-form'); + console.log(json); + }, + fail: function (xhr, errorMsg,error) { + $.each(xhr.responseJSON, function(i,v){ + console.log(v); + console.log(i); + }); + }, + + })); + + + }); + //$.when(callbacks).then(function(x){ + // console.log(x); + // $.each(x,function(i,v){ + // console.log(v); + // }); + // alert("Запросы успешно выполнились"); + //}, function(){ + // alert("Произошла ошибка в запросах"); + //}); + + + $(".update-stages-form").each(function (i, v) { + var currentStageId = parseInt($(this).attr('data-stage-id')); + $.ajax({ + url: '/api/stages/' + currentStageId + '/', + type: 'PUT', + beforeSend: function (xhr) { + xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')) + }, + data: $(this).serialize(), + dataType: 'json', + success: function (json) { + console.log(json); + }, + error: function (e) { + console.log('error'); + console.log(e); + } + }); + }); + + + var currentRecipentId = $(this).attr('data-recipent-id'); + var secureOrder = true + + //socket.send_stages_approve({ + // "format_type": "approve_stages", + // "data": { + // "sender_id": userId, + // "recipent_id": currentRecipentId, + // "order_id": currentOrderId, + // "msg": "Этапы для заказа " + currentOrderId + " изменены", + // } + //}); + + }); + + //Изменение счетчика + $('#order-stages-tab').on('change', '#countStage', function () { + var countStage = parseInt($(this).val()); + var currentCountStage = $("#order-stages .numberStepp").length; + if ((countStage < 1) || isNaN(countStage)) { + countStage = 1; + $('#order-stages-tab #countStage').val(currentCountStage); + } else { + if (countStage > currentCountStage) { + for (var jj = currentCountStage; jj < countStage; jj++) { + var pos = jj + 1; + var lastFormStage = $("#order-stages .numberStepp").last(); + var orderId = lastFormStage.find('.orderStagesInput').val(); + var addFormTemplate = '
    ' + + '

    Этап ' + pos + '

    ' + + '' + + '' + + '' + + '' + + '' + + '' + + '
    '; + lastFormStage.after(addFormTemplate); + } + + } else if (countStage < currentCountStage) { + var ii = currentCountStage; + $($("#order-stages .numberStepp").get().reverse()).each(function () { + var currenFormName = ($(this).find('form').attr('class')); + if (ii > countStage) { + $(this).remove(); + } + ii--; + }); + + } + } + }); + + // Для заказов все вытащить + $('.order-block').on('click', function () { + $("#chat-order-add").css("display", "block"); + $("#formsetStage").css("display", "block"); + + $('.order-block').each(function () { + $(this).removeClass('orAct'); + }); + + $(this).addClass('orAct'); + var orderId = $(this).attr('data-id'); + location.hash = '#order' + orderId; + var projectId = $(this).attr('data-project-id'); + var recipentId = $(this).attr('data-recipent-id'); + var secureOrder = $(this).attr('data-secure-deal'); + secureOrder = Boolean(secureOrder); + $("#chat-order-add #orderId").val(orderId); + $("#add-form-order-note #orderNote").val(orderId); + $("#orderArbitrationId").val(orderId); + $("#projectReviewId").val(projectId); + $("#reserve-button").attr('data-order-id', orderId); + $("#targetContractorId").val(recipentId); + $("#chat-order-add #recipentId").val(recipentId); + $("#add-form-order-note #recipentNote").val(recipentId); + $(".orderStagesInput").val(orderId); + var inbox = document.getElementById('message-chat-order-space'); + var docList = document.getElementById('documentOrderSpace'); + inbox.innerHTML = ''; + docList.innerHTML = ''; + + $.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 += '
    ' + + '

    ' + senderName + '

    ' + v.created + '
    ' + + '

    ' + v.text + '

    '; + + }); + var height = inbox.scrollHeight; + 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 += '
  • ' + v.file + '
  • '; + }); + }, + error: function (e) { + console.log(e); + } + }); + + $.ajax({ + url: '/api/note/', + type: 'GET', + data: { + csrfmiddlewaretoken: csrftoken, + 'order': orderId, + }, + dataType: 'json', + success: function (json) { + var noteHtmlInbox = ''; + $.each(json.results, function (i, v) { + noteHtmlInbox += '
  • ' + v.text + '
  • '; + }); + $(".order-notes-block").html(noteHtmlInbox); + } + }); + getStages(orderId, userId, recipentId, secureOrder); + }); + +}); diff --git a/chat/templates/chat_customer.html b/chat/templates/chat_customer.html index 8ef04bb..bdbdf87 100644 --- a/chat/templates/chat_customer.html +++ b/chat/templates/chat_customer.html @@ -139,9 +139,21 @@ Полное описание заказа + + Удалить заказ +
  • +
    {% endfor %} + +
    + Показать архивные заказы +
    + +

    Архивные заказы

    +
    +
    @@ -265,516 +277,5 @@ - + {% endblock %} diff --git a/chat/urls.py b/chat/urls.py index 055b606..3e1fd01 100644 --- a/chat/urls.py +++ b/chat/urls.py @@ -4,6 +4,7 @@ from .views import ( ChatUserView, DocumentCreateView, messages_delete, + project_delete, download_file, ) @@ -12,6 +13,7 @@ app_name = 'chat' urlpatterns = [ urls.url(r'^$', ChatUserView.as_view(), name='chat-user'), urls.url(r'^messages_delete/$', messages_delete, name='chat-messages_delete'), + urls.url(r'^project/trashed/$', project_delete), urls.url(r'^create/$', DocumentCreateView.as_view()), urls.url(r'^download/(?P.+)', download_file), diff --git a/chat/views.py b/chat/views.py index 67e6829..4ccaf25 100644 --- a/chat/views.py +++ b/chat/views.py @@ -10,7 +10,7 @@ from wsgiref.util import FileWrapper from .response import JSONResponse, response_mimetype from .utils import serialize from .models import Message, Documents -from projects.models import Order +from projects.models import Order, Project from wallets.models import Transaction from users.models import User, Team @@ -56,7 +56,7 @@ class ChatUserView(LoginRequiredMixin, View): contacts_users = User.objects.filter(pk__in=users_ids) chat_messages = Message.objects.filter(Q(sender=request.user.pk) | Q(recipent=request.user.pk)) - orders = request.user.customer_projects.select_related('order').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) transaction = Transaction.objects.get_or_create(customer=request.user, type='reservation', complete=False) self.template_name = 'chat_customer.html' return render(request, self.template_name, {'contacts_users': contacts_users, @@ -75,7 +75,7 @@ class ChatUserView(LoginRequiredMixin, View): 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() - orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).all() + orders = Order.objects.filter(Q(contractor=request.user) | Q(team_id__in=team_ids)).filter(project__state='active').all() contractor_contacts = Message.objects.values_list('sender_id', 'recipent_id').filter( Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)).\ filter(is_delete=False).distinct() @@ -115,6 +115,24 @@ def messages_delete(request): raise Http404 +def project_delete(request): + if request.is_ajax(): + project_id = request.POST.get('project_id') + try: + project = Project.objects.get(pk=project_id,customer=request.user) + except Documents.DoesNotExist: + project = None + if project: + project.state = 'trashed' + project.save() + data = {'status': 'ok'} + else: + data = {'status': 'error'} + return HttpResponse(json.dumps(data), content_type='application/json') + else: + raise Http404 + + def download_file(request,file_name): try: document = Documents.objects.get(file=file_name) diff --git a/projects/models.py b/projects/models.py index 95b52be..a13cc51 100644 --- a/projects/models.py +++ b/projects/models.py @@ -254,6 +254,7 @@ STATUSES = ( ('completed', 'Завершен'), ) +from .validators import validate_term class Stage(models.Model): cost = models.DecimalField(max_digits=10, decimal_places=0) @@ -261,7 +262,7 @@ class Stage(models.Model): name = models.CharField(max_length=255) order = models.ForeignKey(Order, related_name='stages') result = models.CharField(max_length=255) - term = models.DateField() + term = models.DateField(validators=[validate_term]) term_type = models.CharField(max_length=10, choices=TERM_TYPES, default='hour') status = models.CharField(choices=STATUSES, max_length=30, default='not_agreed') created = models.DateTimeField(default=timezone.now) @@ -274,6 +275,13 @@ class Stage(models.Model): def __str__(self): return self.name + # def clean(self, *args, **kwargs): + # super().clean(*args, **kwargs) + # + # def save(self, *args, **kwargs): + # # self.full_clean() + # super().save(*args, **kwargs) + class Meta: ordering = ['pos'] verbose_name = 'Этап' diff --git a/projects/validators.py b/projects/validators.py new file mode 100644 index 0000000..4c51375 --- /dev/null +++ b/projects/validators.py @@ -0,0 +1,6 @@ +from django.core.exceptions import ValidationError + + +def validate_term(date): + if date.weekday() != 0: + raise ValidationError("Это не ваш день")