remotes/origin/PR-39
ArturBaybulatov 9 years ago
parent d9b6897601
commit f65b9984cd
  1. 16
      projects/admin.py
  2. 27
      projects/forms.py
  3. 45
      projects/migrations/0032_auto_20160915_2056.py
  4. 20
      projects/migrations/0033_auto_20160916_1534.py
  5. 15
      projects/models.py
  6. 50
      projects/templates/customer_project_create.html
  7. 50
      projects/templates/customer_project_edit.html
  8. 55
      projects/templates/partials/modals/project_work_type_suggestion.html
  9. 4
      projects/urls.py
  10. 66
      projects/views.py
  11. 83
      templates/partials/base_test.html
  12. 2
      users/templates/contractor_profile.html
  13. 26
      work_sell/migrations/0015_auto_20160915_2056.py

@ -12,6 +12,7 @@ from .models import (
PortfolioPhoto,
Project,
ProjectFile,
ProjectWorkTypeSuggestion,
Realty,
Stage,
)
@ -42,14 +43,15 @@ class StageAdmin(admin.ModelAdmin):
admin.site.register(Answer)
admin.site.register(Portfolio)
admin.site.register(PortfolioPhoto)
admin.site.register(Realty)
admin.site.register(Order, OrderAdmin)
admin.site.register(Candidate)
admin.site.register(Stage, StageAdmin)
admin.site.register(Arbitration)
admin.site.register(BuildingClassfication)
admin.site.register(Candidate)
admin.site.register(ConstructionType)
admin.site.register(Order, OrderAdmin)
admin.site.register(Portfolio)
admin.site.register(PortfolioPhoto)
admin.site.register(Project, ProjectAdmin)
admin.site.register(ProjectFile)
admin.site.register(Arbitration)
admin.site.register(ProjectWorkTypeSuggestion)
admin.site.register(Realty)
admin.site.register(Stage, StageAdmin)

@ -4,8 +4,9 @@ from django.forms.models import inlineformset_factory
from mptt.forms import TreeNodeChoiceField
from pprint import pprint, pformat
import itertools
import pydash as _; _.map = _.map_; _.filter = _.filter_
from .models import Project, ProjectFile, Portfolio, Answer, AnswerMessage, Realty, PortfolioPhoto, Stage
from .models import Project, ProjectFile, Portfolio, Answer, AnswerMessage, Realty, PortfolioPhoto, Stage, ProjectWorkTypeSuggestion
from archilance import util
from common.models import Location, LiveImageUpload
from specializations.models import Specialization
@ -363,4 +364,28 @@ class CustomerProjectDeleteForm(forms.Form):
self.fields['pk'].queryset = self.req.user.customer_projects.filter(Q(state='active') | Q(state='trashed'))
class ProjectWorkTypeSuggestionForm(forms.ModelForm):
class Meta:
model = ProjectWorkTypeSuggestion
fields = (
'name',
'commentary',
'email',
'username',
)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super().__init__(*args, **kwargs)
# for bfield in self:
# attrs = bfield.field.widget.attrs
# attrs['class'] = _.join(_.compact((attrs.get('class'), '-error -error-%s' % bfield.html_name)), ' ')
if self.request and self.request.user.is_authenticated():
self['username'].field.initial = self.request.user.username
self['email'].field.initial = self.request.user.email
# import code; code.interact(local=dict(globals(), **locals()))

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-15 17:56
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0031_merge'),
]
operations = [
migrations.CreateModel(
name='ProjectWorkTypeSuggestion',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('commentary', models.TextField(blank=True)),
('processed', models.BooleanField(default=False)),
('username', models.CharField(max_length=255)),
('email', models.CharField(max_length=255)),
],
options={
'verbose_name': 'Предложение типов работ (проектов)',
'verbose_name_plural': 'Предложения типов работ (проектов)',
},
),
migrations.AlterField(
model_name='answerfile',
name='file',
field=models.FileField(upload_to='projects/answer_files/'),
),
migrations.AlterField(
model_name='portfoliophoto',
name='img',
field=models.ImageField(upload_to='projects/portfolio/'),
),
migrations.AlterField(
model_name='projectfile',
name='file',
field=models.FileField(upload_to='projects/project_files/'),
),
]

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-16 12:34
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('projects', '0032_auto_20160915_2056'),
]
operations = [
migrations.AlterField(
model_name='projectworktypesuggestion',
name='email',
field=models.EmailField(max_length=254),
),
]

@ -345,3 +345,18 @@ class PortfolioPhoto(models.Model):
def __str__(self):
return self.img and self.img.url or str(self.img)
class ProjectWorkTypeSuggestion(models.Model):
name = models.CharField(max_length=255)
commentary = models.TextField(blank=True)
processed = models.BooleanField(default=False)
username = models.CharField(max_length=255)
email = models.EmailField()
class Meta:
verbose_name = 'Предложение типов работ (проектов)'
verbose_name_plural = 'Предложения типов работ (проектов)'
def __str__(self):
return self.name

@ -1,8 +1,14 @@
{% extends 'partials/base.html' %}
{% load common_tags %}
{% block head_css %}
<style>
.-error, .errorlist {color: red}
</style>
{% endblock %}
{% block content %}
{% include 'partials/modals/project_work_type_suggestion.html' %}
{% include 'partials/header.html' %}
<div class="container mainScore">
@ -71,7 +77,7 @@
{% endfor %}
</div>
<div class="textAreaBlock2 box-sizing disTab">
<a href="#" class="new-link new-lw">+ Добавить раздел</a>
<a href="#" onclick="return false" data-toggle="modal" data-target="#projectWorkTypeSuggestionModal" class="new-link new-lw">+ Добавить раздел</a>
</div>
</div>
</div>
@ -290,3 +296,43 @@
</div>
</div>
{% endblock %}
{% block js_block %}
<script>
// Project work type suggestion modal ---------------------------------
;(function() {
var $workTypeSuggestionModal = $('#projectWorkTypeSuggestionModal')
var $form = $workTypeSuggestionModal.find('.-project-work-type-suggestion-form').first()
var workTypeSuggestionUrl = '/projects/suggest-work-type/'
$workTypeSuggestionModal.find('.-action-button').first().on('click', function($evt) {
$.post(workTypeSuggestionUrl, $form.serialize())
.then(function(res) {
if (res.status === 'success') {
console.log('Success')
$form.trigger('reset')
$('.-error').text('')
$workTypeSuggestionModal.modal('hide')
$.jGrowl('Предложение успешно отправлено')
} else if (res.status === 'error') {
console.log('Error')
_.flow(
_.toPairs,
_.each(function(pair) {
var cssSelector = pair[0]
var errors = pair[1]
$(cssSelector).first().text(_.join(' ', errors))
})
)(res.form_errors)
}
})
})
}())
</script>
{% endblock %}

@ -1,8 +1,14 @@
{% extends 'partials/base.html' %}
{% load common_tags %}
{% block head_css %}
<style>
.-error, .errorlist {color: red}
</style>
{% endblock %}
{% block content %}
{% include 'partials/modals/project_work_type_suggestion.html' %}
{% include 'partials/header.html' %}
<div class="container mainScore">
@ -81,7 +87,7 @@
{% endfor %}
</div>
<div class="textAreaBlock2 box-sizing disTab">
<a href="#" class="new-link new-lw">+ Добавить раздел</a>
<a href="#" onclick="return false" data-toggle="modal" data-target="#projectWorkTypeSuggestionModal" class="new-link new-lw">+ Добавить раздел</a>
</div>
</div>
</div>
@ -304,3 +310,43 @@
</div>
</div>
{% endblock %}
{% block js_block %}
<script>
// Project work type suggestion modal ---------------------------------
;(function() {
var $workTypeSuggestionModal = $('#projectWorkTypeSuggestionModal')
var $form = $workTypeSuggestionModal.find('.-project-work-type-suggestion-form').first()
var workTypeSuggestionUrl = '/projects/suggest-work-type/'
$workTypeSuggestionModal.find('.-action-button').first().on('click', function($evt) {
$.post(workTypeSuggestionUrl, $form.serialize())
.then(function(res) {
if (res.status === 'success') {
console.log('Success')
$form.trigger('reset')
$('.-error').text('')
$workTypeSuggestionModal.modal('hide')
$.jGrowl('Предложение успешно отправлено')
} else if (res.status === 'error') {
console.log('Error')
_.flow(
_.toPairs,
_.each(function(pair) {
var cssSelector = pair[0]
var errors = pair[1]
$(cssSelector).first().text(_.join(' ', errors))
})
)(res.form_errors)
}
})
})
}())
</script>
{% endblock %}

@ -0,0 +1,55 @@
<div class="modal fade" id="projectWorkTypeSuggestionModal" tabindex="-1">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
<h4 class="modal-title">Предложение нового типа работы</h4>
</div>
<div class="modal-body">
<form action="{% url 'projects:suggest-work-type' %}" method="POST" novalidate class="-project-work-type-suggestion-form">
{% csrf_token %}
<div>{{ work_type_suggestion_form.non_field_errors }}</div>
<div class="row">
<div class="col-xs-12 projectsBlock">
<div>{{ work_type_suggestion_form.name.label }}</div>
<div>{{ work_type_suggestion_form.name }}</div>
<div class="-error -error-{{ work_type_suggestion_form.name.html_name }}"></div>
</div>
</div>
<div class="row">
<div class="col-xs-12 projectsBlock">
<div>{{ work_type_suggestion_form.commentary.label }}</div>
<div>{{ work_type_suggestion_form.commentary }}</div>
<div class="-error -error-{{ work_type_suggestion_form.commentary.html_name }}"></div>
</div>
</div>
<div class="row">
<div class="col-xs-12 projectsBlock">
<div>{{ work_type_suggestion_form.email.label }}</div>
<div>{{ work_type_suggestion_form.email }}</div>
<div class="-error -error-{{ work_type_suggestion_form.email.html_name }}"></div>
</div>
</div>
<div class="row">
<div class="col-xs-12 projectsBlock">
<div>{{ work_type_suggestion_form.username.label }}</div>
<div>{{ work_type_suggestion_form.username }}</div>
<div class="-error -error-{{ work_type_suggestion_form.username.html_name }}"></div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Отмена</button>
<button type="button" class="btn btn-primary -action-button">Предложить</button>
</div>
</div>
</div>
</div>

@ -22,6 +22,7 @@ from .views import (
ProjectComparisonView,
ProjectDetailWithAnswerView,
ProjectFilterView,
ProjectWorkTypeSuggestionView,
RejectProjectAnswerView,
RestoreProjectAnswerView,
sort_candidates,
@ -58,6 +59,5 @@ urlpatterns = [
urls.url(r'^customer-offer-order/(?P<answer_id>(\d+))/(?P<project_id>(\d+))/$', CustomerOfferOrderView.as_view(), name='customer-offer-order'),
# urls.url(r'^(?P<project_id>\d+)/contractor-offer-order/(?P<contractor_id>\d+)/$', ContractorOfferOrder.as_view(), name='contractor-offer-order'),
# urls.url(r'^(?P<project_id>\d+)/team-offer-order/(?P<team_id>\d+)/$', TeamOfferOrder.as_view(), name='team-offer-order'),
urls.url(r'^suggest-work-type/$', ProjectWorkTypeSuggestionView.as_view(), name='suggest-work-type'),
]

@ -51,6 +51,7 @@ from .forms import (
ProjectAnswerMessageForm,
ProjectFilterForm,
ProjectFilterRealtyForm,
ProjectWorkTypeSuggestionForm,
RealtyForm,
)
@ -374,6 +375,7 @@ class ProjectFilterView(BaseMixin, View):
class CustomerProjectCreateView(BaseMixin, View):
form_class = CustomerProjectEditForm
realty_form = RealtyForm
work_type_suggestion_form = ProjectWorkTypeSuggestionForm
template_name = 'customer_project_create.html'
def dispatch(self, request, *args, **kwargs):
@ -383,11 +385,17 @@ class CustomerProjectCreateView(BaseMixin, View):
raise PermissionDenied
def get(self, request, *args, **kwargs):
context = self.get_context_data(**_.merge({}, request.GET, kwargs))
form = self.form_class(request=request)
realty_form = self.realty_form(request=request, prefix='realty_form')
work_type_suggestion_form = self.work_type_suggestion_form(request=request, prefix='work_type_suggestion')
context = self.get_context_data(**_.merge({}, request.GET, kwargs))
context.update({'form': form, 'realty_form': realty_form})
context.update({
'form': form,
'realty_form': realty_form,
'work_type_suggestion_form': work_type_suggestion_form,
})
return render(request, self.template_name, context)
@ -448,17 +456,24 @@ class CustomerProjectCreateView(BaseMixin, View):
class CustomerProjectEditView(BaseMixin, View):
form_class = CustomerProjectEditForm
realty_form = RealtyForm
work_type_suggestion_form = ProjectWorkTypeSuggestionForm
template_name = 'customer_project_edit.html'
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated() and request.user.is_customer():
# Prevent editing when project's taken:
project = get_object_or_404(request.user.customer_projects, pk=kwargs.get('pk'))
if not project.order.contractor and not project.order.team:
return super().dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
def get(self, request, *args, **kwargs):
project = get_object_or_404(request.user.customer_projects, pk=kwargs.get('pk'))
form = self.form_class(instance=project, request=request)
work_type_suggestion_form = self.work_type_suggestion_form(request=request, prefix='work_type_suggestion')
realty = project.realty
@ -468,7 +483,12 @@ class CustomerProjectEditView(BaseMixin, View):
realty_form = self.realty_form(request=request, prefix='realty_form')
context = self.get_context_data(**_.merge({}, request.GET, kwargs))
context.update({'form': form, 'realty_form': realty_form})
context.update({
'form': form,
'realty_form': realty_form,
'work_type_suggestion_form': work_type_suggestion_form,
})
return render(request, self.template_name, context)
@ -831,22 +851,28 @@ class ArbitrationCreateView(CreateView):
return super().form_invalid(form)
# class ContractorOfferOrder(NoCsrfMixin, CustomerRequiredMixin, View):
# def post(self, request, *args, project_id, contractor_id, **kwargs):
# project = get_object_or_404(Project, pk=project_id)
# contractor = get_object_or_404(User.contractor_objects, pk=contractor_id)
#
# # project.order.contractor
#
# return JsonResponse({'status': 'success'})
#
#
# class TeamOfferOrder(NoCsrfMixin, CustomerRequiredMixin, View):
# def post(self, request, *args, project_id, team_id, **kwargs):
# project = get_object_or_404(Project, pk=project_id)
# team = get_object_or_404(Team, pk=team_id)
#
# return JsonResponse({'status': 'success'})
class ProjectWorkTypeSuggestionView(View):
form_class = ProjectWorkTypeSuggestionForm
template_name = 'customer_project_work_type_suggestion.html'
# def get(self, request, *args, **kwargs):
# form = self.form_class(request=request, prefix='work_type_suggestion')
# context = {'form': form}
# return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request=request, prefix='work_type_suggestion')
if form.is_valid():
form.save()
return JsonResponse({'status': 'success'})
else:
form_errors = {'.-error-%s' % bfield.html_name: bfield.errors for bfield in form}
return JsonResponse({
'status': 'error',
'form_errors': form_errors,
})
# import code; code.interact(local=dict(globals(), **locals()))

@ -0,0 +1,83 @@
{% load staticfiles %}
{% load compress %}
<!doctype html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge, chrome=1'>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<!--<meta name='viewport' content='initial-scale=1.0, user-scalable=no, maximum-scale=1'>-->
{% block head %}{% endblock %}
<title>PROEKTON</title>
{% compress css %}
<link rel='stylesheet' href='{% static "lib/jquery-ui/jquery-ui.css" %}'>
<link rel='stylesheet' href='{% static "css/bootstrap.css" %}'>
{# <link rel='stylesheet' href='{% static "css/font-awesome.min.css" %}'>#}
{# <link rel='stylesheet' href='{% static "css/reset.css" %}'>#}
{# <link rel='stylesheet' href='{% static "lib/bootstrap-select/css/bootstrap-select.css" %}'>#}
{# <link rel='stylesheet' href='{% static "lib/select2/select2.css" %}'> <!-- Tmp -->#}
{# <link rel='stylesheet' href='{% static "css/swiper.min.css" %}'>#}
{# <link rel='stylesheet' href='{% static "lib/jquery.fileupload/css/jquery.fileupload.css" %}'>#}
{# <link rel='stylesheet' href='{% static "js/magnific-popup.css" %}'>#}
{# <link rel="stylesheet" href='{% static "lib/jquery-jgrowl/jquery.jgrowl.min.css" %}'>#}
{% block head_css %}{% endblock %}
{# <link rel='stylesheet' href='{% static "css/main.css" %}'>#}
{# <link rel='stylesheet' href='{% static "css/extra.css" %}'> <!-- Our additional CSS -->#}
<link rel='stylesheet' href='{% static "css/dev-colors.css" %}'> <!-- Dev-time only, temporary!!! -->
{% endcompress %}
</head>
<body>
{% if messages %}
{% for message in messages %}
<div class="c"
style="position: relative; padding: 10px; margin-bottom: 6px; z-index: 100">{{ message|safe }}</div>
{% endfor %}
{% endif %}
<div ondblclick="$(this).css('display', 'none')" style="position: absolute; left: 0; bottom: 0; padding: 6px; color: black; background-color: {% if request.user.is_contractor %}#BADA55{% else %}#C0FFEE{% endif %}; z-index: 50">
{{ request.user }}<br>
{% if request.user.is_authenticated %}
<b>PK:</b> {{ request.user.pk }}<br>
<b>Groups:</b> {{ request.user.groups.all }}
{% endif %}
</div>
{% block content %}{% endblock %}
<script src='{% static "lib/lodash/lodash.js" %}'></script>
<script src='{% static "lib/lodash/lodash.fp.js" %}'></script>
<script src='{% static "js/jquery-2.2.3.min.js" %}'></script>
<script src='{% static "lib/jquery-ui/jquery-ui.js" %}'></script>
<script src='{% static "lib/jquery-ui/i18n/datepicker-ru.js" %}'></script> <!-- jQueryUI Datepicker i18n -->
<script src='{% static "js/bootstrap.min.js" %}'></script>
<script src='{% static "lib/bootstrap-select/js/bootstrap-select.js" %}'></script>
<script src='{% static "lib/select2/select2.js" %}'></script>
<script src='{% static "lib/urijs/URI.min.js" %}'></script>
{#<script src='{% static "lib/jquery.fileupload/js/vendor/jquery.ui.widget.js" %}'></script>#}
{#<script src='{% static "lib/jquery.fileupload/js/jquery.iframe-transport.js" %}'></script>#}
{#<script src='{% static "lib/jquery.fileupload/js/jquery.fileupload.js" %}'></script>#}
{#<script src='{% static "lib/jquery.fileupload/js/jquery.fileupload-process.js" %}'></script>#}
{##}
{#<script src='{% static "js/jquery.magnific-popup.min.js" %}'></script>#}
{#<script src='{% static "lib/jquery.cookie/jquery.cookie.min.js" %}'></script>#}
{#<script src='{% static "lib/jquery-jgrowl/jquery.jgrowl.min.js" %}'></script>#}
<script src='{% static "my-libs.js" %}'></script>
{#<script src='{% static "js/main.js" %}'></script> <!-- Файл верстальщика -->#}
<script src='{% static "index.js" %}'></script> <!-- Файл программистов -->
{% block js_block %}{% endblock %}
</body>
</html>

@ -588,7 +588,7 @@
<script src='{% static "lib/ckeditor/ckeditor.js" %}'></script>
<script src='{% static "lib/ckeditor/adapters/jquery.js" %}'></script>
<script type="text/javascript">
<script>
(function() {
// Pagination ---------------------------------------------------

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-09-15 17:56
from __future__ import unicode_literals
from django.db import migrations, models
import sorl.thumbnail.fields
class Migration(migrations.Migration):
dependencies = [
('work_sell', '0014_merge'),
]
operations = [
migrations.AlterField(
model_name='picture',
name='file',
field=models.ImageField(upload_to='worksell/pictures/'),
),
migrations.AlterField(
model_name='worksellphoto',
name='img',
field=sorl.thumbnail.fields.ImageField(upload_to='worksell/worksell/'),
),
]
Loading…
Cancel
Save