#ARC-9 Open projects

remotes/origin/PR-39
ArturBaybulatov 10 years ago
parent 71dd79518f
commit 5f1bb1d406
  1. 5
      common/templatetags/common_tags.py
  2. 6
      projects/templates/project_detail.html
  3. 35
      projects/templates/project_filter.html
  4. 10
      projects/templatetags/project_tags.py
  5. 18
      projects/views.py
  6. 75
      users/templates/contractor_office_open_projects.html
  7. 4
      users/urls.py
  8. 45
      users/views.py

@ -76,6 +76,11 @@ def basename(val):
return os.path.basename(val) return os.path.basename(val)
@register.filter
def pk(obj):
return obj.pk
@register.simple_tag @register.simple_tag
def lorem(*args, **kwargs): def lorem(*args, **kwargs):
return util.lorem(*args, **kwargs) return util.lorem(*args, **kwargs)

@ -248,7 +248,7 @@
<form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}"> <input type="hidden" name="next" value="{{ request.path }}">
<a href="#" onclick="$(this).closest('form').submit(); return false" class="candLink candLink3">отказ</a> <a href="#" onclick="$(this).closest('form').submit(); return false" class="candLink candLink3" title="{{ answer.pk }}">отказ</a>
</form> </form>
</div> </div>
@ -593,7 +593,7 @@
<form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}"> <input type="hidden" name="next" value="{{ request.path }}">
<a href="#" onclick="$(this).closest('form').submit(); return false" class="candLink candLink3">отказ</a> <a href="#" onclick="$(this).closest('form').submit(); return false" class="candLink candLink3" title="{{ answer.pk }}">отказ</a>
</form> </form>
</div> </div>
@ -747,7 +747,7 @@
<form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate> <form action="{% url 'projects:reject-project-answer' pk=answer.pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}"> <input type="hidden" name="next" value="{{ request.path }}">
<a href="#" onclick="$(this).closest('form').submit(); return false" class="candLink candLink3">отказ</a> <a href="#" onclick="$(this).closest('form').submit(); return false" class="candLink candLink3" title="{{ answer.pk }}">отказ</a>
</form> </form>
</div> </div>

@ -173,54 +173,55 @@
<div class="projectsBlock disTab"> <div class="projectsBlock disTab">
{% for proj in projects %} {% for project in projects %}
<div class="projectPro clearfix"> <div class="projectPro clearfix">
<div class="col-lg-9 leftPro"> <div class="col-lg-9 leftPro">
<p class="titlePro"> <p class="titlePro">
<a href="{% url 'projects:detail' pk=proj.pk %}">{{ proj }}</a> <a href="{% url 'projects:detail' pk=project.pk %}">{{ project.name }}</a>
</p> </p>
<ul class="desPro"> <ul class="desPro">
<li> <li>
Объект "{{ proj.realty.name }}" Объект "{{ project.realty.name }}"
</li> </li>
</ul> </ul>
<p class="textPro">{{ proj.text|linebreaksbr|truncatechars:300 }}</p>
<p class="textPro">{{ project.text|linebreaksbr|truncatechars:300 }}</p>
{% if TEMPLATE_DEBUG %} {% if TEMPLATE_DEBUG %}
<pre><!-- <pre><!--
-->{{ proj|inspect }}<br><!-- --><b>Specialization:</b> {{ project.specialization }}<br><!--
--><br><!-- --><br><!--
--><b>Specialization:</b> {{ proj.specialization }}<br><!-- --><b>Realty location:</b> {{ project.realty.location }}<br><!--
--><br><!-- --><br><!--
--><b>Realty location:</b> {{ proj.realty.location }}<br><!-- --><b>Constr. type:</b> {{ project.realty.construction_type }}<br><!--
--><br><!-- --><br><!--
--><b>Constr. type:</b> {{ proj.realty.construction_type }}<br><!-- --><b>Build. classif.:</b> {{ project.realty.building_classification }}<br><!--
--><br><!--
--><b>Build. classif.:</b> {{ proj.realty.building_classification }}<br><!--
--></pre> --></pre>
{% endif %} {% endif %}
<ul class="listPro"> <ul class="listPro">
<li>{{ proj.created }}</li> <li>{{ project.created }}</li>
<li>{{ proj.hit_count.hits }}</li> <li>{{ project.hit_count.hits }}</li>
<li>{{ proj.answers.count }}</li> <li>{{ project.answers.count }}</li>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<li>{{ proj.customer.username }}</li> <li>{{ project.customer.username }}</li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>
<div class="col-lg-3 rightPro"> <div class="col-lg-3 rightPro">
<p class="cenaPro"> <p class="cenaPro">
{{ proj.budget }} <i class="fa fa-rub"></i> {{ project.budget }} <i class="fa fa-rub"></i>
</p> </p>
<ul> <ul>
{% if proj.secure_deal %} {% if project.secure_deal %}
<li>Безопасная сделка</li> <li>Безопасная сделка</li>
{% endif %} {% endif %}
<li> <li>
{{ proj.specialization.name }} {{ project.specialization.name }}
</li> </li>
</ul> </ul>
</div> </div>

@ -1,5 +1,6 @@
from django import template from django import template
from pprint import pprint, pformat from pprint import pprint, pformat
import pydash as _; _.map = _.map_; _.filter = _.filter_
from archilance import util from archilance import util
@ -22,5 +23,14 @@ def get_candidate_answers(project):
def get_rejected_answers(project): def get_rejected_answers(project):
return project.answers.filter(rejected=True) return project.answers.filter(rejected=True)
@register.filter
def get_answer(project, contractor):
answer = _.find(project.answers.all(), lambda a: a.author == contractor)
if not answer:
answer = _.find(project.answers.all(), lambda a: a.author == contractor.team)
return answer
# import code; code.interact(local=dict(globals(), **locals())) # import code; code.interact(local=dict(globals(), **locals()))

@ -19,6 +19,7 @@ import re
from .mixins import LastAccessMixin from .mixins import LastAccessMixin
from .models import Project, ProjectFile, Portfolio, PortfolioPhoto, Candidate, Answer, AnswerFile, AnswerMessage, Realty, Order from .models import Project, ProjectFile, Portfolio, PortfolioPhoto, Candidate, Answer, AnswerFile, AnswerMessage, Realty, Order
from archilance import util
from archilance.mixins import BaseMixin from archilance.mixins import BaseMixin
from users.models import User, Team from users.models import User, Team
from work_sell.models import Picture, WorkSell, WorkSellPhoto from work_sell.models import Picture, WorkSell, WorkSellPhoto
@ -187,16 +188,25 @@ class RejectProjectAnswerView(BaseMixin, View):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
if request.user.is_contractor(): if request.user.is_contractor():
answer = get_object_or_404(request.user.contractor_answers, pk=kwargs.get('pk')) answer = None
contractor_answer = util.get_or_none(request.user.contractor_answers, pk=kwargs.get('pk'))
if contractor_answer:
answer = contractor_answer
elif request.user.team:
answer = util.get_or_none(request.user.team.answers, pk=kwargs.get('pk'))
if not answer:
raise Http404
elif request.user.is_customer(): elif request.user.is_customer():
project = get_object_or_404(request.user.projects, answers__pk=kwargs.get('pk')) project = get_object_or_404(request.user.projects, answers__pk=kwargs.get('pk'))
answer = get_object_or_404(project.answers, pk=kwargs.get('pk')) answer = get_object_or_404(project.answers, pk=kwargs.get('pk'))
answer.rejected = True answer.rejected = True
answer.save() answer.save()
messages.info(request, 'Успешный отказ от проекта') messages.info(request, 'Успешный отказ от проекта')
redirect_to = request.POST.get('next') redirect_to = request.POST.get('next')
return redirect(redirect_to) return redirect(redirect_to)

@ -1,5 +1,6 @@
{% extends 'partials/base.html' %} {% extends 'partials/base.html' %}
{% load project_tags %}
{% load specializtions_tags %} {% load specializtions_tags %}
{% load thumbnail %} {% load thumbnail %}
@ -17,18 +18,18 @@
<div class="buttonGP disTab"> <div class="buttonGP disTab">
<div class="btn-group valProject2" role="group"> <div class="btn-group valProject2" role="group">
<a href="#" onclick="query('owner', ''); return false" class="btn btn-default">Все</a> <a href="#" data-param-name="owner" data-default onclick="return false" class="btn btn-default -nav">Все</a>
<a href="#" onclick="query('owner', 'private'); return false" class="btn btn-default">Личные</a> <a href="#" data-param-name="owner" data-param-val="private" onclick="return false" class="btn btn-default -nav">Личные</a>
<a href="#" onclick="query('owner', 'teams'); return false" class="btn btn-default">От именни группы</a> <a href="#" data-param-name="owner" data-param-val="teams" onclick="return false" class="btn btn-default -nav">От именни группы</a>
</div> </div>
<div class="btn-group valProject2" role="group"> <div class="btn-group valProject2" role="group">
<a href="#" onclick="query('archived', ''); return false" class="btn btn-default"> <a href="#" data-param-name="archived" data-default onclick="return false" class="btn btn-default -nav">
Открытые проекты Открытые проекты
<span><mark>0</mark> / <span>{{ active_project_count }}</span></span> <span><mark>0</mark> / <span>{{ active_project_count }}</span></span>
</a> </a>
<a href="#" onclick="query('archived', 'on'); return false" class="btn btn-default"> <a href="#" data-param-name="archived" data-param-val="on" onclick="return false" class="btn btn-default -nav">
Архив Архив
<span><mark></mark><span>{{ archived_project_count }}</span></span> <span><mark></mark><span>{{ archived_project_count }}</span></span>
</a> </a>
@ -53,13 +54,15 @@
<pre><!-- <pre><!--
--><b>State:</b> {{ project.state }}<br><!-- --><b>State:</b> {{ project.state }}<br><!--
--><br><!-- --><br><!--
--><b>Specialization:</b> {{ proj.specialization }}<br><!-- --><b>Specialization:</b> {{ project.specialization }}<br><!--
--><br><!-- --><br><!--
--><b>Realty location:</b> {{ proj.realty.location }}<br><!-- --><b>Answer author:</b> {{ project|get_answer:contractor }}<br><!--
--><br><!-- --><br><!--
--><b>Constr. type:</b> {{ proj.realty.construction_type }}<br><!-- --><b>Realty location:</b> {{ project.realty.location }}<br><!--
--><br><!-- --><br><!--
--><b>Build. classif.:</b> {{ proj.realty.building_classification }}<br><!-- --><b>Constr. type:</b> {{ project.realty.construction_type }}<br><!--
--><br><!--
--><b>Build. classif.:</b> {{ project.realty.building_classification }}<br><!--
--></pre> --></pre>
{% endif %} {% endif %}
@ -85,13 +88,14 @@
{{ project.specialization.name }} {{ project.specialization.name }}
</li> </li>
<li> <li class="-hide-if-archived" style="display: none">
<form action="{% url 'projects:contractor-answer-archive' %}" method="POST" novalidate> <form action="{% url 'projects:reject-project-answer' pk=project|get_answer:contractor|pk %}" method="POST" novalidate>
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}"> <input type="hidden" name="next" value="{{ request.path }}">
<input type="hidden" name="project_pk" value="{{ project.pk }}">
<input type="hidden" name="user_pk" value="{{ contractor.pk }}"> <a href="#" onclick="$(this).closest('form').submit(); return false" title="{{ project|get_answer:contractor|pk }}">
<a href="#" onclick="$(this).closest('form').submit(); return false">Отказаться и переместить в архив</a> Отказаться и переместить в архив
</a>
</form> </form>
</li> </li>
</ul> </ul>
@ -103,12 +107,45 @@
{% include 'partials/footer.html' %} {% include 'partials/footer.html' %}
</div> </div>
</div> </div>
{% endblock %}
{% block js_block %}
<script> <script>
function query(paramName, paramVal) { (function() {
var $navLinks = $('a.-nav')
var urlObj = new URI(window.location.href) var urlObj = new URI(window.location.href)
paramVal === '' ? urlObj.removeQuery(paramName) : urlObj.setQuery(paramName, paramVal) var query = urlObj.query(true)
window.location.href = urlObj.href()
} $('[data-default]').addClass('_defaultActive')
$navLinks.each(function(i, link) {
var $link = $(link)
var paramName = $link.data('paramName')
var paramVal = $link.data('paramVal')
if (query[paramName] === paramVal) {
$link.addClass('active')
$('[data-param-name="' + paramName + '"][data-default]').removeClass('_defaultActive')
}
})
$navLinks.filter('._defaultActive').addClass('active')
$navLinks.on('click', function($evt) {
var $link = $(this)
var paramName = $link.data('paramName')
var paramVal = $link.data('paramVal')
paramVal ? urlObj.setQuery(paramName, paramVal) : urlObj.removeQuery(paramName)
window.location.href = urlObj.href()
})
//---------------------------------------------------
if (query.archived !== 'on')
$('.-hide-if-archived').css('display', 'block')
}())
</script> </script>
{% endblock %} {% endblock %}

@ -6,7 +6,7 @@ from .views import (
contractor_resumefile_create, contractor_resumefile_create,
ContractorFilterView, ContractorFilterView,
ContractorOfficeDetailView, ContractorOfficeDetailView,
ContractorOfficeOpenProjectsView, ContractorOfficeProjectsView,
ContractorProfileDetailView, ContractorProfileDetailView,
ContractorResumeUpdateView, ContractorResumeUpdateView,
CustomerProfileCurrentProjectsView, CustomerProfileCurrentProjectsView,
@ -36,5 +36,5 @@ urlpatterns = [
urls.url(r'^contractorsresumefiles/create/$', contractor_resumefile_create, name='contractor-resume-file-create'), urls.url(r'^contractorsresumefiles/create/$', contractor_resumefile_create, name='contractor-resume-file-create'),
urls.url(r'^contractors/(?P<pk>\d+)/$', ContractorProfileDetailView.as_view(), name='contractor-profile'), urls.url(r'^contractors/(?P<pk>\d+)/$', ContractorProfileDetailView.as_view(), name='contractor-profile'),
urls.url(r'^contractor-office/(?P<pk>\d+)/$', ContractorOfficeDetailView.as_view(), name='contractor-office'), urls.url(r'^contractor-office/(?P<pk>\d+)/$', ContractorOfficeDetailView.as_view(), name='contractor-office'),
urls.url(r'^contractor-office/(?P<pk>\d+)/open-projects/$', ContractorOfficeOpenProjectsView.as_view(), name='contractor-office-open-projects'), urls.url(r'^contractor-office/(?P<pk>\d+)/open-projects/$', ContractorOfficeProjectsView.as_view(), name='contractor-office-open-projects'),
] ]

@ -381,7 +381,7 @@ class ContractorOfficeDetailView(DetailView):
return context return context
class ContractorOfficeOpenProjectsView(BaseMixin, View): class ContractorOfficeProjectsView(BaseMixin, View):
template_name = 'contractor_office_open_projects.html' template_name = 'contractor_office_open_projects.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
@ -397,31 +397,36 @@ class ContractorOfficeOpenProjectsView(BaseMixin, View):
contractor = get_object_or_404(User.contractor_objects, pk=kwargs.get('pk')) contractor = get_object_or_404(User.contractor_objects, pk=kwargs.get('pk'))
context['contractor'] = contractor context['contractor'] = contractor
private_projects = tuple(a.project for a in contractor.contractor_answers.all()) # TODO: Show projects only with "active" state
private_project_count = len(private_projects)
team_projects = tuple(a.project for a in contractor.team.answers.all()) private_open_projects = tuple(a.project for a in contractor.contractor_answers.filter(project__state='active', rejected=False))
team_project_count = len(team_projects) private_archived_projects = tuple(a.project for a in contractor.contractor_answers.filter(project__state='active', rejected=True))
context['all_project_count'] = private_project_count + team_project_count team_open_projects = tuple(a.project for a in contractor.team.answers.filter(project__state='active', rejected=False))
team_archived_projects = tuple(a.project for a in contractor.team.answers.filter(project__state='active', rejected=True))
if request.GET.get('owner') == 'private': context['all_project_count'] = \
projects = private_projects len(private_open_projects) + len(private_archived_projects) + \
elif request.GET.get('owner') == 'teams': len(team_open_projects) + len(team_archived_projects)
projects = team_projects
else:
projects = itertools.chain(private_projects, team_projects)
active_projects = _.filter(projects, lambda p: p.state == 'active') context['open_project_count'] = len(private_open_projects) + len(team_open_projects)
context['active_project_count'] = len(active_projects) context['archived_project_count'] = len(private_archived_projects) + len(team_archived_projects)
archived_projects = _.filter(projects, lambda p: p.state == 'trashed') if request.GET.get('owner') == 'private':
context['archived_project_count'] = len(archived_projects) if request.GET.get('archived') == 'on':
projects = private_archived_projects
if request.GET.get('archived') == 'on': else:
projects = archived_projects projects = private_open_projects
elif request.GET.get('owner') == 'teams':
if request.GET.get('archived') == 'on':
projects = team_archived_projects
else:
projects = team_open_projects
else: else:
projects = active_projects if request.GET.get('archived') == 'on':
projects = itertools.chain(private_archived_projects, team_archived_projects)
else:
projects = itertools.chain(private_open_projects, team_open_projects)
context['projects'] = projects context['projects'] = projects

Loading…
Cancel
Save