diff --git a/backend/src/am_app/assort_management/output/queries.py b/backend/src/am_app/assort_management/output/queries.py index d67b248dc076cf09f2f27bde20aa6c3a32af31ea..2414adabe0bb12a82f215535ec3ab56315461e8c 100644 --- a/backend/src/am_app/assort_management/output/queries.py +++ b/backend/src/am_app/assort_management/output/queries.py @@ -31,11 +31,21 @@ def get_list_articles(group_products, category_id, language_id): @execute_sql() def get_detail_inf0_by_article(category_id, article_stock_unit_id): - return "SELECT act.id, act.action_type, act.shop_id, act.stock, asp.price sales_price, ppa.purchase_price FROM " \ - "am_app_assortaction act LEFT JOIN am_app_articlesalesprice asp ON act.article_stock_unit_id = " \ - "asp.article_stock_unit_id AND asp.shop_id = act.shop_id AND (asp.date_start <= current_date " \ - "AND asp.date_finish >= current_date) LEFT JOIN am_app_purchasepricesassort ppa ON " \ - "act.article_stock_unit_id = ppa.article_stock_unit_id AND ppa.is_main_supplier = 'true' " \ - "AND (ppa.date_start <= current_date AND ppa.date_end >= current_date)" \ - "WHERE act.state = 0 AND act.category_id = %s AND act.article_stock_unit_id = %s", \ - (category_id, article_stock_unit_id) + return ''' + SELECT + act.id, + act.action_type, + s.ex_system_code_shop_id public.get_stock_for_shop_article( + act.article_stock_unit_id act.shop_id + ), + public.get_max_sales_price_for_article (act.article_stock_unit_id), + public.supply_price_for_article (act.article_stock_unit_id) + FROM + am_app_assortaction act, + am_app_shop s + WHERE + act.state = 0 + and s.id = act.shop_id + AND act.category_id = %s + AND act.article_stock_unit_id = %s; + ''', (category_id, article_stock_unit_id) diff --git a/backend/src/am_app/assort_management/search/serializers.py b/backend/src/am_app/assort_management/search/serializers.py index d0c17e99f8a519be8b7806a9ffc471f152102555..01fb3415a983d932f4382ce518425761a5343b38 100644 --- a/backend/src/am_app/assort_management/search/serializers.py +++ b/backend/src/am_app/assort_management/search/serializers.py @@ -6,7 +6,7 @@ from am_app.assort_management.common.articles.serializers import ArticleSerializ class ArticleSearchSerializer(serializers.Serializer): group_products = serializers.ListSerializer(child=serializers.IntegerField()) method = serializers.IntegerField(min_value=1, max_value=3) - string_search = serializers.CharField(max_length=255) + string_search = serializers.CharField(max_length=255, required=False) class ArticleSearchProductSerializer(serializers.Serializer): diff --git a/backend/src/am_app/assort_structure/clustering/common/serializers.py b/backend/src/am_app/assort_structure/clustering/common/serializers.py index 31a40ce60b9df722cbf5249198c709495c6422c7..8de3abab2e85ecde404adaef9cdaaa1cdf6d0991 100644 --- a/backend/src/am_app/assort_structure/clustering/common/serializers.py +++ b/backend/src/am_app/assort_structure/clustering/common/serializers.py @@ -44,11 +44,18 @@ class ClusterSetSerializer(serializers.ModelSerializer): conformation_state = serializers.IntegerField(min_value=0, max_value=3, default=0) def get_count_shops_in_cluster(self, obj: Cluster): - return obj.clustershoplink_set.filter(date_end__gt=datetime.date.today(), is_active=True).count() + return obj.clustershoplink_set.filter( + date_end__gt=datetime.date.today(), + is_active=True, + shop_type=1 + ).count() @lru_cache def get_total_shops(self, obj: Cluster): - return Shop.objects.count() + return Shop.objects.filter( + is_active=True, + shop_type=1 + ).count() class Meta: model = Cluster diff --git a/backend/src/am_app/assort_structure/clustering/group_shops/queries.py b/backend/src/am_app/assort_structure/clustering/group_shops/queries.py index 954d62eb2b73d9c5ccf1c2f45da9692936bfde49..31be5305546ed306bab1efd2e9b3b292b156186c 100644 --- a/backend/src/am_app/assort_structure/clustering/group_shops/queries.py +++ b/backend/src/am_app/assort_structure/clustering/group_shops/queries.py @@ -2,9 +2,54 @@ from am_app.common.functions import execute_sql @execute_sql(is_json=True) -def get_group_shops(): - return "SELECT json_build_object('id', a.id, 'name', a.name, 'parent', a.parent_id, 'shops_exist', " \ - "a.shops_exist) FROM (SELECT DISTINCT gs.id as id, gs.name as name, gs.parent_id as parent_id, " \ - "case when (gs.id = s.shop_group_id and s.is_active = 'true') then 'true' else 'false' end as " \ - "shops_exist FROM am_app_groupshops gs LEFT JOIN am_app_shop s on gs.id = s.shop_group_id ORDER BY " \ - "gs.parent_id DESC , gs.name) a" +def query_group_shops(): + return ''' + SELECT + json_build_object( + 'id', a.id, 'name', a.name, 'parent', + a.parent_id, 'shops_exist', a.shops_exist + ) + FROM + ( + SELECT + DISTINCT gs.id as id, + gs.name as name, + gs.parent_id as parent_id, + case when ( + gs.id = s.shop_group_id + and s.is_active = 'true' + ) then 'true' else 'false' end as shops_exist + FROM + am_app_groupshops gs + LEFT JOIN am_app_shop s on gs.id = s.shop_group_id + ORDER BY + gs.parent_id DESC, + gs.name + ) a + ''' + +@execute_sql(is_json=False) +def query_cluster_shop_relation(cl_id: int, shop_id: int): + return f''' + select + count (*) + from + am_app_cluster c, + am_app_assortmatrix m, + am_app_clustershoplink l + where + c.is_actual = 'true' + and c.assort_matrix_id = m.id + and c.id = l.cluster_id + and l.is_active = 'true' + and c.id <> %s --- не текущий кластер + and shop_id = %s --- магазин + and assort_matrix_id = ( + select + cl.assort_matrix_id + from + am_app_cluster cl + where + cl.id = %s + ) --- кластер + ''', (cl_id, shop_id, cl_id) \ No newline at end of file diff --git a/backend/src/am_app/assort_structure/clustering/group_shops/services.py b/backend/src/am_app/assort_structure/clustering/group_shops/services.py new file mode 100644 index 0000000000000000000000000000000000000000..7b60d55bb83d8139c57b064b22dbf011a487431e --- /dev/null +++ b/backend/src/am_app/assort_structure/clustering/group_shops/services.py @@ -0,0 +1,16 @@ +from .queries import * + + +def get_group_shops(cluster_id: int): + group_shops = query_group_shops() + + for shop in group_shops: + shop_id = shop.get('id') + data = query_cluster_shop_relation(cluster_id, shop_id)[0] + + if data['count'] > 0: + shop['cluster_shop_relation'] = True + if data['count'] <= 0: + shop['cluster_shop_relation'] = False + + return group_shops \ No newline at end of file diff --git a/backend/src/am_app/assort_structure/clustering/group_shops/shops/queries.py b/backend/src/am_app/assort_structure/clustering/group_shops/shops/queries.py index 87177027e2bf157819ce2f756fde7daf5d10512b..2b5e825ee43ae800525eb779a3b2673c1eb54d79 100644 --- a/backend/src/am_app/assort_structure/clustering/group_shops/shops/queries.py +++ b/backend/src/am_app/assort_structure/clustering/group_shops/shops/queries.py @@ -11,6 +11,6 @@ def get_shops(group_shop): ) FROM ( SELECT id,ex_system_code_shop_id, physical_address - FROM am_app_shop aas WHERE aas.shop_group_id = %s ORDER BY physical_address + FROM am_app_shop aas WHERE aas.shop_group_id = %s and aas.shop_type = 1 ORDER BY physical_address ) as t """, (group_shop,) diff --git a/backend/src/am_app/assort_structure/clustering/group_shops/urls.py b/backend/src/am_app/assort_structure/clustering/group_shops/urls.py index 5b36546e5ecd34a04d4f825dbad7009f6c909853..138b883d73cec1755eca54e96b2b3fdf66fafa6f 100644 --- a/backend/src/am_app/assort_structure/clustering/group_shops/urls.py +++ b/backend/src/am_app/assort_structure/clustering/group_shops/urls.py @@ -2,6 +2,6 @@ from django.urls import path, include from .views import * urlpatterns = [ - path('', GroupShopsListView.as_view()), + path('/', GroupShopsListView.as_view()), path('/shops/', include('am_app.assort_structure.clustering.group_shops.shops.urls')), ] diff --git a/backend/src/am_app/assort_structure/clustering/group_shops/views.py b/backend/src/am_app/assort_structure/clustering/group_shops/views.py index 26d25bb9b30b5b649544439a11081194488c6d90..d941dcff825cf4e06cf6d710574e85ea7cc7b3eb 100644 --- a/backend/src/am_app/assort_structure/clustering/group_shops/views.py +++ b/backend/src/am_app/assort_structure/clustering/group_shops/views.py @@ -8,17 +8,18 @@ from am_app.common.permissions import IsAuthenticated, AccessLevelTwoPermission from .queries import * from .serializers import * +from .services import * class GroupShopsListView(APIView): permission_classes = [IsAuthenticated, AccessLevelTwoPermission] - queryset = GroupShops.objects.all().order_by('pk') @swagger_auto_schema( - tags=["Кластеризация", "Магазины"], operation_summary="Вывести группы магазинов магазины(филиалы)", + tags=["Кластеризация", "Магазины"], + operation_summary="Вывести группы магазинов магазины(филиалы)", responses={200: GroupShopsListSerializer(many=True)} ) - def get(self, request): - group_shops = get_group_shops() + def get(self, request, cluster_id): + group_shops = get_group_shops(cluster_id) return Response(group_shops) diff --git a/backend/src/am_app/assort_structure/confirm_clustering/queries.py b/backend/src/am_app/assort_structure/confirm_clustering/queries.py index b9fbaec4c3adfd09293b0dcf27532de5e7918ff0..d7abd366837e78516a7b526e38653c7aaaa48c38 100644 --- a/backend/src/am_app/assort_structure/confirm_clustering/queries.py +++ b/backend/src/am_app/assort_structure/confirm_clustering/queries.py @@ -75,7 +75,7 @@ def get_count_clusters(user_id: int, search_string: str = ''): @execute_sql() def get_count_shops(): - return """SELECT count(*) as total_shops FROM am_app_shop WHERE is_active = true;""" + return """SELECT count(*) as total_shops FROM am_app_shop WHERE is_active = true AND shop_type = 1;""" @execute_sql() diff --git a/backend/src/am_app/assort_structure/mapping/services.py b/backend/src/am_app/assort_structure/mapping/services.py index ad2b618d409d4cbd49f60180839bd2685d903e96..afb0f93ba7e4ff4aecf83e4f8d128e4c0f9abc4c 100644 --- a/backend/src/am_app/assort_structure/mapping/services.py +++ b/backend/src/am_app/assort_structure/mapping/services.py @@ -1,6 +1,6 @@ from django.http import Http404 from rest_framework.status import HTTP_201_CREATED, HTTP_404_NOT_FOUND, HTTP_200_OK, HTTP_418_IM_A_TEAPOT -from am_app.models import Category, GroupProduct, CategoryGroupProductLink +from am_app.models import Category, GroupProduct, CategoryGroupProductLink, Language from am_app.assort_structure.mapping.serializers import LinkListSerializer @@ -10,6 +10,11 @@ def create_link(category_id, group_product_id, username): link.save() return link +def get_language_pks(): + return Language.objects.values_list( + 'id', + flat=True + ) def get_filter_list(data, queryset): def apply(item): diff --git a/backend/src/am_app/assort_structure/mapping/views.py b/backend/src/am_app/assort_structure/mapping/views.py index 86c68f7573416a9c21612ceb3df146f148443673..8d5a162740da57961a81bdd50236a45215f7b58e 100644 --- a/backend/src/am_app/assort_structure/mapping/views.py +++ b/backend/src/am_app/assort_structure/mapping/views.py @@ -29,6 +29,7 @@ from am_app.models import ( from .serializers import * from .services import ( associate_category_with_group_product, + get_language_pks, unlink_category_with_group_product, CategoryTree ) @@ -82,11 +83,18 @@ class CategoryView(APIView): type_id=serializer.validated_data.pop('type') ) category.save() - CategoryDictionary.objects.create(translation=serializer.validated_data.pop('name'), - user_created=self.request.user.username, - user_updated=self.request.user.username, - category_id=category.pk, - language_id=self.request.user.language.pk) + + language_pks = get_language_pks() + + for language_pk in language_pks: + CategoryDictionary.objects.create( + translation=serializer.validated_data.pop('name'), + user_created=self.request.user.username, + user_updated=self.request.user.username, + category_id=category.pk, + language_id=language_pk + ) + serializer = CategoryDetailSerializer(category) return Response(serializer.data) diff --git a/backend/src/am_app/common/permissions.py b/backend/src/am_app/common/permissions.py index 460ac7f385dc6ee921ffd90cc4f47cd7966d79e9..a29c8203ddf406acff916692a67cc7aaa30a1fca 100644 --- a/backend/src/am_app/common/permissions.py +++ b/backend/src/am_app/common/permissions.py @@ -1,18 +1,19 @@ +from os import access from rest_framework.permissions import BasePermission from rest_framework.views import View from rest_framework.request import Request from am_app.models import RightForRole, CustomUser - -class IsOwner(BasePermission): - message = "Вы не являетесь владельцем для выполнения данного действия." +class IsOwnerOrHasPermission(BasePermission): + message = "Вы не являетесь владельцем или у вас недостаточно прав для выполнения данного действия." def has_permission(self, request, view): return request.user and request.user.is_authenticated def has_object_permission(self, request, view, obj: CustomUser): + is_write_persmission = AccessLevelFivePermission().has_permission(request, view) if request.method in ['PUT', 'PATCH']: - return obj == request.user + return obj == request.user or is_write_persmission return True diff --git a/backend/src/am_app/users/category/queries.py b/backend/src/am_app/users/category/queries.py index 153c831eab928db4030ee8eb1354de19d42d68fe..83060c30431e3d9e5f2a280a99c6ef0f1d8cd614 100644 --- a/backend/src/am_app/users/category/queries.py +++ b/backend/src/am_app/users/category/queries.py @@ -4,13 +4,30 @@ from am_app.common.functions import execute_sql @execute_sql() def get_category(language_id: int): return """ - SELECT aac.id, - aac.level, - aac.type_id as type, - aac.parent_id as parent, - COALESCE(a.translation, 'No traslation ' || aac.id) as name - FROM am_app_category aac - LEFT JOIN am_app_categorydictionary a on aac.id = a.category_id AND language_id = %s - WHERE aac.state = true - ORDER BY aac.parent_id DESC, aac.level + SELECT + aac.id, + aac.level, + aac.type_id as type, + aac.parent_id as parent, + COALESCE( + a.translation, 'No traslation ' || aac.id + ) as name + FROM + am_app_category aac + LEFT JOIN am_app_categorydictionary a on aac.id = a.category_id + AND language_id = %s + WHERE + aac.state = true + and aac.id in ( + select + l.category_id + from + am_app_categorygroupproductlink l + where + l.state = 'true' + ) + ORDER BY + name, + aac.parent_id DESC, + aac.level """, (language_id,) diff --git a/backend/src/am_app/users/users/password/serializers.py b/backend/src/am_app/users/users/password/serializers.py index 125356b329c9a8ec4b3a82b57c5e2e8df9dd4375..6b0f45c1e31b783a90b6c9cd86fb194ac6d73282 100644 --- a/backend/src/am_app/users/users/password/serializers.py +++ b/backend/src/am_app/users/users/password/serializers.py @@ -11,13 +11,13 @@ from .error_service import InvalidPasswordError class PasswordSerialiser(serializers.Serializer): - old_password = serializers.CharField(max_length=150, allow_null=False, required=True) + # old_password = serializers.CharField(max_length=150, allow_null=False, required=True) new_password = serializers.CharField(max_length=150, allow_null=False, required=True) - def validate_old_password(self, value: str): - if self.context.user.check_password(value): - return value - raise ValidationError([InvalidPasswordError().as_dict()]) + # def validate_old_password(self, value: str): + # if self.context.user.check_password(value): + # return value + # raise ValidationError([InvalidPasswordError().as_dict()]) def validated_new_password(self, value): """Converting Django Errors to Standard Application Errors""" diff --git a/backend/src/am_app/users/users/password/views.py b/backend/src/am_app/users/users/password/views.py index e1b79d9248b14f236aa5a3dda3fba5723c9e4f05..aba8e8f781688908d1272dcb024941987856e271 100644 --- a/backend/src/am_app/users/users/password/views.py +++ b/backend/src/am_app/users/users/password/views.py @@ -3,17 +3,18 @@ from rest_framework.response import Response from rest_framework import views, status from am_app.models import CustomUser -from am_app.common.permissions import IsAuthenticated, IsOwner +from am_app.common.permissions import IsAuthenticated, IsOwnerOrHasPermission from am_app.common.functions import get_object from .serializers import * class ChangePasswordView(views.APIView): - permission_classes = [IsAuthenticated, IsOwner] + permission_classes = [IsAuthenticated, IsOwnerOrHasPermission] @swagger_auto_schema( - tags=['Модуль "Пользователи"', 'Пользователи'], operation_summary="Изменить пароль, меняет только владелец", + tags=['Модуль "Пользователи"', 'Пользователи'], + operation_summary="Изменить пароль", request_body=PasswordSerialiser() ) def patch(self, request, *args, **kwargs):