#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. 128
      chat/templates/chat_contractor.html
  6. 113
      chat/templates/chat_customer.html
  7. 33
      projects/serializers.py

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

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

@ -1,6 +1,6 @@
var SocketHandler = function () {
domain = domain.replace(':' + port, '');
var url = 'ws://' + domain + '/chat/' + userId + '/';
var url = 'ws://' + domain + ':8888/chat/' + userId + '/';
var sock = new WebSocket(url);
var intervalId;
sock.onopen = function () {
@ -20,6 +20,11 @@ var SocketHandler = function () {
} else if (message.answer_type == 'add_message_team') {
inbox = document.getElementById('message-chat-team-space');
} 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');
}
if (inbox) {

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

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

@ -288,23 +288,22 @@
//Получить заказы
function getStages(orderId, senderId, recipentId, secureOrder) {
$.ajax({
url: '/api/stages/',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
dataType: 'json',
success: function (json) {
var stageCount = json.results.length;
url:'/api/orders/' + orderId + '/',
type: 'GET',
data:{csrfmiddlewaretoken: csrftoken},
dataType: 'json',
}).then(function(data){
var stagesResults = data.stages;
var stageCount = stagesResults.length;
if (stageCount == 0) {
$("#reserveSpace").hide();
stageCountVal = 1;
} else {
stageCountVal = stageCount;
}
var htmlInbox = "";
var htmlInboxStage = '<p class="textStepss">Какое кол-во этапов подразумевает работа? ' +
'<input type="text" id="countStage" value="' + stageCountVal + '"size="3"/></p>';
@ -320,13 +319,19 @@
'</form></div>';
}
var statusNotAgreed = true;
var stagesInWork = [];
var stagesPaidProcess = [];
$.each(json.results, function (i, v) {
if ((v.status == "in_process") && (v.is_paid)){
$.each(stagesResults, function (i, 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.status == "not_agreed") {
htmlInbox += '<div class="numberStepp box-sizing">' +
'<p>Этап</p><form class="update-stages-form" data-stage-id="' + v.id + '" id="stage-form-' + v.pos + '">' +
@ -349,8 +354,8 @@
});
if (statusNotAgreed) {
if(secureOrder) {
var orderSecureCheckbox = 'checked="checked"';
if(!data.secure) {
var orderSecureCheckbox = '';
htmlInbox += '<div class="box-sizing disTab">' +
'<div class="checkbox"><input name="secure" id="secureOrder"'+ orderSecureCheckbox +'type="checkbox" style="opacity:1">' +
'Перейти в режим безопасной сделки</div></div>';
@ -360,28 +365,26 @@
'<a href="#" data-sender-id="' + senderId +'" ' +
'data-recipent-id="' + recipentId +'" data-order-id="' + orderId + '" ' +
'id="addStagesForm">отправить на согласование</a> </div>';
}else if(json.results.length>0){
}else if((stagesResults.length>0) && (data.secure)){
$("#reserveSpace").show();
}
htmlInbox = htmlInboxStage + htmlInbox;
$("#order-stages").html(htmlInbox);
$("#completeWork").hide();
if (stagesPaidProcess.length > 0){
if(stagesInWork.length > 0){
$("#completeWork").show();
var stage = stagesPaidProcess[0];
var stage = stagesInWork[0];
var stageWork = '<p>В работе '+ stage.name +'</p> ' +
'<p>Результат этапа : '+ stage.result +'</p>' +
'<p>Срок сдачи 25.08.2016 <b>' + stage.cost + 'р.</b></p>';
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);
}else{
$("#completeWork").hide();
}
}
});
}
@ -389,6 +392,7 @@
$('#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',
@ -398,6 +402,15 @@
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) {
@ -462,11 +475,14 @@
"sender_id": userId,
"recipent_id": currentRecipentId,
"order_id": currentOrderId,
"msg": "Этапы для заказа "+ currentOrderId +"изменены",
}
});
setTimeout(function () {
getStages(currentOrderId,userId,currentRecipentId,secureOrder);
}, 1000);
{# setTimeout(function () {#}
{# getStages(currentOrderId,userId,currentRecipentId,secureOrder);#}
{##}
{# }, 1000);#}
});
@ -474,33 +490,38 @@
$('#order-stages-tab').on('change', '#countStage', function () {
var countStage = parseInt($(this).val());
var currentCountStage = $(".numberStepp").length;
if (countStage > currentCountStage){
for(var jj=currentCountStage; jj<countStage;jj++){
var pos = jj + 1;
var lastFormStage = $(".numberStepp").last();
var orderId = lastFormStage.find('.orderStagesInput').val();
var addFormTemplate = '<div class="numberStepp box-sizing" id="stage1">' +
'<p>Этап <span class="stage-span-id">'+ pos +'</span></p><form class="new-stages-form" id="stage-form">' +
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 = $(".numberStepp").last();
var orderId = lastFormStage.find('.orderStagesInput').val();
var addFormTemplate = '<div class="numberStepp box-sizing" id="stage1">' +
'<p>Этап <span class="stage-span-id">' + pos + '</span></p><form class="new-stages-form" id="stage-form">' +
'<label for="">Название</label><input class="form-control" name="name" type="text" />' +
'<label for="">Цена</label><input class="form-control" name="cost" type="text" />' +
'<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '" />' +
'<label for="">Срок</label><input class="form-control" name="term" type="text" />' +
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' +
'<input class="form-control" name="pos" value="'+ pos +'" type="hidden" />'
'</form></div>';
lastFormStage.after(addFormTemplate);
}
}else if (countStage < currentCountStage) {
var ii = currentCountStage;
$($(".numberStepp").get().reverse()).each(function(){
var currenFormName = ($(this).find('form').attr('class'));
if(ii>countStage) {
$(this).remove();
'<input class="form-control" name="pos" value="' + pos + '" type="hidden" />'
'</form></div>';
lastFormStage.after(addFormTemplate);
}
ii--;
});
} else if (countStage < currentCountStage) {
var ii = currentCountStage;
$($(".numberStepp").get().reverse()).each(function () {
var currenFormName = ($(this).find('form').attr('class'));
if (ii > countStage) {
$(this).remove();
}
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):
# order = OrderSerializer()
@ -97,6 +83,25 @@ class StageSerializer(ModelSerializer):
# 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):
customer = UserSerializer()
specialization = SpecializationSerializer()

Loading…
Cancel
Save