remotes/origin/PR-39
ArturBaybulatov 10 years ago
parent 60a38e7499
commit f43bb85af4
  1. 8
      archilance/management/commands/generate_work_sells.py
  2. 8
      users/models.py
  3. 13
      users/templates/contractor_office.html
  4. 6
      users/templates/contractor_profile.html
  5. 517
      users/templates/team_profile.html
  6. 7
      users/urls.py
  7. 46
      users/views.py
  8. 1
      work_sell/filters.py
  9. 22
      work_sell/migrations/0010_worksell_team.py
  10. 1
      work_sell/models.py
  11. 4
      work_sell/serializers.py

@ -9,7 +9,7 @@ from archilance import util
from common.models import Location from common.models import Location
from projects.models import TERM_TYPES, CURRENCIES, BuildingClassfication, ConstructionType from projects.models import TERM_TYPES, CURRENCIES, BuildingClassfication, ConstructionType
from specializations.models import Specialization from specializations.models import Specialization
from users.models import User from users.models import User, Team
from work_sell.models import WorkSell, WorkSellPhoto from work_sell.models import WorkSell, WorkSellPhoto
@ -32,7 +32,11 @@ class Command(BaseCommand):
ws.save() ws.save()
ws.user = User.contractor_objects.order_by('?').first() if _.sample((True, False)):
ws.contractor = User.contractor_objects.order_by('?').first()
else:
ws.team = Team.objects.order_by('?').first()
ws.building_classification = BuildingClassfication.objects.order_by('?').first() ws.building_classification = BuildingClassfication.objects.order_by('?').first()
ws.construction_type = ConstructionType.objects.order_by('?').first() ws.construction_type = ConstructionType.objects.order_by('?').first()
ws.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first() ws.location = Location.objects.root_nodes()[0].get_descendants().order_by('?').first()

@ -220,12 +220,16 @@ class User(AbstractBaseUser, PermissionsMixin):
def get_popular_specialization(self): def get_popular_specialization(self):
from ratings.models import SpecializationRating from ratings.models import SpecializationRating
return SpecializationRating.objects.filter(user=self).order_by('position').first().specialization.name
rating = SpecializationRating.objects.filter(user=self).order_by('position').first()
if rating:
return rating.specialization.name
class Team(models.Model): class Team(models.Model):
answers = GenericRelation('projects.Answer', related_query_name='teams') answers = GenericRelation('projects.Answer', related_query_name='teams')
avatar = models.ImageField(upload_to='teams/avatars/', blank=True) avatar = models.ImageField(upload_to='teams/avatars/', blank=True) # TODO: Unused field?
created = models.DateTimeField(default=timezone.now) created = models.DateTimeField(default=timezone.now)
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
owner = models.OneToOneField(User, related_name='team', blank=True, null=True) owner = models.OneToOneField(User, related_name='team', blank=True, null=True)

@ -82,7 +82,7 @@
<div class="block-users"> <div class="block-users">
<p>Состав группы</p> <p>Состав группы</p>
{% for c in team_members %} {% for c in contractor.team.contractors.all %}
<div class="message-new"> <div class="message-new">
<div class="imgMess"> <div class="imgMess">
{% if c.avatar %} {% if c.avatar %}
@ -114,7 +114,7 @@
<p class="navv">На сайте {{ contractor.team.created }}</p> <p class="navv">На сайте {{ contractor.team.created }}</p>
<p class="navv"> <p class="navv">
Кол-во человек: <span>{{ team_member_count }}</span> Кол-во человек: <span>{{ contractor.team.contractors.count }}</span>
</p> </p>
<p class="navv"> <p class="navv">
@ -261,17 +261,18 @@
var $moreWorkSellsfBtn = $('.-more-work-sells-btn').first() var $moreWorkSellsfBtn = $('.-more-work-sells-btn').first()
var workSellAbsUrl = '/work_sell/' var workSellAbsUrl = '/work_sell/'
var contractorId = {{ contractor.pk }}
var teamId = {{ contractor.team.pk }} var teamId = {{ contractor.team.pk }}
var contractorIds var contractorIds = [contractorId]
var portfUrl = new URI('/api/portfolios/') var portfUrl = new URI('/api/portfolios/')
var workSellUrl = new URI('/api/work-sells/') var workSellUrl = new URI('/api/work-sells/')
var pageSize = 3 var pageSize = 3
$.get('/api/teams/' + teamId + '/').then(function(res) { $.get('/api/teams/' + teamId + '/').then(function(res) {
contractorIds = _.map(function(contractor) { Array.prototype.push.apply(contractorIds, _.map(function(contractor) {
return contractor.id return contractor.id
}, res.contractors) }, res.contractors))
}) })
.then(loadMorePortfolios) .then(loadMorePortfolios)
.then(loadMoreWorkSells) .then(loadMoreWorkSells)
@ -305,7 +306,7 @@
function loadMoreWorkSells() { function loadMoreWorkSells() {
var query = workSellUrl.query(true) var query = workSellUrl.query(true)
workSellUrl.setQuery('contractor__in', _.join(',', contractorIds)) workSellUrl.setQuery('contractor', contractorId)
workSellUrl.setQuery('page_size', pageSize) workSellUrl.setQuery('page_size', pageSize)
workSellUrl.setQuery('page', query.page ? Number(query.page) + 1 : 2) workSellUrl.setQuery('page', query.page ? Number(query.page) + 1 : 2)

@ -101,7 +101,7 @@
<h4 class="modal-title">Контакты владельца </h4> <h4 class="modal-title">Контакты владельца </h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="row" style="height: 100px;"> <div class="row" style="height: 140px;">
<div class="col-lg-8 col-lg-offset-1"> <div class="col-lg-8 col-lg-offset-1">
<ul class="list-summ"> <ul class="list-summ">
{% if contractor.website %} {% if contractor.website %}
@ -113,6 +113,10 @@
{% if contractor.phone %} {% if contractor.phone %}
<li>{{ contractor.phone }}</li> <li>{{ contractor.phone }}</li>
{% endif %} {% endif %}
{% if contractor.phone2 %}
<li>{{ contractor.phone2 }}</li>
{% endif %}
</ul> </ul>
</div> </div>
</div> </div>

@ -0,0 +1,517 @@
{% extends 'partials/base.html' %}
{% load specializtions_tags %}
{% load thumbnail %}
{% block content %}
{% include 'partials/header.html' %}
<div class="container mainScore mainBlock2">
<div class="row">
<div class="col-lg-12">
<div class="col-lg-3 divCol3">
<div class="avatar">
<div class="avatarInset">
{% if team.owner.avatar %}
{% thumbnail team.owner.avatar "265x264" crop="center" as im %}
<img src="{{ im.url }}" alt="profile-image">
{% endthumbnail %}
{% else %}
<img src="{% static 'img/profile.jpg' %}" alt="profile-image">
{% endif %}
</div>
</div>
<div class="menuUser disTab">
<a href="{% url 'users:contractor-filter' %}" class="add-man">
добавить участника
</a>
<div class="block-users">
<p>Состав группы</p>
{% for c in team.contractors.all %}
<div class="message-new">
<div class="imgMess">
{% if c.avatar %}
{% thumbnail c.avatar "60x60" crop="center" as im %}
<img src="{{ im.url }}" alt="mess-image">
{% endthumbnail %}
{% else %}
<img src="{% static 'img/profile.jpg' %}" alt="mess-image">
{% endif %}
</div>
<p class="nameMess" style="float: none">
<a href="{% url 'users:contractor-profile' c.pk %}">{{ c.get_full_name }}</a>
</p>
<p><span>{{ c.get_popular_specialization }}</span></p>
</div>
{% empty %}
В группе пока нет участников
{% endfor %}
</div>
</div>
</div>
<div class="col-lg-9 divCol9">
<div class="col-lg-4">
<p class="nameUser">{{ team.name }}</p>
<p class="cityUser">{{ team.owner.get_location }}</p>
<p class="navv">На сайте {{ team.created }}</p>
<p class="navv">
Кол-во человек: <span>{{ team.contractors.count }}</span>
</p>
<p class="navv">
Выполненных проектов: <span>{{ completed_project_count }}</span>
</p>
<div class="statusUser st-new">Свободен</div>
<a href="javascript:void(0)" class="new-prop new-prop2 new-prop3">написать сообщение</a>
</div>
<div class="col-lg-4">
{% specialization_team_widget team.pk %}
</div>
<div class="col-lg-4">
{% ratings_team_widget team.pk %}
{% if team.owner.cro %}
<div class="sroUser">
<div class="iconSRO"></div>
<p>Есть допуск СРО</p>
</div>
{% endif %}
</div>
</div>
<div class="col-lg-9">
<div class="profileTabs2">
<ul class="nav nav-tabs nav-justified">
<li role="presentation" class="active">
<a href="#tab11" data-toggle="tab">Портфолио</a>
</li>
<li role="presentation">
<a href="#tab12" data-toggle="tab">Готовые проекты</a>
</li>
<li role="presentation">
<a href="#tab13" data-toggle="tab">Отзывы</a>
</li>
</ul>
</div>
</div>
<div class="tab-content">
<div id="tab11" class="tab-pane fade in active">
<div class="galleryWork2 disTab col-lg-9 -portfolios-container">
<script type="text/template" class="-portfolio-item-templ">
<div class="col-lg-4">
<div class="insetCol box-sizing disTab">
<div class="imgGal" style="background:rgba(0, 0, 0, 0) url('<%- portfolio.photos[0].img %>') no-repeat scroll center center / cover">
<a class="open-modal-image" href="<%- portfolio.photos[0].img %>"><div class="imgFigure"></div></a>
</div>
</div>
<div class="insetCol2 box-sizing disTab text-center">
<a href="<%- portfAbsUrl %>"><%- trunc({length: 50}, portfolio.name) %></a>
</div>
</div>
</script>
</div>
<div class="col-lg-9 col-lg-offset-3 -more-portfolios-btn">
<div class="linkElse">
<a href="#" onclick="loadMorePortfolios(); return false" class="showElse">показать еще</a>
</div>
</div>
</div>
<div id="tab12" class="tab-pane fade">
<div class="galleryWork2 disTab -work-sells-container">
<script type="text/template" class="-work-sell-item-templ">
<div class="col-lg-4">
<div class="insetCol box-sizing disTab">
<div class="imgGal" style="background:rgba(0, 0, 0, 0) url('<%- workSell.photos[0].img %>') no-repeat scroll center center / cover ;">
<a class="open-modal-image" href="<%- workSell.photos[0].img %>"><div class="imgFigure"></div></a>
</div>
<div class="cenaImg box-sizing">
<div class="cenaImgInset">
<%- workSell.budget %> <i class="fa fa-rub"></i>
</div>
</div>
</div>
<div class="insetCol2 box-sizing disTab">
<a href="<%- workSellAbsUrl %>"><%- trunc({length: 50}, workSell.name) %></a>
</div>
</div>
</script>
</div>
<div class="col-lg-9 col-lg-offset-3 -more-work-sells-btn">
<div class="linkElse">
<a href="#" onclick="loadMoreWorkSells(); return false" class="showElse">показать еще</a>
</div>
</div>
</div>
<div id="tab13" class="tab-pane fade">
{% for review in reviews %}
<div class="new-comm-44">
<div class="col-lg-12">
<p class="nameComm">
<a href="#">{{ review.get_sender }}</a>
</p>
{% if review.project.deal_type == 'secure_deal' %}
<span class="dateComm44">Безопасная сделка</span>
{% endif %}
<div class="stars box-sizing">
<a href="#">положительный отзыв</a>
</div>
<p class="textComm44">
{{ review.text|safe }}
</p>
</div>
</div>
{% empty %}
<div class="new-comm-44">
<p style="text-align: center;">Отзывов пока нет</p>
</div>
{% endfor %}
</div>
</div>
<div>
{% include 'partials/footer.html' %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block js_block %}
<script type="text/javascript">
(function() {
// Pagination ---------------------------------------------------
var $portfoliosContainer = $('.-portfolios-container').first()
var portfolioItemTempl = _.template($portfoliosContainer.find('.-portfolio-item-templ').first().html())
var $morePortfBtn = $('.-more-portfolios-btn').first()
var portfAbsUrl = '/projects/portfolio/'
var $workSellsContainer = $('.-work-sells-container').first()
var workSellItemTempl = _.template($workSellsContainer.find('.-work-sell-item-templ').first().html())
var $moreWorkSellsfBtn = $('.-more-work-sells-btn').first()
var workSellAbsUrl = '/work_sell/'
var teamId = {{ team.pk }}
var contractorIds = [{{ team.owner.pk }}]
var portfUrl = new URI('/api/portfolios/')
var workSellUrl = new URI('/api/work-sells/')
var pageSize = 3
$.get('/api/teams/' + teamId + '/').then(function(res) {
Array.prototype.push.apply(contractorIds, _.map(function(contractor) {
return contractor.id
}, res.contractors))
})
.then(loadMorePortfolios)
.then(loadMoreWorkSells)
function loadMorePortfolios() {
var query = portfUrl.query(true)
portfUrl.setQuery('user__id__in', _.join(',', contractorIds))
portfUrl.setQuery('page_size', pageSize)
portfUrl.setQuery('page', query.page ? Number(query.page) + 1 : 2)
$.get(portfUrl.href())
.then(function(res) {
_.each(function(portfolio) {
$portfoliosContainer.append(portfolioItemTempl({
portfolio: portfolio,
portfAbsUrl: portfAbsUrl + portfolio.id + '/',
trunc: _.truncate,
}))
}, res.results)
if (!res.next)
$morePortfBtn.css('display', 'none')
})
.then(function() {
$('.open-modal-image').magnificPopup({type: 'image'})
})
}
function loadMoreWorkSells() {
var query = workSellUrl.query(true)
workSellUrl.setQuery('team', teamId)
workSellUrl.setQuery('page_size', pageSize)
workSellUrl.setQuery('page', query.page ? Number(query.page) + 1 : 2)
$.get(workSellUrl.href()).then(function(res) {
_.each(function(ws) {
$workSellsContainer.append(workSellItemTempl({
workSell: ws,
workSellAbsUrl: workSellAbsUrl + ws.id + '/',
trunc: _.truncate,
}))
}, res.results)
if (!res.next)
$moreWorkSellsfBtn.css('display', 'none')
})
}
window.loadMorePortfolios = loadMorePortfolios
window.loadMoreWorkSells = loadMoreWorkSells
// Persistent Bootstrap tabs --------------------------------------
$('a[data-toggle="tab"][href="' + window.location.hash + '"]').tab('show')
$('a[data-toggle="tab"]').on('click', function($evt) { // Better handle "shown.bs.tab" event?
window.location.hash = $(this).attr('href')
})
//-----------------------------------------------------------------
{# var userId = '{{ contractor.pk }}';#}
{# #}
{# var hash = window.location.hash;#}
{# #}
{# if (hash == '#open-contact') {#}
{# $("#contact-contactor-modal").modal();#}
{# }#}
{# #}
{# $('#resume-edit-form').on('submit', function (e) {#}
{# e.preventDefault();#}
{# var resumeEditUrl = "{% url 'users:contractor-resume-update' contractor.contractor_resume.pk %}";#}
{# var dataSerializer = $(this).serialize();#}
{# #}
{# $.ajax({#}
{# url: resumeEditUrl,#}
{# method: 'POST',#}
{# beforeSend: function (xhr) {#}
{# xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))#}
{# },#}
{# data: dataSerializer,#}
{# dataType: 'json',#}
{# success: function (data) {#}
{# console.log(data);#}
{# if (data.status == 'ok') {#}
{# $("#resume-text-out").html(data.text);#}
{# $("#resume-text-edit").modal('hide');#}
{# #}
{# }#}
{# },#}
{# error: function (jqXHR, exception) {#}
{# console.log(jqXHR);#}
{# console.log(exception);#}
{# console.log(jqXHR.statusCode);#}
{# }#}
{# #}
{# });#}
{# });#}
{# #}
{# #}
{# $("#diplom-cro-gallery").on('click', '.delete-resume-file',function(e){#}
{# e.preventDefault();#}
{# #}
{# var _this = $(this);#}
{# var deleteResumeUrl = '/api/contractorresumefiles/' + $(this).attr('data-id') + '/';#}
{# $.ajax({#}
{# url:deleteResumeUrl,#}
{# type: 'DELETE',#}
{# beforeSend: function (xhr) {#}
{# xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'))#}
{# },#}
{# success: function(json){#}
{# _this.parent().parent().parent().remove();#}
{# console.log(json);#}
{# },#}
{# error: function(jqXHR, e){#}
{# console.log(jqXHR.statusCode);#}
{# }#}
{# });#}
{# });#}
{# #}
{# #}
{# $('#worksell-add-form').on('submit', function (e) {#}
{# e.preventDefault();#}
{# var dataSerializer = $(this).serialize();#}
{# $.ajax({#}
{# url: '/work_sell/create/',#}
{# method: 'POST',#}
{# data: dataSerializer,#}
{# dataType: 'json',#}
{# success: function (data) {#}
{# if (data.status == 'ok') {#}
{# location.reload();#}
{# }#}
{# #}
{# },#}
{# error: function (jqXHR, exception) {#}
{# console.log(jqXHR.statusCode);#}
{# console.log(jqXHR);#}
{# }#}
{# #}
{# })#}
{# });#}
{# #}
{# #}
{# $('#portfolio-add-form').on('submit', function (e) {#}
{# e.preventDefault();#}
{# var dataSerializer = $(this).serialize();#}
{# #}
{# $.ajax({#}
{# url: '/projects/portfolio/create/',#}
{# method: 'POST',#}
{# data: dataSerializer,#}
{# dataType: 'json',#}
{# success: function (data) {#}
{# if (data.status == 'ok') {#}
{# $('#portfolio-add-form').each(function () {#}
{# this.reset();#}
{# });#}
{# location.reload();#}
{# } else if (data.status == 'no') {#}
{# #}
{# $.each(data.form_errors, function (k, v) {#}
{# $('.error-' + k).html(v).show();#}
{# });#}
{# }#}
{# },#}
{# error: function (jqXHR, exception) {#}
{# console.log(jqXHR.statusCode);#}
{# }#}
{# });#}
{# });#}
{# var url = '/work_sell/basic/';#}
{# var csrftoken = $.cookie('csrftoken');#}
{# #}
{# $("#upload-resume").on('change',function(e){#}
{# $("#resume-success").html("");#}
{# var formData = new FormData($(this).closest("form"));#}
{# formData.append('resume_file', e.target.files[0]);#}
{# console.log(formData);#}
{# console.log(e.target.files[0]);#}
{# $.ajax({#}
{# url:'/api/contractorresume/{{ contractor.contractor_resume.pk }}/',#}
{# method:'PUT',#}
{# beforeSend: function (xhr) {#}
{# xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));#}
{# },#}
{# data: formData,#}
{# cache: false,#}
{# dataType: 'json',#}
{# processData: false,#}
{# contentType: false,#}
{# success: function(data){#}
{# $("#resume-success").html("Файл для резюме успешно загружен!");#}
{# $(".download-summ").css('display','block').attr('href',data.resume_file);#}
{# console.log(data);#}
{# },#}
{# error: function(jqXHR){#}
{# console.log(jqXHR);#}
{# }#}
{# });#}
{# });#}
{# #}
{# $('#fileupload').fileupload({#}
{# url: url,#}
{# crossDomain: false,#}
{# beforeSend: function (xhr, settings) {#}
{# $('#progress-portfolio .progress-bar').css(#}
{# 'width',#}
{# '0%'#}
{# );#}
{# if (!csrfSafeMethod(settings.type)) {#}
{# xhr.setRequestHeader("X-CSRFToken", csrftoken);#}
{# }#}
{# },#}
{# dataType: 'json',#}
{# done: function (e, data) {#}
{# console.log(data);#}
{# $.each(data.result.files, function (index, file) {#}
{# var img = $('<img style="width:200px;height:200px;margin:10px;">').attr('src', file.url).appendTo("#files");#}
{# console.log(file);#}
{# var currentValue = $("#upload-files-pk").val();#}
{# currentValue += file.id + ';';#}
{# $("#upload-files-pk").val(currentValue);#}
{# #}
{# });#}
{# },#}
{# progressall: function (e, data) {#}
{# var progress = parseInt(data.loaded / data.total * 100, 10);#}
{# console.log(progress);#}
{# $('#progress-portfolio .progress-bar').css(#}
{# 'width',#}
{# progress + '%'#}
{# );#}
{# }#}
{# }).prop('disabled', !$.support.fileInput)#}
{# .parent().addClass($.support.fileInput ? undefined : 'disabled');#}
{# #}
{# $('#fileupload-worksell').fileupload({#}
{# url: url,#}
{# crossDomain: false,#}
{# beforeSend: function (xhr, settings) {#}
{# $('#progress-worksell .progress-bar').css(#}
{# 'width',#}
{# '0%'#}
{# );#}
{# if (!csrfSafeMethod(settings.type)) {#}
{# xhr.setRequestHeader("X-CSRFToken", csrftoken);#}
{# }#}
{# },#}
{# dataType: 'json',#}
{# done: function (e, data) {#}
{# console.log(data);#}
{# $.each(data.result.files, function (index, file) {#}
{# var img = $('<img style="width:200px;height:200px;margin:10px;">').attr('src', file.url).appendTo("#files-worksell");#}
{# console.log(file);#}
{# var currentValue = $("#upload-files-worksell-pk").val();#}
{# currentValue += file.id + ';';#}
{# $("#upload-files-worksell-pk").val(currentValue);#}
{# #}
{# });#}
{# },#}
{# progressall: function (e, data) {#}
{# var progress = parseInt(data.loaded / data.total * 100, 10);#}
{# console.log(progress);#}
{# $('#progress-worksell .progress-bar').css(#}
{# 'width',#}
{# progress + '%'#}
{# );#}
{# }#}
{# }).prop('disabled', !$.support.fileInput)#}
{# .parent().addClass($.support.fileInput ? undefined : 'disabled');#}
{# #}
{# function csrfSafeMethod(method) {#}
{# // these HTTP methods do not require CSRF protection#}
{# return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));#}
{# }#}
}())
</script>
{% endblock %}

@ -7,13 +7,14 @@ from .views import (
ContractorFilterView, ContractorFilterView,
ContractorOfficeProjectsView, ContractorOfficeProjectsView,
ContractorOfficeView, ContractorOfficeView,
ContractorProfileDetailView, ContractorProfileView,
ContractorResumeUpdateView, ContractorResumeUpdateView,
CustomerProfileCurrentProjectsView, CustomerProfileCurrentProjectsView,
CustomerProfileOpenProjectsView, CustomerProfileOpenProjectsView,
CustomerProfileReviewsView, CustomerProfileReviewsView,
CustomerProfileTrashedProjectsView, CustomerProfileTrashedProjectsView,
TeamCreateView, TeamCreateView,
TeamProfileView,
UserFinancialInfoEditView, UserFinancialInfoEditView,
UserProfileEditView, UserProfileEditView,
) )
@ -34,7 +35,9 @@ urlpatterns = [
urls.url(r'^contractors/resume/(?P<pk>\d+)/edit/$', ContractorResumeUpdateView.as_view(), name='contractor-resume-update'), urls.url(r'^contractors/resume/(?P<pk>\d+)/edit/$', ContractorResumeUpdateView.as_view(), name='contractor-resume-update'),
urls.url(r'^contractors/team/create/$', TeamCreateView.as_view(), name='team-create'), urls.url(r'^contractors/team/create/$', TeamCreateView.as_view(), name='team-create'),
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+)/$', ContractorProfileView.as_view(), name='contractor-profile'),
urls.url(r'^contractor-office/(?P<pk>\d+)/$', ContractorOfficeView.as_view(), name='contractor-office'), urls.url(r'^contractor-office/(?P<pk>\d+)/$', ContractorOfficeView.as_view(), name='contractor-office'),
urls.url(r'^contractor-office/(?P<pk>\d+)/open-projects/$', ContractorOfficeProjectsView.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'),
urls.url(r'^teams/(?P<pk>\d+)/$', TeamProfileView.as_view(), name='team-profile'),
] ]

@ -325,7 +325,7 @@ class ContractorFilterView(BaseMixin, View):
return render(request, self.template_name, context) return render(request, self.template_name, context)
class ContractorProfileDetailView(DetailView): class ContractorProfileView(DetailView):
model = User model = User
worksell_form_class = WorkSellForm worksell_form_class = WorkSellForm
portfolio_form_class = PortfolioForm portfolio_form_class = PortfolioForm
@ -371,34 +371,42 @@ class ContractorOfficeView(DetailView):
contractor = self.object contractor = self.object
if util.get_related_or_none(contractor, 'team'): if util.get_related_or_none(contractor, 'team'):
members = contractor.team.contractors.all() team = contractor.team
context['team_members'] = members
context['team_member_count'] = len(members)
compl_proj = [] # compl_proj = []
# portfolios = [] # Fetched via DRF # compl_proj.extend(tuple(o.project for o in contractor.orders.filter(status='completed')))
# work_sells = [] # Fetched via DRF #
# for c in members:
# compl_proj.extend(tuple(o.project for o in c.orders.filter(status='completed')))
compl_proj.extend(tuple(o.project for o in contractor.orders.filter(status='completed'))) compl_proj = tuple(o.project for o in team.orders.filter(status='completed'))
# portfolios.extend(contractor.portfolios.all())
# work_sells.extend(contractor.work_sell.all())
for c in members:
compl_proj.extend(tuple(o.project for o in c.orders.filter(status='completed')))
# portfolios.extend(c.portfolios.all())
# work_sells.extend(c.work_sell.all())
context['completed_project_count'] = len(compl_proj) context['completed_project_count'] = len(compl_proj)
# context['portfolios'] = portfolios context['reviews'] = Review.objects.filter(target_contractor=contractor)
# context['work_sells'] = work_sells
context['reviews'] = Review.objects.filter(target_contractor__in=itertools.chain((contractor,), members))
context['form_team'] = self.form_class context['form_team'] = self.form_class
return context return context
class TeamProfileView(DetailView):
model = Team
template_name = 'team_profile.html'
context_object_name = 'team'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
team = self.object
compl_proj = tuple(o.project for o in team.orders.filter(status='completed'))
context['completed_project_count'] = len(compl_proj)
context['reviews'] = Review.objects.filter(target_team=team)
return context
class ContractorOfficeProjectsView(BaseMixin, View): class ContractorOfficeProjectsView(BaseMixin, View):
template_name = 'contractor_office_open_projects.html' template_name = 'contractor_office_open_projects.html'

@ -38,6 +38,7 @@ class WorkSellFilterSet(FilterSet):
location = RelatedFilter('common.filters.LocationFilterSet') location = RelatedFilter('common.filters.LocationFilterSet')
photos = RelatedFilter('work_sell.filters.WorkSellPhotoFilterSet') photos = RelatedFilter('work_sell.filters.WorkSellPhotoFilterSet')
specialization = RelatedFilter('specializations.filters.SpecializationFilterSet') specialization = RelatedFilter('specializations.filters.SpecializationFilterSet')
team = RelatedFilter('users.filters.TeamFilterSet')
class Meta: class Meta:
model = WorkSell model = WorkSell

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-02 14:19
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0015_user_phone2'),
('work_sell', '0009_auto_20160901_1548'),
]
operations = [
migrations.AddField(
model_name='worksell',
name='team',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='work_sells', to='users.Team'),
),
]

@ -21,6 +21,7 @@ class WorkSell(models.Model):
location = TreeForeignKey('common.Location', related_name='worksells', null=True, blank=True) location = TreeForeignKey('common.Location', related_name='worksells', null=True, blank=True)
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
specialization = TreeForeignKey(Specialization, related_name='worksells', null=True, blank=True) specialization = TreeForeignKey(Specialization, related_name='worksells', null=True, blank=True)
team = models.ForeignKey(Team, related_name='work_sells', null=True, blank=True)
term = models.IntegerField(default=0, null=True, blank=True) term = models.IntegerField(default=0, null=True, blank=True)
term_type = models.CharField(max_length=20, choices=TERM_TYPES, default='hour', null=True, blank=True) term_type = models.CharField(max_length=20, choices=TERM_TYPES, default='hour', null=True, blank=True)

@ -5,7 +5,7 @@ from .models import WorkSell, WorkSellPhoto
from common.serializers import LocationSerializer from common.serializers import LocationSerializer
from projects.serializers import BuildingClassficationSerializer, ConstructionTypeSerializer from projects.serializers import BuildingClassficationSerializer, ConstructionTypeSerializer
from specializations.serializers import SpecializationSerializer from specializations.serializers import SpecializationSerializer
from users.serializers import UserSerializer from users.serializers import UserSerializer, TeamSerializer
class WorkSellPhotoSerializer(ModelSerializer): class WorkSellPhotoSerializer(ModelSerializer):
@ -30,6 +30,7 @@ class WorkSellSerializer(ModelSerializer):
location = LocationSerializer() location = LocationSerializer()
photos = WorkSellPhotoSerializer(many=True) photos = WorkSellPhotoSerializer(many=True)
specialization = SpecializationSerializer() specialization = SpecializationSerializer()
team = TeamSerializer()
class Meta: class Meta:
model = WorkSell model = WorkSell
@ -47,6 +48,7 @@ class WorkSellSerializer(ModelSerializer):
'name', 'name',
'photos', 'photos',
'specialization', 'specialization',
'team',
'term', 'term',
'term_type', 'term_type',
) )

Loading…
Cancel
Save