Skip to content

Commit

Permalink
Merge pull request #62 from b2b-marketplace/feature/company_registration
Browse files Browse the repository at this point in the history
регистрация компании
  • Loading branch information
ByJIaT authored Aug 16, 2023
2 parents fe55be5 + cc44289 commit ab14554
Show file tree
Hide file tree
Showing 25 changed files with 2,110 additions and 982 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check_codestyle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.9
python-version: 3.11
-
name: Install Poetry
uses: snok/install-poetry@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check_migrations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.9"
python-version: "3.11"
-
name: Install Poetry
uses: snok/install-poetry@v1
Expand Down
24 changes: 24 additions & 0 deletions apps/core/routers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from rest_framework.routers import DynamicRoute, SimpleRouter


class DynamicRouter(SimpleRouter):
"""Роутер для динамических маршрутов."""

routes = [
# Dynamically generated list routes. Generated using
# @action(detail=False) decorator on methods of the viewset.
DynamicRoute(
url=r"^{prefix}/{url_path}{trailing_slash}$",
name="{basename}-{url_name}",
detail=False,
initkwargs={},
),
# Dynamically generated detail routes. Generated using
# @action(detail=True) decorator on methods of the viewset.
DynamicRoute(
url=r"^{prefix}/{lookup}/{url_path}{trailing_slash}$",
name="{basename}-{url_name}",
detail=True,
initkwargs={},
),
]
1 change: 1 addition & 0 deletions apps/users/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class CustomUserAdmin(UserAdmin):
"username",
"email",
"is_company",
"is_active",
)
list_filter = ("is_company",)
empty_value_display = "-empty-"
Expand Down
20 changes: 20 additions & 0 deletions apps/users/migrations/0002_alter_customuser_managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.1 on 2023-08-14 16:43

from django.db import migrations

import apps.users.models


class Migration(migrations.Migration):
dependencies = [
("users", "0001_initial"),
]

operations = [
migrations.AlterModelManagers(
name="customuser",
managers=[
("objects", apps.users.models.CustomUserManager()),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Generated by Django 4.1 on 2023-08-16 04:56

from django.db import migrations, models

import apps.users.models


class Migration(migrations.Migration):
dependencies = [
("users", "0002_alter_customuser_managers"),
]

operations = [
migrations.AlterField(
model_name="company",
name="company_account",
field=models.CharField(
max_length=20,
null=True,
unique=True,
validators=[
apps.users.models.validate_account,
apps.users.models.validate_digits_only,
],
verbose_name="Account",
),
),
migrations.AlterField(
model_name="company",
name="ogrn",
field=models.CharField(
max_length=13,
null=True,
unique=True,
validators=[
apps.users.models.validate_ogrn,
apps.users.models.validate_digits_only,
],
verbose_name="PSRN",
),
),
]
12 changes: 12 additions & 0 deletions apps/users/migrations/0004_merge_20230816_0511.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Generated by Django 4.1 on 2023-08-16 05:11

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("users", "0002_alter_address_options_alter_address_address_and_more"),
("users", "0003_alter_company_company_account_alter_company_ogrn"),
]

operations = []
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 4.1 on 2023-08-16 05:17

from django.db import migrations, models

import apps.users.models


class Migration(migrations.Migration):
dependencies = [
("users", "0004_merge_20230816_0511"),
]

operations = [
migrations.AlterField(
model_name="company",
name="company_account",
field=models.CharField(
blank=True,
max_length=20,
null=True,
unique=True,
validators=[
apps.users.models.validate_account,
apps.users.models.validate_digits_only,
],
verbose_name="Account",
),
),
migrations.AlterField(
model_name="company",
name="ogrn",
field=models.CharField(
blank=True,
max_length=13,
null=True,
unique=True,
validators=[
apps.users.models.validate_ogrn,
apps.users.models.validate_digits_only,
],
verbose_name="PSRN",
),
),
]
25 changes: 24 additions & 1 deletion apps/users/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import re

from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import AbstractUser, UserManager
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _


Expand Down Expand Up @@ -86,6 +87,8 @@ class Company(models.Model):
unique=True,
validators=[validate_account, validate_digits_only],
verbose_name=_("Account"),
null=True,
blank=True,
)
inn = models.CharField(
max_length=10,
Expand All @@ -98,6 +101,8 @@ class Company(models.Model):
unique=True,
validators=[validate_ogrn, validate_digits_only],
verbose_name=_("PSRN"),
null=True,
blank=True,
)
phone_number = models.ForeignKey(PhoneNumber, on_delete=models.SET_NULL, null=True, blank=False)
address = models.ForeignKey(Address, on_delete=models.SET_NULL, null=True, blank=True)
Expand Down Expand Up @@ -132,6 +137,13 @@ def __str__(self):
return f"{self.first_name} {self.last_name}"


class CustomUserManager(UserManager):
def get_companies(self):
return self.filter(Q(is_company=True) & Q(is_active=True)).select_related(
"company", "company__address", "company__phone_number"
)


class CustomUser(AbstractUser):
email = models.EmailField(unique=True, blank=False, max_length=254, verbose_name=_("Email"))
username = models.CharField(
Expand All @@ -158,13 +170,16 @@ class CustomUser(AbstractUser):
on_delete=models.SET_NULL,
)

objects = CustomUserManager()

class Meta:
swappable = "AUTH_USER_MODEL"
ordering = ("username",)
verbose_name = _("User")
verbose_name_plural = _("Users")

def clean(self):
super().clean()
if self.is_company and not self.company:
raise ValidationError(_("Company field is required for companies!"))
if not (self.is_superuser or self.is_staff) and not (self.is_company or self.personal):
Expand All @@ -182,3 +197,11 @@ def save(self, *args, **kwargs):

def __str__(self):
return self.username

def delete(self):
"""Предотвращает удаление модели.
Вместо непосредственного удаления, помечает запись удалённой (is_active=True).
"""
self.is_active = False
self.save()
Empty file.
11 changes: 11 additions & 0 deletions apps/users/serializers/addresses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from rest_framework import serializers

from apps.users.models import Address


class AddressSerializer(serializers.ModelSerializer):
"""Сериализатор для получения данных оо адресе."""

class Meta:
model = Address
fields = ("id", "address")
58 changes: 58 additions & 0 deletions apps/users/serializers/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from django.contrib.auth import get_user_model
from django.db import transaction
from djoser.conf import settings
from rest_framework import serializers

from apps.users.models import Address, PhoneNumber

User = get_user_model()


class BaseSerializer(serializers.ModelSerializer):
"""Абстрактный сериализатор для создания нового пользователя."""

password = serializers.CharField(style={"input_type": "password"}, write_only=True)

def perform_create(self, validated_data, **fields):
"""Создает пользователя."""
with transaction.atomic():
user = User.objects.create_user(**validated_data, **fields)
if settings.SEND_ACTIVATION_EMAIL:
user.is_active = False
user.save(update_fields=["is_active"])
return user

def _address_phone_attach(self, obj):
"""Создает объекты адреса и номера телефона."""
address = obj.pop("address", None)
phone_number = obj.pop("phone_number", None)

address_obj = Address.objects.create(**address)
phone_number_obj = PhoneNumber.objects.create(**phone_number)

return {"address": address_obj, "phone_number": phone_number_obj}

def _extract_relations(self, validated_data):
"""Извлекает один уровень вложенных отношений."""
reverse_relations = {}
for field_name, field in self.fields.items():
if isinstance(field, serializers.ModelSerializer | serializers.ListSerializer):
if field.source not in validated_data:
continue

reverse_relations[field_name] = (
self.fields[field_name].Meta.model,
validated_data.pop(field_name),
)
return reverse_relations

def update_or_create(self, validated_data):
"""Создает объекты компании или физ. лица."""
reverse_relations = {}
relations = self._extract_relations(validated_data)

for field_name, (model, data) in relations.items():
with transaction.atomic():
address_phone = self._address_phone_attach(data)
reverse_relations[field_name] = model.objects.create(**data, **address_phone)
return reverse_relations
Loading

0 comments on commit ab14554

Please sign in to comment.