remotes/origin/PR-39
ArturBaybulatov 10 years ago
commit 6309168666
  1. 2
      archilance/settings/base.py
  2. 11
      assets/js/chat.js
  3. 320
      assets/js/chat_customer.js
  4. 63
      chat/templates/chat_contractor.html
  5. 250
      chat/templates/chat_customer.html
  6. 41
      chat/templates/reverse_stage_modal.html
  7. 49
      chat/templates/review_add_modal.html
  8. 13
      chat/views.py
  9. 29
      projects/migrations/0014_auto_20160824_0154.py
  10. 20
      projects/migrations/0015_auto_20160824_1119.py
  11. 16
      projects/migrations/0016_merge.py
  12. 9
      projects/models.py
  13. 2
      projects/serializers.py
  14. 6
      projects/views.py
  15. 1
      requirements/base.txt
  16. 5
      templates/partials/header.html
  17. 20
      wallets/migrations/0009_transaction_stages_id.py
  18. 1
      wallets/models.py
  19. 5
      wallets/views.py

@ -41,6 +41,7 @@ THIRD_PARTY_APPS = [
'mathfilters', # Basic math operations in templates; https://pypi.python.org/pypi/django-mathfilters 'mathfilters', # Basic math operations in templates; https://pypi.python.org/pypi/django-mathfilters
'generic_relations', # https://github.com/Ian-Foote/rest-framework-generic-relations 'generic_relations', # https://github.com/Ian-Foote/rest-framework-generic-relations
'hitcount', 'hitcount',
'django_activeurl',
] ]
LOCAL_APPS = [ LOCAL_APPS = [
@ -85,6 +86,7 @@ TEMPLATES = [
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'django.core.context_processors.request',
], ],
# Load these templatetags by default: # Load these templatetags by default:

@ -20,7 +20,7 @@ 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') {
alert('approve stages'); console.log('approve stages');
} }
if (inbox) { if (inbox) {
var textMessage = message.msg; var textMessage = message.msg;
@ -94,6 +94,15 @@ function csrfSafeMethod(method) {
$(function () { $(function () {
setTimeout(function () {
$(".user-block").first().trigger('click');
}, 10);
setTimeout(function () {
$(".order-block").first().trigger('click');
}, 100);
$('.deleteMess').on('click', function (e) { $('.deleteMess').on('click', function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();

@ -0,0 +1,320 @@
$(function () {
var currentChatUser = {
{
request.user.pk
}
}
;
var socket = new SocketHandler();
var form = document.getElementById('message_form');
var csrftoken = getCookie('csrftoken');
$("#reserve-button").on("click", function (e) {
e.preventDefault();
var orderId = $(this).attr('data-order-id');
$.ajax({
url: '/api/stages/',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
dataType: 'json',
success: function (json) {
console.log(json.results);
}
});
});
function getStages(orderId, senderId, recipentId) {
$.ajax({
url: '/api/stages/',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
dataType: 'json',
success: function (json) {
var stageCount = json.results.length;
if (stageCount == 0) {
stageCountVal = 1;
} else {
stageCountVal = stageCount;
}
var htmlInbox = "";
var htmlInboxStage = '<p class="textStepss">Какое кол-во этапов подразумевает работа? ' +
'<input type="text" id="countStage" value="' + stageCountVal + '"size="3"/></p>';
if (stageCount == 0) {
htmlInboxStage += '<div class="numberStepp box-sizing" id="stage1">' +
'<p>Этап <span class="stage-span-id">1</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" />' +
'<label for="">Позиция</label><input class="form-control" name="pos" value="1" type="text" />' +
'</form></div>';
}
var statusNotAgreed = true;
$.each(json.results, function (i, 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 + '">' +
'<label for="">Название</label><input class="form-control" type="text" name="name" value="' + v.name + '" />' +
'<label for="">Цена</label><input class="form-control" type="text" name="cost" value="' + v.cost + '" />' +
'<input class="form-control orderStagesInput" type="hidden" name="order" value="' + v.order + '"/>' +
'<label for="">Срок</label><input class="form-control" type="text" name="term" value="' + v.term + '" />' +
'<label for="">Результат</label><input class="form-control" type="text" name="result" value="' + v.result + '" />' +
'</form></div>';
} else {
statusNotAgreed = false;
htmlInboxStage = "";
htmlInbox += '<div class="numberStepp box-sizing"><div class="insetNumStepp">' +
'<p class="titleNumStepp"><span>Этап ' + v.pos + '</span>' + v.name + '</p>' +
'<p class="textNumStepp">Результаты этапа:' + v.result + '</p><div>' +
'<p>до Дата</p><span>' + v.cost + '<i class="fa fa-rub"></i></span></div></div></div>';
}
});
if (statusNotAgreed) {
htmlInbox += '<div class="box-sizing disTab" style="text-align:center;"><div class="checkbox"><input type="checkbox" style="opacity:1">Перейти в режим безопасной сделки' +
'</div></div><div class="textAreaBlock2 box-sizing disTab">' +
'<a href="#" data-sender-id="' + senderId + '" data-recipent-id="' + recipentId + '" data-order-id="' + orderId + '" id="addStagesForm">отправить на согласование</a> </div>';
}
htmlInbox = htmlInboxStage + htmlInbox;
$("#order-stages").html(htmlInbox);
}
});
}
setTimeout(function () {
$(".user-block").first().trigger('click');
}, 10);
setTimeout(function () {
$(".order-block").first().trigger('click');
}, 100);
$("#order-stages").on('click', "#addStagesForm", function (e) {
e.preventDefault();
$(".new-stages-form").each(function (i, v) {
$.ajax({
url: '/api/stages/',
type: 'POST',
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(e);
}
});
});
$(".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 currentOrderId = $(this).attr('data-order-id');
var currentRecipentId = $(this).attr('data-recipent-id');
getStages(currentOrderId, userId, currentRecipentId);
socket.send_stages_approve({
"format_type": "approve_stages",
"data": {
"sender_id": userId,
"recipent_id": currentRecipentId,
"order_id": currentOrderId,
}
});
});
$('#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">' +
'<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" />' +
'<label for="">Позиция</label><input class="form-control" name="pos" value="' + pos + '" type="text" />'
'</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();
}
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');
var recipentId = $(this).attr('data-recipent-id');
$("#chat-order-add #orderId").val(orderId);
$("#projectReviewId").val(orderId);
$("#reserve-button").attr('data-order-id', orderId);
$("#targetContractorId").val(recipentId);
$("#chat-order-add #recipentId").val(recipentId);
$(".orderStagesInput").val(orderId);
var inbox = document.getElementById('message-chat-order-space');
inbox.innerHTML = '';
$.ajax({
url: '/api/message',
type: 'GET',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
dataType: 'json',
success: function (json) {
$.each(json.results, function (i, v) {
var senderName = 'Вы';
var className = 'youChat';
if (v.sender.id !== currentChatUser) {
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>';
});
}
});
getStages(orderId, userId, recipentId);
});
// Вытащить сообщения для конактов
$('.user-block').on('click', function () {
var userId = $(this).attr('data-id');
$("#contact-chat-form #recipentId").val(userId);
$("#add-form-contractor-note #recipentNoteContractor").val(userId);
$('.user-block').each(function () {
$(this).removeClass('mesAct');
});
$(this).addClass('mesAct');
var inbox = document.getElementById('message-chat-space');
inbox.innerHTML = '';
$.ajax({
url: '/api/message',
type: 'GET',
data: {
csrfmiddlewaretoken: csrftoken,
'operand': 'in',
'sender_id': currentChatUser,
'recipent_id': userId
},
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>';
});
}
});
});
$('#contact-chat-add-message').on('click', function (e) {
e.preventDefault();
var chatMessage = $("#chat").val();
var recipentId = $("#recipentId").val();
var senderId = $("#senderId").val();
socket.add_contact_message({
"format_type": "add_message_contact",
"data": {
"sender_id": senderId,
"recipent_id": recipentId,
"chat_message": chatMessage,
}
});
$("#chat").val("");
});
$('#order-review-add').on('click', function () {
alert('add review');
});
$('#order-chat-add-message').on('click', function (e) {
e.preventDefault();
var chatMessage = $("#chat-order-add #chat").val();
var recipentId = $("#chat-order-add #recipentId").val();
var senderId = $("#chat-order-add #senderId").val();
var orderId = $("#chat-order-add #orderId").val();
socket.add_contact_message({
"format_type": "add_message_order",
"data": {
"sender_id": senderId,
"recipent_id": recipentId,
"chat_message": chatMessage,
"order_id": orderId,
}
});
$("#chat-order-add #chat").val("");
});
});
var userId = '{{ request.user.pk }}';

@ -162,6 +162,18 @@
</div> </div>
<div class="stepssBlock box-sizing disTab" id="completeWork">
<p class="titleStepss">3 / Выполнение работы</p>
<p class="textStepss">
Процесс выполнения задания в заказе до получения
заказчиком итогового результата работы.
</p>
<div id="stagesWork" class="stages-work textAreaBlock2">
</div>
</div>
<div class="textAreaBlock2 box-sizing disTab"> <div class="textAreaBlock2 box-sizing disTab">
<ul class="notes-block"> <ul class="notes-block">
</ul> </ul>
@ -275,14 +287,6 @@
var form = document.getElementById('message_form'); var form = document.getElementById('message_form');
var csrftoken = getCookie('csrftoken'); var csrftoken = getCookie('csrftoken');
setTimeout(function () {
$(".user-block").first().trigger('click');
}, 10);
setTimeout(function () {
$(".order-block").first().trigger('click');
}, 100);
setTimeout(function () { setTimeout(function () {
$(".team-order-block").first().trigger('click'); $(".team-order-block").first().trigger('click');
}, 1000); }, 1000);
@ -454,9 +458,14 @@
console.log(json.results); console.log(json.results);
var htmlInbox = ""; var htmlInbox = "";
var stagesReservedHtml = ""; var stagesReservedHtml = "";
var stagesPaidProcess = [];
if (json.results.length > 0) { if (json.results.length > 0) {
$.each(json.results, function (i, v) { $.each(json.results, function (i, v) {
if ((v.status == "in_process") && (v.is_paid)){
stagesPaidProcess.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 {
@ -465,7 +474,7 @@
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.status + '</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>'; htmlInbox += '<div class="textAreaBlock2 FFD box-sizing disTab"><a id="approve-stages" href="#">согласовать</a></div>';
@ -473,6 +482,20 @@
$("#order-stages").html(htmlInbox); $("#order-stages").html(htmlInbox);
$(".stages-paid").html(stagesReservedHtml); $(".stages-paid").html(stagesReservedHtml);
if (stagesPaidProcess.length > 0){
$("#completeWork").show();
var stage = stagesPaidProcess[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>';
$("#stagesWork").html(stageWork);
}else{
$("#completeWork").hide();
}
} }
}); });
@ -500,6 +523,28 @@
}); });
}); });
$('#tab2').on('click','.closeStage', function(e){
e.preventDefault();
var stageId = $(this).attr('data-stage-id');
$.ajax({
url: '/api/stages/' + stageId + '/',
type: 'PATCH',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
data: "close_contractor=True",
dataType: 'json',
success: function (json) {
alert(json);
console.log(json);
},
error: function (e) {
console.log('error');
console.log(e);
}
});
});
// Вытащить сообщения для конактов // Вытащить сообщения для конактов

@ -106,7 +106,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.order.contractor.pk }}" data-id="{{ order.order.id }}"> id="orderBlock{{ order.order.id }}" data-secure-deal="{% if order.order.secure %}true{% else %}false{% endif %}" data-recipent-id="{{ order.order.contractor.pk }}" data-id="{{ order.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">
@ -156,7 +156,7 @@
<div id="order-stages" class="stepssBlock"></div> <div id="order-stages" class="stepssBlock"></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">
Резервирование заказчиком суммы оплаты по заказ. Деньги перечисляются и хранятся на Резервирование заказчиком суммы оплаты по заказ. Деньги перечисляются и хранятся на
@ -164,7 +164,7 @@
</p> </p>
<div class="textAreaBlock2 FFD box-sizing disTab"> <div class="textAreaBlock2 FFD box-sizing disTab">
<a href="#" id="reserve-button" data-order-id="" data-toggle="modal" data-target="#reserve-stage-modal">Зарезирвировать</a> <a href="#" id="reserve-button" data-order-id="">Зарезирвировать</a>
</div> </div>
</div> </div>
@ -173,12 +173,16 @@
{% include 'reverse_stage_modal.html' %} {% include 'reverse_stage_modal.html' %}
<!-- Конец блока --> <!-- Конец блока -->
<div class="stepssBlock box-sizing disTab"> <div class="stepssBlock box-sizing disTab" id="completeWork">
<p class="titleStepss">3 / Выполнение работы</p> <p class="titleStepss">3 / Выполнение работы</p>
<p class="textStepss"> <p class="textStepss">
Процесс выполнения задания в заказе до получения заказчиком итогового результата работы. Процесс выполнения задания в заказе до получения
</p> заказчиком итогового результата работы.
</div> </p>
<div id="stagesWork" class="stages-work textAreaBlock2">
</div>
</div>
<div class="textAreaBlock2 box-sizing disTab"> <div class="textAreaBlock2 box-sizing disTab">
@ -188,7 +192,7 @@
</div> </div>
<div class="closeChat closeChat1"> <div class="closeChat closeChat1" id="leaveReview" style="display: none;">
<a href="#" data-toggle="modal" data-target="#review-add"> <a href="#" data-toggle="modal" data-target="#review-add">
Закрыть проект<br>и оставить отзыв Закрыть проект<br>и оставить отзыв
</a> </a>
@ -197,54 +201,7 @@
<!-- Review add --> <!-- Review add -->
{% include 'review_add_modal.html' %}
<div id="review-add" class="modal fade" role="dialog">
<div class="modal-dialog" role="document" style="width:900px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×
</button>
<h4 class="modal-title">Оставить отзыв</h4>
</div>
<form id="review-adds-form" method="POST">{% csrf_token %}
<div class="modal-body">
<div style="height: 250px;">
<div class="text-nn box-sizing disTab">
<input type="radio" value="positive"
name="type">Положительный
<input type="radio" value="negative"
name="type">Отрицательный
<input type="radio" value="neutral"
name="type">Нейтральный
</div>
<div class="textAreaBlock2 text-nn box-sizing disTab">
<textarea cols="40" name="text" rows="10"></textarea>
<input type="hidden" name="from_customer"
value="{{ request.user.pk }}"/>
<input type="hidden" name="target_contractor"
id="targetContractorId"/>
<input type="hidden" name="project" id="projectReviewId"/>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть
</button>
<button type="submit" id="order-review-add" class="btn btn-primary">Оставить
отзыв
</button>
</div>
</form>
</div>
</div>
</div>
<!-- --> <!-- -->
</div> </div>
@ -273,20 +230,64 @@
var csrftoken = getCookie('csrftoken'); var csrftoken = getCookie('csrftoken');
$("#reserve-button").on("click",function(e) { $("#reserve-button").on("click",function(e) {
e.preventDefault(); e.preventDefault();
$("#reserve-stage-modal").modal('show');
var orderId = $(this).attr('data-order-id'); var orderId = $(this).attr('data-order-id');
$.ajax({
url: '/api/stages/', $.ajax({
type: 'GET', url: '/api/stages/',
data: {csrfmiddlewaretoken: csrftoken, 'order': orderId}, type: 'GET',
dataType: 'json', data: {csrfmiddlewaretoken: csrftoken, 'order': orderId},
success: function (json) { dataType: 'json',
console.log(json.results); success: function (json) {
} var outputValues = '';
}); var totalSum = 0;
var stagesIds = '';
$.each(json.results, function (i, v) {
console.log(v.cost);
totalSum += parseInt(v.cost);
outputValues += '<option data-stage-sum="' + v.cost + '" value="'+ v.id +'">' + v.name + '</option>';
stagesIds += v.id + ';'
});
$("#stagesSelect").html(outputValues);
$(".totalSum").text(totalSum);
$("#choiceWayOrder").val(totalSum)
$("#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);
$("#stages-pay-form #stagesIds").val($(this).val());
}); });
function getStages(orderId, senderId, recipentId) { //Получить заказы
function getStages(orderId, senderId, recipentId, secureOrder) {
$.ajax({ $.ajax({
url: '/api/stages/', url: '/api/stages/',
@ -296,6 +297,7 @@
success: function (json) { success: function (json) {
var stageCount = json.results.length; var stageCount = json.results.length;
if (stageCount == 0) { if (stageCount == 0) {
$("#reserveSpace").hide();
stageCountVal = 1; stageCountVal = 1;
} else { } else {
stageCountVal = stageCount; stageCountVal = stageCount;
@ -314,11 +316,17 @@
'<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '"/>' + '<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="term" type="text" />' +
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' + '<label for="">Результат</label><input class="form-control" name="result" type="text" />' +
'<label for="">Позиция</label><input class="form-control" name="pos" value="1" type="text" />' + '<input class="form-control" name="pos" value="1" type="hidden" />' +
'</form></div>'; '</form></div>';
} }
var statusNotAgreed = true; var statusNotAgreed = true;
var stagesPaidProcess = [];
$.each(json.results, function (i, v) { $.each(json.results, function (i, v) {
if ((v.status == "in_process") && (v.is_paid)){
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 + '">' +
@ -334,30 +342,73 @@
htmlInbox += '<div class="numberStepp box-sizing"><div class="insetNumStepp">' + htmlInbox += '<div class="numberStepp box-sizing"><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>до Дата</p><span>' + v.cost + '<i class="fa fa-rub"></i></span></div></div></div>'; '<p>до Дата</p><span>' + v.cost + '<i class="fa fa-rub"></i></span>' +
'</div></div></div>';
} }
}); });
if (statusNotAgreed) { if (statusNotAgreed) {
htmlInbox += '<div class="box-sizing disTab" style="text-align:center;"><div class="checkbox"><input type="checkbox" style="opacity:1">Перейти в режим безопасной сделки' + if(secureOrder) {
'</div></div><div class="textAreaBlock2 box-sizing disTab">' + var orderSecureCheckbox = 'checked="checked"';
'<a href="#" data-sender-id="' + senderId +'" data-recipent-id="' + recipentId +'" data-order-id="' + orderId + '" id="addStagesForm">отправить на согласование</a> </div>'; htmlInbox += '<div class="box-sizing disTab">' +
'<div class="checkbox"><input name="secure" id="secureOrder"'+ orderSecureCheckbox +'type="checkbox" style="opacity:1">' +
'Перейти в режим безопасной сделки</div></div>';
}
htmlInbox +='<div class="textAreaBlock2 box-sizing disTab">' +
'<a href="#" data-sender-id="' + senderId +'" ' +
'data-recipent-id="' + recipentId +'" data-order-id="' + orderId + '" ' +
'id="addStagesForm">отправить на согласование</a> </div>';
}else if(json.results.length>0){
$("#reserveSpace").show();
} }
htmlInbox = htmlInboxStage + htmlInbox; htmlInbox = htmlInboxStage + htmlInbox;
$("#order-stages").html(htmlInbox); $("#order-stages").html(htmlInbox);
if (stagesPaidProcess.length > 0){
$("#completeWork").show();
var stage = stagesPaidProcess[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>';
}
$("#stagesWork").html(stageWork);
}else{
$("#completeWork").hide();
}
} }
}); });
} }
setTimeout(function () { //Закрыть этап
$(".user-block").first().trigger('click'); $('#tab2').on('click','.closeStage', function(e){
}, 10); e.preventDefault();
var stageId = $(this).attr('data-stage-id');
$.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) {
console.log(json);
},
error: function (e) {
console.log('error');
console.log(e);
}
});
});
setTimeout(function () {
$(".order-block").first().trigger('click');
}, 100);
// Добавление этапов
$("#order-stages").on('click', "#addStagesForm", function (e) { $("#order-stages").on('click', "#addStagesForm", function (e) {
e.preventDefault(); e.preventDefault();
$(".new-stages-form").each(function (i, v) { $(".new-stages-form").each(function (i, v) {
@ -403,11 +454,10 @@
}); });
}); });
var currentOrderId = $(this).attr('data-order-id'); var currentOrderId = $(this).attr('data-order-id');
var currentRecipentId = $(this).attr('data-recipent-id'); var currentRecipentId = $(this).attr('data-recipent-id');
var secureOrder = true
getStages(currentOrderId,userId,currentRecipentId); getStages(currentOrderId,userId,currentRecipentId,secureOrder);
socket.send_stages_approve({ socket.send_stages_approve({
"format_type": "approve_stages", "format_type": "approve_stages",
@ -421,6 +471,7 @@
}); });
//Изменение счетчика
$('#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;
@ -437,11 +488,9 @@
'<input class="form-control orderStagesInput" name="order" type="hidden" value="' + orderId + '" />' + '<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="term" type="text" />' +
'<label for="">Результат</label><input class="form-control" name="result" type="text" />' + '<label for="">Результат</label><input class="form-control" name="result" type="text" />' +
'<label for="">Позиция</label><input class="form-control" name="pos" value="'+ pos +'" type="text" />' '<input class="form-control" name="pos" value="'+ pos +'" type="hidden" />'
'</form></div>'; '</form></div>';
lastFormStage.after(addFormTemplate); lastFormStage.after(addFormTemplate);
} }
}else if (countStage < currentCountStage) { }else if (countStage < currentCountStage) {
@ -456,6 +505,7 @@
} }
}); });
// Для заказов все вытащить
$('.order-block').on('click', function () { $('.order-block').on('click', function () {
$("#chat-order-add").css("display", "block"); $("#chat-order-add").css("display", "block");
$("#formsetStage").css("display", "block"); $("#formsetStage").css("display", "block");
@ -467,6 +517,8 @@
$(this).addClass('orAct'); $(this).addClass('orAct');
var orderId = $(this).attr('data-id'); var orderId = $(this).attr('data-id');
var recipentId = $(this).attr('data-recipent-id'); var recipentId = $(this).attr('data-recipent-id');
var secureOrder = $(this).attr('data-secure-deal');
secureOrder = Boolean(secureOrder);
$("#chat-order-add #orderId").val(orderId); $("#chat-order-add #orderId").val(orderId);
$("#projectReviewId").val(orderId); $("#projectReviewId").val(orderId);
$("#reserve-button").attr('data-order-id', orderId); $("#reserve-button").attr('data-order-id', orderId);
@ -496,7 +548,7 @@
}); });
} }
}); });
getStages(orderId,userId,recipentId); getStages(orderId,userId,recipentId, secureOrder);
}); });
// Вытащить сообщения для конактов // Вытащить сообщения для конактов
@ -557,8 +609,28 @@
$("#chat").val(""); $("#chat").val("");
}); });
$('#order-review-add').on('click', function () { // Добавление отзыва
alert('add review'); $('#order-review-add').on('click', function (e) {
e.preventDefault();
e.stopPropagation();
var formData = $("#review-adds-form").serialize();
$.ajax({
url: '/api/reviews/',
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))
},
data: formData,
dataType: 'json',
success: function (json) {
console.log("Успешно");
console.log(json);
},
error: function (e) {
console.log('error');
console.log(e);
}
});
}); });
$('#order-chat-add-message').on('click', function (e) { $('#order-chat-add-message').on('click', function (e) {

@ -12,13 +12,13 @@
<div class="searchF1 polsF1 polsFF radio-afer"> <div class="searchF1 polsF1 polsFF radio-afer">
<div class="col-lg-6"> <div class="col-lg-6">
<label> <label>
<input type="radio" name="choice_way" value="secure_deal"> <input data-stages-ids="" type="radio" checked="checked" id="choiceWayOrder"name="choice_way" value="">
<span></span> <span></span>
</label> </label>
<p class="text-afer">Сумма оплаты всего заказа</p> <p class="text-afer">Сумма оплаты всего заказа</p>
<p class="des-afer"> <p class="des-afer">
Общий бюджет заказа: 300 р. <br /> Общий бюджет заказа: <span class="totalSum" id="totalSum"></span>р. <br />
Итого к оплате: 344 рубля Итого к оплате: <span class="totalSum"></span> р.
</p> </p>
</div> </div>
</div> </div>
@ -26,28 +26,45 @@
<div class="searchF1 polsF1 polsFF radio-afer"> <div class="searchF1 polsF1 polsFF radio-afer">
<div class="col-lg-6"> <div class="col-lg-6">
<label> <label>
<input type="radio" name="choice_way" value="choice_way"> <input type="radio" name="choice_way" id="choiceWayStage" value="">
<span></span> <span></span>
</label> </label>
<p class="text-afer">Оплатить этап</p><br /> <p class="text-afer" style="width: 250px;">Оплатить этап</p><br />
<p class="des-afer"> <p class="des-afer">
Бюджет Этапа 1: 300 р.<br /> Бюджет Этапа 1: <span class="stageSum"></span>р.<br />
Итого к оплате: 344 р. Итого к оплате: <span class="stageSum"></span> р.
</p> </p>
</div> </div>
<div class="col-lg-6"> <div class="col-lg-6">
<select class="selectpicker"> <select id="stagesSelect">
<option>Этап1</option>
<option>Этап1</option>
<option>Этап1</option>
</select> </select>
</div> </div>
</div> </div>
<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 %}
<div class="modal-body">
<div style="height: 150px;">
<div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Кол-во денег {{ transaction.pk }} </p>
<input type="text" name="sum" id="stageSumPay">
<input type='hidden' name='shopId' value='{{ YANDEX_MONEY.shop_id }}'>
<input type='hidden' name='scid' value='{{ YANDEX_MONEY.scid }}'>
<input type='hidden' name='customerNumber' value='{{ user_score.pk }}'>
<input type='hidden' name='paymentType' value='AC'>
<input type='hidden' name='transactionId' value='{{ transaction.pk }}'>
<input type='text' name='stagesId' id='stagesIds' value=''>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Пополнить</button>
</div>
</form>
</div> </div>
</div> </div>

@ -0,0 +1,49 @@
<div id="review-add" class="modal fade" role="dialog">
<div class="modal-dialog" role="document" style="width:900px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×
</button>
<h4 class="modal-title">Оставить отзыв</h4>
</div>
<form id="review-adds-form" method="POST">
<div class="modal-body">
<div style="height: 250px;">
<div class="searchF1 polsF1 polsFF radio-afer">
<input type="radio" value="positive"
name="type">Положительный
<input type="radio" value="negative"
name="type">Отрицательный
<input type="radio" value="neutral"
name="type">Нейтральный
</div>
<div class="textAreaBlock2 text-nn box-sizing disTab">
<p>Ваш отзыв</p>
<textarea id="text-new" name="text"></textarea>
<input type="hidden" name="from_customer" value="{{ request.user.pk }}"/>
<input type="hidden" name="target_contractor" id="targetContractorId"/>
<input type="hidden" name="project" id="projectReviewId"/>
<input type="hidden" name="target_team">
<input type="hidden" name="target_customer">
<input type="hidden" name="from_contractor">
<input type="hidden" name="from_team">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть
</button>
<button type="button" id="order-review-add" class="btn btn-primary">Оставить
отзыв
</button>
</div>
</form>
</div>
</div>
</div>

@ -1,5 +1,6 @@
import json import json
from django.shortcuts import render from django.shortcuts import render
from django.conf import settings
from django.views.generic import View from django.views.generic import View
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
from django.db.models import Q from django.db.models import Q
@ -7,6 +8,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Message from .models import Message
from projects.models import Order from projects.models import Order
from wallets.models import Transaction
from users.models import User, Team from users.models import User, Team
@ -16,7 +18,7 @@ class ChatUserView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))
user_id = request.GET.get('user_id',None) user_id = request.GET.get('user_id',None)
if request.user.is_authenticated() and request.user.is_customer(): if request.user.is_customer():
customer_contacts = Message.objects.values_list('sender_id', 'recipent_id'). \ customer_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)).distinct() filter(Q(recipent_id=request.user.pk) | Q(sender_id=request.user.pk)).filter(Q(team_id=None)).distinct()
@ -34,10 +36,15 @@ class ChatUserView(LoginRequiredMixin, View):
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.projects.select_related('order').exclude(order__contractor__isnull=True) orders = request.user.projects.select_related('order').exclude(order__contractor__isnull=True)
transaction = Transaction.objects.get_or_create(customer=request.user, type='reservation')
print(transaction)
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,
'orders': orders}) 'orders': orders,
'transaction': transaction[0],
'YANDEX_MONEY': settings.YANDEX_MONEY,
})
else: else:
orders = request.user.orders.all() orders = request.user.orders.all()
contractor_contacts = Message.objects.values_list('sender_id', 'recipent_id').filter( contractor_contacts = Message.objects.values_list('sender_id', 'recipent_id').filter(
@ -60,13 +67,13 @@ class ChatUserView(LoginRequiredMixin, View):
else: else:
teams = Team.objects.filter(contractors__id=request.user.pk).all() 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() team_orders = Order.objects.filter(team_id__in=[team.pk for team in teams]).all()
# team_orders = []
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,
'chat_messages': chat_messages, 'chat_messages': chat_messages,
'team_orders': team_orders, 'team_orders': team_orders,
}) })

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-23 22:54
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0013_auto_20160819_1735'),
]
operations = [
migrations.AlterModelOptions(
name='project',
options={'ordering': ('-created',), 'verbose_name': 'Проект', 'verbose_name_plural': 'Проекты'},
),
migrations.AddField(
model_name='stage',
name='close_contractor',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='stage',
name='close_customer',
field=models.BooleanField(default=False),
),
]

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-24 08:19
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0014_auto_20160824_0154'),
]
operations = [
migrations.AlterField(
model_name='order',
name='status',
field=models.CharField(choices=[('created', 'Создан'), ('process', 'В процессе'), ('completed', 'Завершен')], default='created', max_length=30),
),
]

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-24 14:23
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('projects', '0015_auto_20160824_1538'),
('projects', '0015_auto_20160824_1119'),
]
operations = [
]

@ -199,12 +199,17 @@ class AnswerFile(models.Model):
class Order(models.Model): class Order(models.Model):
STATUSES = (
('created', 'Создан'),
('process', 'В процессе'),
('completed', 'Завершен'),
)
contractor = models.ForeignKey(User, null=True, blank=True, related_name='orders') contractor = models.ForeignKey(User, null=True, blank=True, related_name='orders')
team = models.ForeignKey(Team, null=True, blank=True, related_name='orders') team = models.ForeignKey(Team, null=True, blank=True, related_name='orders')
created = models.DateTimeField(default=timezone.now) created = models.DateTimeField(default=timezone.now)
project = models.OneToOneField(Project, related_name='order') project = models.OneToOneField(Project, related_name='order')
secure = models.BooleanField(default=False) secure = models.BooleanField(default=False)
status = models.BooleanField(default=False) status = models.CharField(max_length=30, choices=STATUSES, default='created')
def __str__(self): def __str__(self):
return self.project.name return self.project.name
@ -233,6 +238,8 @@ class Stage(models.Model):
created = models.DateTimeField(default=timezone.now) created = models.DateTimeField(default=timezone.now)
pos = models.IntegerField(default=0, null=True, blank=True) pos = models.IntegerField(default=0, null=True, blank=True)
is_paid = models.BooleanField(default=False) is_paid = models.BooleanField(default=False)
close_contractor = models.BooleanField(default=False)
close_customer = models.BooleanField(default=False)
def __str__(self): def __str__(self):
return self.name return self.name

@ -80,6 +80,8 @@ class StageSerializer(ModelSerializer):
'pos', 'pos',
'status', 'status',
'is_paid', 'is_paid',
'close_contractor',
'close_customer',
) )

@ -357,8 +357,12 @@ class CustomerProjectCreateView(BaseMixin, View):
project.save() project.save()
form.save_m2m() form.save_m2m()
Order.objects.create(project=project) secure = False
if 'secure_deal' in project.deal_type:
secure = True
Order.objects.create(project=project, secure=secure)
for file in request.FILES.getlist('new_files'): for file in request.FILES.getlist('new_files'):
ProjectFile.objects.create(file=file, project=project) ProjectFile.objects.create(file=file, project=project)

@ -41,3 +41,4 @@ django-mathfilters
gunicorn==19.6.0 gunicorn==19.6.0
rest-framework-generic-relations rest-framework-generic-relations
django-hitcount django-hitcount
django-activeurl==0.1.9

@ -1,6 +1,7 @@
{% load staticfiles %} {% load staticfiles %}
{% load thumbnail %} {% load thumbnail %}
{% load user_tags %} {% load user_tags %}
{% load activeurl %}
<div class="wrTop {% if request.user.is_authenticated %} disTab {% endif %}"> <div class="wrTop {% if request.user.is_authenticated %} disTab {% endif %}">
<div class="container-fluid topMain"> <div class="container-fluid topMain">
@ -8,7 +9,7 @@
<div class="col-lg-3"> <div class="col-lg-3">
<div class="logo" onClick="window.location='/'"></div> <div class="logo" onClick="window.location='/'"></div>
</div> </div>
{% activeurl %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div class="col-lg-7"> <div class="col-lg-7">
<ul class="mainMenu"> <ul class="mainMenu">
@ -54,7 +55,7 @@
</ul> </ul>
</div> </div>
{% endif %} {% endif %}
{% endactiveurl %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div class="col-lg-2"> <div class="col-lg-2">
<div class="imgProfile"> <div class="imgProfile">

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-24 12:53
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wallets', '0008_wallet'),
]
operations = [
migrations.AddField(
model_name='transaction',
name='stages_id',
field=models.CharField(blank=True, max_length=100, null=True),
),
]

@ -70,6 +70,7 @@ class Transaction(models.Model):
voids_at = models.DateTimeField() voids_at = models.DateTimeField()
sum = models.DecimalField(max_digits=20, decimal_places=0, default=0) sum = models.DecimalField(max_digits=20, decimal_places=0, default=0)
type = models.CharField(max_length=20, choices=TYPES, default='add') type = models.CharField(max_length=20, choices=TYPES, default='add')
stages_id = models.CharField(max_length=100, null=True, blank=True)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.pk and self.created_at: if not self.pk and self.created_at:

@ -33,13 +33,14 @@ class ScoreView(LoginRequiredMixin, View):
template_name = 'score-detail.html' template_name = 'score-detail.html'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
transaction = Transaction.objects.create(customer=request.user, type='add') # transaction = Transaction.objects.get_or_create(customer=request.user, complete=False)
transaction = Transaction.objects.get_or_create(customer=request.user, type='add')
user_score = get_object_or_404(User.objects, pk=kwargs.get('pk')) user_score = get_object_or_404(User.objects, pk=kwargs.get('pk'))
current_sum_info = InvoiceHistory.objects.filter(user=user_score).aggregate(Sum('sum')) current_sum_info = InvoiceHistory.objects.filter(user=user_score).aggregate(Sum('sum'))
user_score_balance = current_sum_info['sum__sum'] or 0 user_score_balance = current_sum_info['sum__sum'] or 0
return render(request, self.template_name, { return render(request, self.template_name, {
'transaction': transaction, 'transaction': transaction[0],
'YANDEX_MONEY': settings.YANDEX_MONEY, 'YANDEX_MONEY': settings.YANDEX_MONEY,
'user_score': user_score, 'user_score': user_score,
'user_score_balance': user_score_balance, 'user_score_balance': user_score_balance,

Loading…
Cancel
Save