#ARC-18 add complete work

remotes/origin/PR-39
Mukhtar 10 years ago
parent 0a7055358d
commit bfcecd3031
  1. 2
      api/urls.py
  2. 15
      api/views.py
  3. 7
      assets/js/chat.js
  4. 4
      chat/chat.py
  5. 98
      chat/templates/chat_contractor.html
  6. 69
      chat/templates/chat_customer.html
  7. 33
      projects/serializers.py

@ -17,6 +17,7 @@ from .views import (
StageViewSet, StageViewSet,
TeamViewSet, TeamViewSet,
UserViewSet, UserViewSet,
OrderViewSet,
) )
@ -32,6 +33,7 @@ router.register(r'note', NoteViewSet)
router.register(r'portfolio-photos', PortfolioPhotoViewSet) router.register(r'portfolio-photos', PortfolioPhotoViewSet)
router.register(r'portfolios', PortfolioViewSet) router.register(r'portfolios', PortfolioViewSet)
router.register(r'projects', ProjectViewSet) router.register(r'projects', ProjectViewSet)
router.register(r'orders', OrderViewSet)
router.register(r'realties', RealtyViewSet) router.register(r'realties', RealtyViewSet)
router.register(r'reviews', ReviewViewSet) router.register(r'reviews', ReviewViewSet)
router.register(r'specializations', SpecializationViewSet) router.register(r'specializations', SpecializationViewSet)

@ -2,9 +2,12 @@ from django.db.models import Q
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from rest_framework import permissions from rest_framework import permissions
from projects.models import Project, Realty, Stage, Portfolio, PortfolioPhoto, Answer, AnswerFile from projects.models import Project, Realty, Stage, Portfolio, PortfolioPhoto, Answer, AnswerFile, Order
from projects.serializers import ProjectSerializer, RealtySerializer, StageSerializer, PortfolioSerializer, PortfolioPhotoSerializer, AnswerSerializer, AnswerFileSerializer from projects.serializers import (ProjectSerializer, RealtySerializer, StageSerializer,
from projects.filters import ProjectFilterSet, RealtyFilterSet, StageFilterSet, PortfolioFilterSet, PortfolioPhotoFilterSet PortfolioSerializer, PortfolioPhotoSerializer, AnswerSerializer,
OrderSerializer, AnswerFileSerializer,)
from projects.filters import (ProjectFilterSet, RealtyFilterSet, StageFilterSet, PortfolioFilterSet,
OrderFilterSet, PortfolioPhotoFilterSet,)
from specializations.models import Specialization from specializations.models import Specialization
from specializations.serializers import SpecializationSerializer from specializations.serializers import SpecializationSerializer
@ -108,6 +111,12 @@ class RealtyViewSet(ModelViewSet):
filter_class = RealtyFilterSet filter_class = RealtyFilterSet
class OrderViewSet(ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
filter_class = OrderFilterSet
class SpecializationViewSet(ModelViewSet): class SpecializationViewSet(ModelViewSet):
try: # TODO: dirty try: # TODO: dirty
queryset = Specialization.objects.root_nodes()[0].get_descendants() queryset = Specialization.objects.root_nodes()[0].get_descendants()

@ -1,6 +1,6 @@
var SocketHandler = function () { var SocketHandler = function () {
domain = domain.replace(':' + port, ''); domain = domain.replace(':' + port, '');
var url = 'ws://' + domain + '/chat/' + userId + '/'; var url = 'ws://' + domain + ':8888/chat/' + userId + '/';
var sock = new WebSocket(url); var sock = new WebSocket(url);
var intervalId; var intervalId;
sock.onopen = function () { sock.onopen = function () {
@ -20,6 +20,11 @@ var SocketHandler = function () {
} else if (message.answer_type == 'add_message_team') { } else if (message.answer_type == 'add_message_team') {
inbox = document.getElementById('message-chat-team-space'); inbox = document.getElementById('message-chat-team-space');
} else if (message.answer_type == 'approve_stages') { } else if (message.answer_type == 'approve_stages') {
var resOrderId = message.order_id;
$.jGrowl(message.msg,{life: 2000});
setTimeout(function () {
$("#orderBlock" + resOrderId).trigger('click');
}, 2000);
console.log('approve stages'); console.log('approve stages');
} }
if (inbox) { if (inbox) {

@ -43,14 +43,14 @@ class ChatHandler(websocket.WebSocketHandler):
@gen.coroutine @gen.coroutine
def approve_stages(self, data): def approve_stages(self, data):
print(data)
sender_id = data['data']['sender_id'] sender_id = data['data']['sender_id']
recipent_id = data['data']['recipent_id'] recipent_id = data['data']['recipent_id']
order_id = data['data'].get('order_id') order_id = data['data'].get('order_id')
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 or c == sender_id)
for waiter in waiters: for waiter in waiters:
waiter.write_message({'msg': 'Этапы обновлены', 'answer_type': answer_type}) 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):

@ -108,7 +108,7 @@
<p>Заказы</p> <p>Заказы</p>
{% for order in orders %} {% for order in orders %}
<div class="orderBlock box-sizing order-block" <div class="orderBlock box-sizing order-block"
data-recipent-id="{{ order.project.customer.pk }}" data-id="{{ order.id }}"> id="orderBlock{{ order.id }}" data-recipent-id="{{ order.project.customer.pk }}" data-id="{{ order.id }}">
<span class="dimovChat"></span> <span class="dimovChat"></span>
<p class="titleOB">{{ order }}</p> <p class="titleOB">{{ order }}</p>
<div class="hideOBB"> <div class="hideOBB">
@ -147,16 +147,17 @@
<div class="stepssBlock box-sizing disTab"> <div class="stepssBlock box-sizing disTab">
<p class="titleStepss">1 / Согласование условий</p> <p class="titleStepss">1 / Согласование условий</p>
<p class="textStepss"> <p class="textStepss">
Обсуджение задания и условий выполнения работы. Подтверждение заказа исполнителем. Обсуджение задания и условий выполнения работы.
Подтверждение заказа исполнителем.
</p> </p>
</div> </div>
<div id="order-stages"></div> <div id="order-stages"></div>
<div class="stepssBlock box-sizing disTab"> <div class="stepssBlock box-sizing disTab" id="reserveSpace" style="display:none;">
<p class="titleStepss">2 / Резервирование</p> <p class="titleStepss">2 / Резервирование</p>
<p class="textStepss"> <p class="textStepss">
Резервирование заказчиком суммы оплаты по заказ. Деньги перечисляются и хранятся на Резервирование заказчиком суммы оплаты по заказ.
сайте. Деньги перечисляются и хранятся на сайте.
</p> </p>
<ul class="stages-paid"></ul> <ul class="stages-paid"></ul>
</div> </div>
@ -293,6 +294,7 @@
var url = '/work_sell/basic/'; var url = '/work_sell/basic/';
//Загрузка документов
$('#upload-document-team').fileupload({ $('#upload-document-team').fileupload({
url: url, url: url,
crossDomain: false, crossDomain: false,
@ -325,12 +327,11 @@
}).prop('disabled', !$.support.fileInput) }).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled'); .parent().addClass($.support.fileInput ? undefined : 'disabled');
// Согласование этапов
$("#order-stages").on('click', "#approve-stages", function (e) { $("#order-stages").on('click', "#approve-stages", function (e) {
e.preventDefault(); e.preventDefault();
$(".stage-block-approve").each(function () { $(".stage-block-approve").each(function () {
var stageId = $(this).attr('data-id'); var stageId = $(this).attr('data-id');
$.ajax({ $.ajax({
url: '/api/stages/' + stageId + '/', url: '/api/stages/' + stageId + '/',
type: 'PATCH', type: 'PATCH',
@ -341,6 +342,7 @@
dataType: 'json', dataType: 'json',
success: function (json) { success: function (json) {
console.log(json); console.log(json);
}, },
error: function (e) { error: function (e) {
console.log('error'); console.log('error');
@ -349,6 +351,18 @@
}); });
}); });
var orderId = $(this).attr('data-order-id');
socket.send_stages_approve({
"format_type": "approve_stages",
"data": {
"sender_id": $(this).attr('data-sender-id'),
"recipent_id": $(this).attr('data-recipent-id'),
"order_id": orderId,
"msg": "Исполнитель согласовал этапы для заказа " + orderId,
}
});
}); });
$(".team-chat-user").on('click', function (e) { $(".team-chat-user").on('click', function (e) {
@ -449,57 +463,80 @@
}); });
$.ajax({ $.ajax({
url: '/api/stages/', url:'/api/orders/' + orderId + '/',
type: 'GET', type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId}, data:{csrfmiddlewaretoken: csrftoken},
dataType: 'json', dataType: 'json',
success: function (json) {
console.log(json.results); }).then(function(data){
var htmlInbox = ""; var htmlInbox = "";
var stagesReservedHtml = ""; var stagesReservedHtml = "";
var stagesPaidProcess = []; var stagesPaidProcess = [];
if (json.results.length > 0) { var stagesInWork = [];
var stagesResults = data.stages;
$.each(json.results, function (i, v) { var statusNotAgreed = false;
if (stagesResults.length > 0) {
$.each(stagesResults, function (i, v) {
if(v.status == "not_agreed"){
statusNotAgreed = true;
}
if(!data.secure){
if(v.status == "in_process"){
stagesInWork.push(v);
if ((v.status == "in_process") && (v.is_paid)){ }
} else if ((v.status == "in_process") && (v.is_paid)){
stagesPaidProcess.push(v); stagesPaidProcess.push(v);
stagesInWork.push(v);
} }
if (v.is_paid) { if (v.is_paid) {
stagesReservedHtml += '<li class="reserved">Сумма за этап ' + v.pos + '.Зарезервирована.</li>'; stagesReservedHtml += '<li class="reserved">Сумма за этап ' + v.pos + '.Зарезервирована.</li>';
} else { } else {
stagesReservedHtml += '<li class="unreserved">Сумма за этап ' + v.pos + '.Не зарезервирована.</li>'; stagesReservedHtml += '<li class="unreserved">Сумма за этап ' + v.pos + '.Не зарезервирована.</li>';
} }
htmlInbox += '<div data-id="' + v.id + '" class="numberStepp box-sizing stage-block-approve"><div class="insetNumStepp">' + htmlInbox += '<div data-id="' + v.id + '" class="numberStepp box-sizing stage-block-approve"><div class="insetNumStepp">' +
'<p class="titleNumStepp"><span>Этап ' + v.pos + '</span>' + v.name + '</p>' + '<p class="titleNumStepp"><span>Этап ' + v.pos + '</span>' + v.name + '</p>' +
'<p class="textNumStepp">Результаты этапа:' + v.result + '</p><div>' + '<p class="textNumStepp">Результаты этапа:' + v.result + '</p><div>' +
'<p>' + v.term + '</p><span>' + v.cost + '<i class="fa fa-rub"></i></span></div></div></div>'; '<p>' + v.term + '</p><span>' + v.cost + '<i class="fa fa-rub"></i></span></div></div></div>';
}); });
htmlInbox += '<div class="textAreaBlock2 FFD box-sizing disTab"><a id="approve-stages" href="#">согласовать</a></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 + '"' +
' data-order-id="' + orderId + '" href="#">согласовать</a></div>';
} }
}
$("#order-stages").html(htmlInbox); $("#order-stages").html(htmlInbox);
$(".stages-paid").html(stagesReservedHtml); $(".stages-paid").html(stagesReservedHtml);
if (stagesInWork.length > 0){
if (stagesPaidProcess.length > 0){
$("#completeWork").show(); $("#completeWork").show();
var stage = stagesPaidProcess[0]; var stage = stagesInWork[0];
var stageWork = '<p>В работе '+ stage.name +'</p> ' + var stageWork = '<p>В работе '+ stage.name +'</p> ' +
'<p>Результат этапа : '+ stage.result +'</p>' + '<p>Результат этапа : '+ stage.result +'</p>' +
'<p>Срок сдачи 25.08.2016 <b>' + stage.cost + 'р.</b></p>' + '<p>Срок сдачи '+ stage.term +' <b>' + stage.cost + 'р.</b></p>';
'<a href="#" class="closeStage" data-stage-id="'+ stage.id +'">Завершить этап</a>' +
'<a href="#">Обратитьсяв арбитраж</a>'; if(!stage.close_contractor){
stageWork += '<a href="#" class="closeStage" data-sender-id="{{ request.user.pk }}" data-recipent-id="'+ recipentId+'"' +
' data-order-id="'+ data.id +'" data-stage-id="'+ stage.id +'">Завершить этап</a>';
}else{
stageWork += '<p>Этап ожидает завершения статуса от заказчика</p>';
}
stageWork += '<a href="#">Обратитьсяв арбитраж</a>';
$("#stagesWork").html(stageWork); $("#stagesWork").html(stageWork);
}else{ }else{
$("#completeWork").hide(); $("#completeWork").hide();
} }
}
}); });
}); });
//Добавить заметку.
$('#add-note-button').on('click', function (e) { $('#add-note-button').on('click', function (e) {
e.preventDefault(); e.preventDefault();
$.ajax({ $.ajax({
@ -525,6 +562,7 @@
$('#tab2').on('click','.closeStage', function(e){ $('#tab2').on('click','.closeStage', function(e){
e.preventDefault(); e.preventDefault();
var stageId = $(this).attr('data-stage-id'); var stageId = $(this).attr('data-stage-id');
var _this = $(this);
$.ajax({ $.ajax({
url: '/api/stages/' + stageId + '/', url: '/api/stages/' + stageId + '/',
type: 'PATCH', type: 'PATCH',
@ -534,7 +572,17 @@
data: "close_contractor=True", data: "close_contractor=True",
dataType: 'json', dataType: 'json',
success: function (json) { success: function (json) {
alert(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); console.log(json);
}, },
error: function (e) { error: function (e) {

@ -288,23 +288,22 @@
//Получить заказы //Получить заказы
function getStages(orderId, senderId, recipentId, secureOrder) { function getStages(orderId, senderId, recipentId, secureOrder) {
$.ajax({ $.ajax({
url: '/api/stages/', url:'/api/orders/' + orderId + '/',
type: 'GET', type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId}, data:{csrfmiddlewaretoken: csrftoken},
dataType: 'json', dataType: 'json',
success: function (json) {
var stageCount = json.results.length; }).then(function(data){
var stagesResults = data.stages;
var stageCount = stagesResults.length;
if (stageCount == 0) { if (stageCount == 0) {
$("#reserveSpace").hide(); $("#reserveSpace").hide();
stageCountVal = 1; stageCountVal = 1;
} else { } else {
stageCountVal = stageCount; stageCountVal = stageCount;
} }
var htmlInbox = ""; var htmlInbox = "";
var htmlInboxStage = '<p class="textStepss">Какое кол-во этапов подразумевает работа? ' + var htmlInboxStage = '<p class="textStepss">Какое кол-во этапов подразумевает работа? ' +
'<input type="text" id="countStage" value="' + stageCountVal + '"size="3"/></p>'; '<input type="text" id="countStage" value="' + stageCountVal + '"size="3"/></p>';
@ -320,13 +319,19 @@
'</form></div>'; '</form></div>';
} }
var statusNotAgreed = true; var statusNotAgreed = true;
var stagesInWork = [];
var stagesPaidProcess = []; var stagesPaidProcess = [];
$.each(json.results, function (i, v) { $.each(stagesResults, function (i, v) {
if(!data.secure){
if ((v.status == "in_process") && (v.is_paid)){ if(v.status == "in_process") {
stagesInWork.push(v);
}
}else if ((v.status == "in_process") && (v.is_paid)){
stagesInWork.push(v);
stagesPaidProcess.push(v); stagesPaidProcess.push(v);
} }
if (v.status == "not_agreed") { if (v.status == "not_agreed") {
htmlInbox += '<div class="numberStepp box-sizing">' + htmlInbox += '<div class="numberStepp box-sizing">' +
'<p>Этап</p><form class="update-stages-form" data-stage-id="' + v.id + '" id="stage-form-' + v.pos + '">' + '<p>Этап</p><form class="update-stages-form" data-stage-id="' + v.id + '" id="stage-form-' + v.pos + '">' +
@ -349,8 +354,8 @@
}); });
if (statusNotAgreed) { if (statusNotAgreed) {
if(secureOrder) { if(!data.secure) {
var orderSecureCheckbox = 'checked="checked"'; var orderSecureCheckbox = '';
htmlInbox += '<div class="box-sizing disTab">' + htmlInbox += '<div class="box-sizing disTab">' +
'<div class="checkbox"><input name="secure" id="secureOrder"'+ orderSecureCheckbox +'type="checkbox" style="opacity:1">' + '<div class="checkbox"><input name="secure" id="secureOrder"'+ orderSecureCheckbox +'type="checkbox" style="opacity:1">' +
'Перейти в режим безопасной сделки</div></div>'; 'Перейти в режим безопасной сделки</div></div>';
@ -360,27 +365,25 @@
'<a href="#" data-sender-id="' + senderId +'" ' + '<a href="#" data-sender-id="' + senderId +'" ' +
'data-recipent-id="' + recipentId +'" data-order-id="' + orderId + '" ' + 'data-recipent-id="' + recipentId +'" data-order-id="' + orderId + '" ' +
'id="addStagesForm">отправить на согласование</a> </div>'; 'id="addStagesForm">отправить на согласование</a> </div>';
}else if(json.results.length>0){ }else if((stagesResults.length>0) && (data.secure)){
$("#reserveSpace").show(); $("#reserveSpace").show();
} }
htmlInbox = htmlInboxStage + htmlInbox; htmlInbox = htmlInboxStage + htmlInbox;
$("#order-stages").html(htmlInbox); $("#order-stages").html(htmlInbox);
$("#completeWork").hide();
if(stagesInWork.length > 0){
if (stagesPaidProcess.length > 0){
$("#completeWork").show(); $("#completeWork").show();
var stage = stagesPaidProcess[0]; var stage = stagesInWork[0];
var stageWork = '<p>В работе '+ stage.name +'</p> ' + var stageWork = '<p>В работе '+ stage.name +'</p> ' +
'<p>Результат этапа : '+ stage.result +'</p>' + '<p>Результат этапа : '+ stage.result +'</p>' +
'<p>Срок сдачи 25.08.2016 <b>' + stage.cost + 'р.</b></p>'; '<p>Срок сдачи 25.08.2016 <b>' + stage.cost + 'р.</b></p>';
if (stage.close_contractor){ if (stage.close_contractor){
stageWork += '<a href="#" class="closeStage" data-stage-id="'+ stage.id+'">Закрыть этап '+ stage.pos +'</a>'; stageWork += '<a href="#" class="closeStage" data-order-id="'+ orderId + '" data-sender-id="{{ request.user.pk }}"' +
' data-recipent-id="'+ recipentId + '" data-stage-id="'+ stage.id+'">Закрыть этап '+ stage.pos +'</a>';
} }
$("#stagesWork").html(stageWork); $("#stagesWork").html(stageWork);
}else{
$("#completeWork").hide();
}
} }
}); });
} }
@ -389,6 +392,7 @@
$('#tab2').on('click','.closeStage', function(e){ $('#tab2').on('click','.closeStage', function(e){
e.preventDefault(); e.preventDefault();
var stageId = $(this).attr('data-stage-id'); var stageId = $(this).attr('data-stage-id');
var _this = $(this);
$.ajax({ $.ajax({
url: '/api/stages/' + stageId + '/', url: '/api/stages/' + stageId + '/',
type: 'PATCH', type: 'PATCH',
@ -398,6 +402,15 @@
data: {close_customer: true, status: 'completed'}, data: {close_customer: true, status: 'completed'},
dataType: 'json', dataType: 'json',
success: function (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); console.log(json);
}, },
error: function (e) { error: function (e) {
@ -462,11 +475,14 @@
"sender_id": userId, "sender_id": userId,
"recipent_id": currentRecipentId, "recipent_id": currentRecipentId,
"order_id": currentOrderId, "order_id": currentOrderId,
"msg": "Этапы для заказа "+ currentOrderId +"изменены",
} }
}); });
setTimeout(function () {
getStages(currentOrderId,userId,currentRecipentId,secureOrder); {# setTimeout(function () {#}
}, 1000); {# getStages(currentOrderId,userId,currentRecipentId,secureOrder);#}
{##}
{# }, 1000);#}
}); });
@ -474,7 +490,10 @@
$('#order-stages-tab').on('change', '#countStage', function () { $('#order-stages-tab').on('change', '#countStage', function () {
var countStage = parseInt($(this).val()); var countStage = parseInt($(this).val());
var currentCountStage = $(".numberStepp").length; var currentCountStage = $(".numberStepp").length;
if ((countStage<1) || isNaN(countStage)) {
countStage = 1;
$('#order-stages-tab #countStage').val(currentCountStage);
}else {
if (countStage > currentCountStage) { if (countStage > currentCountStage) {
for (var jj = currentCountStage; jj < countStage; jj++) { for (var jj = currentCountStage; jj < countStage; jj++) {
var pos = jj + 1; var pos = jj + 1;
@ -501,6 +520,8 @@
} }
ii--; ii--;
}); });
}
} }
}); });

@ -47,20 +47,6 @@ class RealtySerializer(ModelSerializer):
) )
class OrderSerializer(ModelSerializer):
class Meta:
model = Order
fields = (
'id',
'contractor',
'team',
'created',
'project',
'secure',
'status',
)
class StageSerializer(ModelSerializer): class StageSerializer(ModelSerializer):
# order = OrderSerializer() # order = OrderSerializer()
@ -97,6 +83,25 @@ class StageSerializer(ModelSerializer):
# return inst # return inst
class OrderSerializer(ModelSerializer):
stages = StageSerializer(many=True)
class Meta:
model = Order
fields = (
'id',
'contractor',
'team',
'created',
'project',
'secure',
'status',
'stages',
)
class ProjectSerializer(ModelSerializer): class ProjectSerializer(ModelSerializer):
customer = UserSerializer() customer = UserSerializer()
specialization = SpecializationSerializer() specialization = SpecializationSerializer()

Loading…
Cancel
Save