Skip to content
This repository has been archived by the owner on Jun 24, 2024. It is now read-only.

Commit

Permalink
Merge branch 'release/3.6.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandreJunod committed Mar 11, 2024
2 parents 94a68ee + 954f4ff commit 7b07deb
Show file tree
Hide file tree
Showing 69 changed files with 18,670 additions and 3,385 deletions.
12 changes: 11 additions & 1 deletion docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ volumes:

services:
web:
# Uncomment those two lines for debug
#tty: true
#stdin_open: true
build:
args:
ENV: DEV
Expand All @@ -19,13 +22,20 @@ services:
- ./_dev_volumes/private_documents:/private_documents
- ./_dev_volumes/archive:/archive
depends_on:
- "postgres"
postgres:
condition: service_healthy
ports:
- "${DJANGO_DOCKER_PORT}:9000"

postgres:
image: postgis/postgis:13-3.2
restart: unless-stopped
healthcheck:
test: [ "CMD", "pg_isready", "-q", "-U", "${PGUSER}" ]
interval: 5s
timeout: 10s
retries: 3
start_period: 10s
environment:
- POSTGRES_USER=${PGUSER}
- POSTGRES_PASSWORD=${PGPASSWORD}
Expand Down
16 changes: 8 additions & 8 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ set -e
# If not will, the container will fail and restart.
python3 manage.py shell -c "import django; django.db.connection.ensure_connection();"

# On PROD, we run migrations at startup unless explicitly disabled.
# If disabled, this command must be run manually for the application to function correctly after a model update.
if [ "$ENV" == "PROD" ] && [ "${DISABLE_MIGRATION_SCRIPT_ON_PRODUCTION}" != "true" ]; then
python3 manage.py migrate
fi

# On PROD, we always collect statics
if [ "$ENV" == "PROD" ]; then
# On PROD, we run migrations at startup unless explicitly disabled.
# If disabled, this command must be run manually for the application to function correctly after a model update.
if [ "${DISABLE_MIGRATION_SCRIPT_ON_PRODUCTION}" != "true" ]; then
python3 manage.py migrate
fi
python3 manage.py collectstatic --no-input
elif [ "$ENV" == "DEV" ]; then
python3 manage.py migrate
fi

python3 manage.py update_integrator_permissions
python3 manage.py compilemessages -l fr
python3 manage.py update_integrator_permissions

# Run the command
exec $@
30 changes: 22 additions & 8 deletions geocity/apps/accounts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from geocity.apps.accounts.models import AdministrativeEntity, UserProfile
from geocity.apps.reports.models import Report
from geocity.apps.submissions.models import Submission, SubmissionWorkflowStatus
from geocity.apps.submissions.payments.models import ServiceFeeType
from geocity.fields import GeometryWidget

from . import models, permissions_groups
Expand Down Expand Up @@ -67,6 +68,7 @@
</ul>
"""


# Allow a user belonging to integrator group to see only objects created by this group
def filter_for_user(user, qs):
if not user.is_superuser:
Expand Down Expand Up @@ -453,7 +455,6 @@ class Media:
css = {"all": ("css/admin/admin.css",)}

def clean_permissions(self):

permissions = self.cleaned_data["permissions"]
permissions_for_trusted_users = Permission.objects.filter(
codename__in=permissions_groups.AVAILABLE_FOR_INTEGRATOR_PERMISSION_CODENAMES
Expand Down Expand Up @@ -603,7 +604,6 @@ def get__sites_number(self, obj):
get__sites_number.short_description = _("Nombre de sites")

def get_queryset(self, request):

if request.user.is_superuser:
qs = Group.objects.all()
else:
Expand All @@ -627,14 +627,12 @@ def save_model(self, request, obj, form, change):
def formfield_for_manytomany(self, db_field, request, **kwargs):
# permissions that integrator role can grant to group
if db_field.name == "permissions":

if (
not request.user.is_superuser
and request.user.groups.get(
permit_department__is_integrator_admin=True
).pk
):

integrator_permissions = Permission.objects.filter(
codename__in=permissions_groups.AVAILABLE_FOR_INTEGRATOR_PERMISSION_CODENAMES
)
Expand All @@ -649,7 +647,6 @@ def label_from_instance(self, obj):


def get_sites_field(user):

qs = models.Site.objects.all()

if not user.is_superuser:
Expand Down Expand Up @@ -702,6 +699,7 @@ class Meta:
"signature_sheet",
"signature_sheet_description",
"additional_searchtext_for_address_field",
"services_fees_hourly_rate",
"geom",
"integrator",
]
Expand Down Expand Up @@ -760,9 +758,15 @@ class SubmissionWorkflowStatusInline(admin.TabularInline):
verbose_name_plural = _("Flux (complet par défaut)")


class ServiceFeeInline(admin.TabularInline):
model = ServiceFeeType
extra = 3
verbose_name = _("Type de prestation")
verbose_name_plural = _("Types de prestation")


@admin.register(models.AdministrativeEntityForAdminSite)
class AdministrativeEntityAdmin(IntegratorFilterMixin, admin.ModelAdmin):

fieldsets = (
(
None,
Expand Down Expand Up @@ -822,7 +826,17 @@ class AdministrativeEntityAdmin(IntegratorFilterMixin, admin.ModelAdmin):
),
},
),
(
_("Tarification des prestations"),
{
"fields": ("services_fees_hourly_rate",),
"description": _(
"La tarification des prestations permet de saisir le tarif horaire de facturation des prestations pour l'entité administrative courante."
),
},
),
)

# Pass the user from ModelAdmin to ModelForm
def get_form(self, request, obj=None, **kwargs):
Form = super().get_form(request, obj, **kwargs)
Expand All @@ -837,6 +851,7 @@ def __new__(cls, *args, **kwargs):
change_form_template = "accounts/admin/administrative_entity_change.html"
form = AdministrativeEntityAdminForm
inlines = [
ServiceFeeInline,
SubmissionWorkflowStatusInline,
]
list_filter = [
Expand All @@ -854,6 +869,7 @@ def __new__(cls, *args, **kwargs):
"get_tags",
"get_is_single_form",
"get_sites",
"services_fees_hourly_rate",
]

def sortable_str(self, obj):
Expand Down Expand Up @@ -882,15 +898,13 @@ def get_is_single_form(self, obj):
get_is_single_form.admin_order_field = "is_single_form_submissions"

def formfield_for_foreignkey(self, db_field, request, **kwargs):

if db_field.name == "integrator":
kwargs["queryset"] = Group.objects.filter(
permit_department__is_integrator_admin=True,
)
return super().formfield_for_foreignkey(db_field, request, **kwargs)

def save_model(self, request, obj, form, change):

if not request.user.is_superuser:
obj.integrator = request.user.groups.get(
permit_department__is_integrator_admin=True
Expand Down
24 changes: 24 additions & 0 deletions geocity/apps/accounts/migrations/0017_service_fee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.9 on 2024-01-24 08:20

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("accounts", "0016_administrativeentity_reply_to_email"),
]

operations = [
migrations.AddField(
model_name="administrativeentity",
name="services_fees_hourly_rate",
field=models.DecimalField(
decimal_places=2,
default=0.0,
help_text="Tarif horaire des prestations de l'entité administrative",
max_digits=12,
verbose_name="Tarif horaire",
),
),
]
10 changes: 8 additions & 2 deletions geocity/apps/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ class AdministrativeEntity(models.Model):
default=True,
help_text=_("Nécessaire pour l'utilisation du système de paiement en ligne"),
)

sites = models.ManyToManyField(
Site,
related_name="administrative_entity",
Expand All @@ -357,6 +356,14 @@ class AdministrativeEntity(models.Model):
signature_sheet_description = models.TextField(
_("Texte explicatif relatif au volet de transmission"), blank=True
)
services_fees_hourly_rate = models.DecimalField(
decimal_places=2,
max_digits=12,
default=settings.DEFAULT_SERVICES_FEES_RATE,
verbose_name=_("Tarif horaire"),
help_text=_("Tarif horaire des prestations de l'entité administrative"),
)

objects = AdministrativeEntityManager()

class Meta:
Expand Down Expand Up @@ -611,7 +618,6 @@ class Meta:
verbose_name_plural = _("3.2 Consultation des auteurs")

def __str__(self):

return (
str(self.user.first_name) + " " + str(self.user.last_name)
if self.user
Expand Down
5 changes: 5 additions & 0 deletions geocity/apps/accounts/permissions_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"submissions": [
"submissionamendfield",
"submissionworkflowstatus",
"servicefeetype",
],
"reports": [
"report",
Expand All @@ -28,6 +29,7 @@
"section",
"headerfooter",
],
# FIXME: get nested submissions.payments
}

# define permissions required by integrator role
Expand Down Expand Up @@ -62,16 +64,19 @@
"can_generate_pdf",
"can_refund_transactions",
"can_revert_refund_transactions",
"can_manage_service_fee",
]

DEFAULT_PILOT_PERMISSION_CODENAMES = [
"read_submission",
"amend_submission",
"classify_submission",
"can_generate_pdf",
"can_manage_service_fee",
]

DEFAULT_VALIDATOR_PERMISSION_CODENAMES = [
"read_submission",
"validate_submission",
"can_manage_service_fee",
]
1 change: 1 addition & 0 deletions geocity/apps/accounts/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,5 @@ def get_users_list_for_integrator_admin(user, remove_anonymous=False):
):
anonymous_users.append(user.pk)
qs = qs.exclude(pk__in=anonymous_users)

return qs
28 changes: 27 additions & 1 deletion geocity/apps/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
SubmissionGeoTime,
SubmissionInquiry,
)
from geocity.apps.submissions.payments.models import SubmissionPrice
from geocity.apps.submissions.payments.models import ServiceFee, SubmissionPrice
from geocity.apps.submissions.payments.postfinance.models import PostFinanceTransaction


Expand Down Expand Up @@ -291,6 +291,23 @@ class Meta:
)


class SubmissionServiceFeeSerializer(serializers.ModelSerializer):

permit_department = serializers.SlugRelatedField(
read_only=True, slug_field="shortname"
)
service_fee_type = serializers.SlugRelatedField(read_only=True, slug_field="name")

class Meta:
model = ServiceFee
fields = (
"permit_department",
"service_fee_type",
"time_spent_on_task",
"monetary_amount",
)


class PostFinanceTransactionPrintSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
repr = super(PostFinanceTransactionPrintSerializer, self).to_representation(
Expand Down Expand Up @@ -338,6 +355,7 @@ class Meta:
"forms_names",
"current_inquiry",
"price",
"service_fees_total_price",
"sent_date",
)

Expand Down Expand Up @@ -638,6 +656,7 @@ class SubmissionPrintSerializer(gis_serializers.GeoFeatureModelSerializer):
read_only=True, source="author.userprofile", default=None
)
validations = SubmissionValidationSerializer(source="*", read_only=True)
service_fee = SubmissionServiceFeeSerializer(many=True, read_only=True)

def get_creditor_type(self, obj):
if obj.creditor_type is not None:
Expand Down Expand Up @@ -673,6 +692,7 @@ class Meta:
"author",
"geo_envelop",
"validations",
"service_fee",
)

@classmethod
Expand Down Expand Up @@ -771,6 +791,7 @@ def get_agenda_form_fields(value, detailed, available_filters):
obj = value.get_selected_forms().all()
form_fields = obj.values(
"submission__featured_agenda",
"submission__status_agenda",
"field_values__field__name",
"field_values__field__api_name",
"field_values__value__val",
Expand Down Expand Up @@ -869,6 +890,11 @@ def get_agenda_form_fields(value, detailed, available_filters):
]

result["properties"]["featured"] = field["submission__featured_agenda"]
result["properties"]["status"] = (
field["submission__status_agenda"]
if field["submission__status_agenda"] != "null"
else None
)

# Custom way to retrieve starts_at and ends_at for both light and detailed
geo_time_qs = value.geo_time.all()
Expand Down
4 changes: 3 additions & 1 deletion geocity/apps/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,6 @@ def get_queryset(self, geom_type=None):
),
to_attr="current_inquiries_filtered",
)

qs = (
Submission.objects.filter(base_filter)
.filter(
Expand All @@ -263,6 +262,9 @@ def get_queryset(self, geom_type=None):
.prefetch_related(geotime_prefetch)
.prefetch_related(current_inquiry_prefetch)
.prefetch_related("selected_forms", "contacts")
.prefetch_related("service_fee")
.prefetch_related("service_fee__permit_department")
.prefetch_related("service_fee__service_fee_type")
.select_related(
"administrative_entity",
"author",
Expand Down
Loading

0 comments on commit 7b07deb

Please sign in to comment.