Compare commits
4 Commits
b31272511c
...
cfe2f68305
| Author | SHA1 | Date | |
|---|---|---|---|
| cfe2f68305 | |||
| 8da934bae7 | |||
| 1761f57fde | |||
| 4e5360553a |
|
|
@ -21,4 +21,7 @@ CURRENCY_GETGEOIP_API_KEY=""
|
||||||
FLOWER_BASIC_AUTH="login:pwd"
|
FLOWER_BASIC_AUTH="login:pwd"
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
SENTRY_DSN=""
|
SENTRY_DSN=""
|
||||||
|
|
||||||
|
# production/stage
|
||||||
|
SENTRY_ENVIRONMENT=""
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import User, BonusProgramTransaction
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
@admin.register(User)
|
@admin.register(User)
|
||||||
|
|
@ -11,14 +11,3 @@ class UserAdmin(admin.ModelAdmin):
|
||||||
return User.objects.with_base_related()
|
return User.objects.with_base_related()
|
||||||
|
|
||||||
|
|
||||||
@admin.register(BonusProgramTransaction)
|
|
||||||
class BonusProgramTransactionAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('id', 'type', 'user', 'date', 'amount', 'comment', 'order', 'was_cancelled')
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
|
||||||
return BonusProgramTransaction.objects.with_base_related()
|
|
||||||
|
|
||||||
def delete_queryset(self, request, queryset):
|
|
||||||
for obj in queryset:
|
|
||||||
obj.cancel()
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from django.db import migrations, models
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
|
|
||||||
import account.models
|
import account.models
|
||||||
|
import bonus_program.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
@ -64,7 +65,7 @@ class Migration(migrations.Migration):
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('balance', models.PositiveSmallIntegerField(default=0, verbose_name='Баланс, руб')),
|
('balance', models.PositiveSmallIntegerField(default=0, verbose_name='Баланс, руб')),
|
||||||
('referral_code', models.CharField(default=account.models.generate_referral_code, editable=False, max_length=9)),
|
('referral_code', models.CharField(default=bonus_program.models.generate_referral_code, editable=False, max_length=9)),
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
# Generated by Django 4.2.2 on 2024-04-07 17:36
|
# Generated by Django 4.2.2 on 2024-04-07 17:36
|
||||||
|
|
||||||
import account.models
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
import account.models
|
import bonus_program.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
@ -25,6 +24,6 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name='user',
|
||||||
name='referral_code',
|
name='referral_code',
|
||||||
field=models.CharField(default=account.models.generate_referral_code, editable=False, max_length=10),
|
field=models.CharField(default=bonus_program.models.generate_referral_code, editable=False, max_length=10),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1 @@
|
||||||
from .bonus import (generate_referral_code, BonusType, BonusProgramMixin, BonusProgram,
|
|
||||||
BonusProgramTransaction, BonusProgramTransactionQuerySet)
|
|
||||||
from .user import User, UserManager, UserQuerySet, ReferralRelationship
|
from .user import User, UserManager, UserQuerySet, ReferralRelationship
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from phonenumber_field.modelfields import PhoneNumberField
|
from phonenumber_field.modelfields import PhoneNumberField
|
||||||
from phonenumber_field.phonenumber import PhoneNumber
|
from phonenumber_field.phonenumber import PhoneNumber
|
||||||
|
|
||||||
from account.models import BonusProgramMixin
|
from bonus_program.models import BonusProgramMixin, BonusProgram
|
||||||
from account.models.bonus import BonusProgram
|
|
||||||
from store.utils import concat_not_null_values
|
from store.utils import concat_not_null_values
|
||||||
from tg_bot.tasks import send_tg_message
|
from tg_bot.tasks import send_tg_message
|
||||||
|
|
||||||
|
|
@ -179,6 +178,11 @@ class User(BonusProgramMixin, AbstractUser):
|
||||||
.annotate(_orders_count=Count('customer_orders'))
|
.annotate(_orders_count=Count('customer_orders'))
|
||||||
.filter(_orders_count__gt=0))
|
.filter(_orders_count__gt=0))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def completed_orders_count(self):
|
||||||
|
from store.models import Checklist
|
||||||
|
return Checklist.objects.filter(customer_id=self.id, status=Checklist.Status.COMPLETED).count()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def inviter(self):
|
def inviter(self):
|
||||||
return User.objects.filter(user_invited__invited=self.id).first()
|
return User.objects.filter(user_invited__invited=self.id).first()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ from djoser.conf import settings as djoser_settings
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.exceptions import AuthenticationFailed
|
from rest_framework.exceptions import AuthenticationFailed
|
||||||
|
|
||||||
from .models import User, BonusProgramTransaction, BonusType
|
from bonus_program.serializers import BonusProgramTransactionSerializer
|
||||||
|
from .models import User
|
||||||
|
from bonus_program.models import BonusType
|
||||||
from .utils import verify_telegram_authentication
|
from .utils import verify_telegram_authentication
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -24,15 +26,6 @@ class UserSerializer(serializers.ModelSerializer):
|
||||||
return obj.invited_users_with_orders.count()
|
return obj.invited_users_with_orders.count()
|
||||||
|
|
||||||
|
|
||||||
class BonusProgramTransactionSerializer(serializers.ModelSerializer):
|
|
||||||
order_id = serializers.StringRelatedField(source='order.id', allow_null=True)
|
|
||||||
type = serializers.CharField(source='get_type_display')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = BonusProgramTransaction
|
|
||||||
fields = ('id', 'type', 'date', 'amount', 'order_id', 'comment', 'was_cancelled')
|
|
||||||
|
|
||||||
|
|
||||||
def non_zero_validator(value):
|
def non_zero_validator(value):
|
||||||
if value == 0:
|
if value == 0:
|
||||||
raise serializers.ValidationError("Value cannot be zero")
|
raise serializers.ValidationError("Value cannot be zero")
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ import logging
|
||||||
from django.db.models.signals import post_save, post_delete
|
from django.db.models.signals import post_save, post_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from account.models import User, ReferralRelationship, BonusProgramTransaction
|
from account.models import User, ReferralRelationship
|
||||||
|
from bonus_program.models import BonusProgramTransaction
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ from rest_framework.renderers import StaticHTMLRenderer
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from account.models import User
|
from account.models import User
|
||||||
from account.serializers import SetInitialPasswordSerializer, BonusProgramTransactionSerializer, \
|
from account.serializers import SetInitialPasswordSerializer, UserBalanceUpdateSerializer, TelegramCallbackSerializer
|
||||||
UserBalanceUpdateSerializer, TelegramCallbackSerializer
|
from bonus_program.serializers import BonusProgramTransactionSerializer
|
||||||
from tg_bot.handlers.start import request_phone_sync
|
from tg_bot.handlers.start import request_phone_sync
|
||||||
from tg_bot.messages import TGCoreMessage
|
from tg_bot.messages import TGCoreMessage
|
||||||
|
|
||||||
|
|
|
||||||
0
bonus_program/__init__.py
Normal file
0
bonus_program/__init__.py
Normal file
16
bonus_program/admin.py
Normal file
16
bonus_program/admin.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from bonus_program.models import BonusProgramTransaction
|
||||||
|
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
@admin.register(BonusProgramTransaction)
|
||||||
|
class BonusProgramTransactionAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('id', 'type', 'user', 'date', 'amount', 'comment', 'order', 'was_cancelled')
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
return BonusProgramTransaction.objects.with_base_related()
|
||||||
|
|
||||||
|
def delete_queryset(self, request, queryset):
|
||||||
|
for obj in queryset:
|
||||||
|
obj.cancel()
|
||||||
6
bonus_program/apps.py
Normal file
6
bonus_program/apps.py
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class BonusProgramConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'bonus_program'
|
||||||
0
bonus_program/migrations/__init__.py
Normal file
0
bonus_program/migrations/__init__.py
Normal file
|
|
@ -10,6 +10,7 @@ from django.utils.formats import localize
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
from core.models import BonusProgramConfig
|
from core.models import BonusProgramConfig
|
||||||
|
from store.models import Checklist
|
||||||
from tg_bot.messages import TGBonusMessage
|
from tg_bot.messages import TGBonusMessage
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -76,7 +77,7 @@ class BonusProgramTransaction(models.Model):
|
||||||
""" Represents the history of all bonus program transactions """
|
""" Represents the history of all bonus program transactions """
|
||||||
|
|
||||||
type = models.PositiveSmallIntegerField('Тип транзакции', choices=BonusType.CHOICES)
|
type = models.PositiveSmallIntegerField('Тип транзакции', choices=BonusType.CHOICES)
|
||||||
user = models.ForeignKey('User', verbose_name='Пользователь транзакции', on_delete=models.CASCADE, related_name='bonus_transactions')
|
user = models.ForeignKey('account.User', verbose_name='Пользователь транзакции', on_delete=models.CASCADE, related_name='bonus_transactions')
|
||||||
date = models.DateTimeField('Дата транзакции', auto_now_add=True)
|
date = models.DateTimeField('Дата транзакции', auto_now_add=True)
|
||||||
amount = models.SmallIntegerField('Количество, руб')
|
amount = models.SmallIntegerField('Количество, руб')
|
||||||
comment = models.CharField('Комментарий', max_length=200, null=True, blank=True)
|
comment = models.CharField('Комментарий', max_length=200, null=True, blank=True)
|
||||||
|
|
@ -273,9 +274,8 @@ class BonusProgram:
|
||||||
user.update_balance(amount, bonus_type)
|
user.update_balance(amount, bonus_type)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_order_bonus(order: 'Checklist'):
|
def add_order_bonus(order: Checklist):
|
||||||
bonus_type = BonusType.DEFAULT_PURCHASE
|
bonus_type = BonusType.DEFAULT_PURCHASE
|
||||||
amount = BonusProgramConfig.load().amount_default_purchase
|
|
||||||
|
|
||||||
# Check if data is sufficient
|
# Check if data is sufficient
|
||||||
if order is None or order.customer_id is None:
|
if order is None or order.customer_id is None:
|
||||||
|
|
@ -285,11 +285,14 @@ class BonusProgram:
|
||||||
if order.status != settings.BONUS_ELIGIBILITY_STATUS:
|
if order.status != settings.BONUS_ELIGIBILITY_STATUS:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
level = BonusProgramLevel.objects.level_for_order_count(order.customer.completed_orders_count)
|
||||||
|
amount = getattr(level, 'amount_default_purchase', 0)
|
||||||
|
|
||||||
# Add bonuses
|
# Add bonuses
|
||||||
order.customer.update_balance(amount, bonus_type, order=order)
|
order.customer.update_balance(amount, bonus_type, order=order)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_referral_bonus(order: 'Checklist', for_inviter: bool):
|
def add_referral_bonus(order: Checklist, for_inviter: bool):
|
||||||
amount = BonusProgramConfig.load().amount_referral
|
amount = BonusProgramConfig.load().amount_referral
|
||||||
|
|
||||||
# Check if data is sufficient
|
# Check if data is sufficient
|
||||||
|
|
@ -306,3 +309,17 @@ class BonusProgram:
|
||||||
|
|
||||||
# Add bonuses
|
# Add bonuses
|
||||||
user.update_balance(amount, bonus_type, order=order)
|
user.update_balance(amount, bonus_type, order=order)
|
||||||
|
|
||||||
|
|
||||||
|
class BonusProgramLevelQuerySet(models.QuerySet):
|
||||||
|
def level_for_order_count(self, count):
|
||||||
|
return self.filter(orders_count__lt=count).order_by('-orders_count').first()
|
||||||
|
|
||||||
|
|
||||||
|
class BonusProgramLevel(models.Model):
|
||||||
|
slug = models.SlugField('Идентификатор', unique=True)
|
||||||
|
name = models.CharField('Название', max_length=30)
|
||||||
|
orders_count = models.PositiveSmallIntegerField('Минимальное количество заказов', unique=True)
|
||||||
|
amount_default_purchase = models.PositiveSmallIntegerField('Бонус за обычную покупку')
|
||||||
|
|
||||||
|
objects = BonusProgramLevelQuerySet.as_manager()
|
||||||
12
bonus_program/serializers.py
Normal file
12
bonus_program/serializers.py
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from bonus_program.models import BonusProgramTransaction
|
||||||
|
|
||||||
|
|
||||||
|
class BonusProgramTransactionSerializer(serializers.ModelSerializer):
|
||||||
|
order_id = serializers.StringRelatedField(source='order.id', allow_null=True)
|
||||||
|
type = serializers.CharField(source='get_type_display')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = BonusProgramTransaction
|
||||||
|
fields = ('id', 'type', 'date', 'amount', 'order_id', 'comment', 'was_cancelled')
|
||||||
3
bonus_program/tests.py
Normal file
3
bonus_program/tests.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
bonus_program/views.py
Normal file
3
bonus_program/views.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
|
@ -37,8 +37,6 @@ DEFAULT_CONFIG = settings.BONUS_PROGRAM_DEFAULT_CONFIG
|
||||||
class BonusProgramConfig(models.Model):
|
class BonusProgramConfig(models.Model):
|
||||||
amount_signup = models.PositiveSmallIntegerField(
|
amount_signup = models.PositiveSmallIntegerField(
|
||||||
'Бонус за регистрацию', default=DEFAULT_CONFIG['amounts']['signup'])
|
'Бонус за регистрацию', default=DEFAULT_CONFIG['amounts']['signup'])
|
||||||
amount_default_purchase = models.PositiveSmallIntegerField(
|
|
||||||
'Бонус за обычную покупку', default=DEFAULT_CONFIG['amounts']['default_purchase'])
|
|
||||||
amount_referral = models.PositiveSmallIntegerField(
|
amount_referral = models.PositiveSmallIntegerField(
|
||||||
'Реферальный бонус', default=DEFAULT_CONFIG['amounts']['referral'])
|
'Реферальный бонус', default=DEFAULT_CONFIG['amounts']['referral'])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,8 @@ INSTALLED_APPS = [
|
||||||
'account',
|
'account',
|
||||||
'store',
|
'store',
|
||||||
'tg_bot',
|
'tg_bot',
|
||||||
'core'
|
'core',
|
||||||
|
'bonus_program'
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|
@ -250,6 +251,7 @@ if SENTRY_DSN:
|
||||||
# of sampled transactions.
|
# of sampled transactions.
|
||||||
# We recommend adjusting this value in production.
|
# We recommend adjusting this value in production.
|
||||||
profiles_sample_rate=1.0,
|
profiles_sample_rate=1.0,
|
||||||
|
environment=get_secret("SENTRY_ENVIRONMENT"),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Celery
|
# Celery
|
||||||
|
|
@ -267,7 +269,15 @@ BONUS_ELIGIBILITY_STATUS = 'completed'
|
||||||
BONUS_PROGRAM_DEFAULT_CONFIG = {
|
BONUS_PROGRAM_DEFAULT_CONFIG = {
|
||||||
"amounts": {
|
"amounts": {
|
||||||
"signup": 150,
|
"signup": 150,
|
||||||
"default_purchase": 50,
|
|
||||||
"referral": 500,
|
"referral": 500,
|
||||||
}
|
},
|
||||||
|
|
||||||
|
"levels": [
|
||||||
|
# slug, name, orders_count, amount_default_purchase
|
||||||
|
("new", "Новичок", 0, 50),
|
||||||
|
("fashion", "Модник", 3, 150),
|
||||||
|
("pro", "Профессионал", 10, 250),
|
||||||
|
("shopaholic", "Шопоголик", 20, 350),
|
||||||
|
("killer", "Фэшн Киллер", 30, 500),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
from django.core.management import BaseCommand
|
from django.core.management import BaseCommand
|
||||||
|
from django.conf import settings
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
from bonus_program.models import BonusProgramLevel
|
||||||
from store.models import Category, PaymentMethod
|
from store.models import Category, PaymentMethod
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -134,10 +136,23 @@ def create_payment_types():
|
||||||
PaymentMethod.objects.get_or_create(slug=slug, defaults=data)
|
PaymentMethod.objects.get_or_create(slug=slug, defaults=data)
|
||||||
|
|
||||||
|
|
||||||
|
def create_bonus_program_levels():
|
||||||
|
for cfg in settings.BONUS_PROGRAM_DEFAULT_CONFIG['levels']:
|
||||||
|
slug, name, order_count, amount_default_purchase = cfg
|
||||||
|
BonusProgramLevel.objects.get_or_create(
|
||||||
|
slug=slug,
|
||||||
|
defaults={
|
||||||
|
'name': name,
|
||||||
|
'orders_count': order_count,
|
||||||
|
'amount_default_purchase': amount_default_purchase
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = ''' Create root categories '''
|
help = ''' Create root categories '''
|
||||||
|
|
||||||
def handle(self, *args, **kwargs):
|
def handle(self, *args, **kwargs):
|
||||||
create_categories()
|
create_categories()
|
||||||
create_payment_types()
|
create_payment_types()
|
||||||
|
create_bonus_program_levels()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ from django_cleanup import cleanup
|
||||||
from mptt.fields import TreeForeignKey
|
from mptt.fields import TreeForeignKey
|
||||||
from mptt.models import MPTTModel
|
from mptt.models import MPTTModel
|
||||||
|
|
||||||
from account.models import BonusProgram
|
|
||||||
from core.models import GlobalSettings
|
from core.models import GlobalSettings
|
||||||
from store.utils import create_preview
|
from store.utils import create_preview
|
||||||
|
|
||||||
|
|
@ -166,7 +165,7 @@ class ChecklistQuerySet(models.QuerySet):
|
||||||
.prefetch_related(Prefetch('images', to_attr='_images'))
|
.prefetch_related(Prefetch('images', to_attr='_images'))
|
||||||
|
|
||||||
def annotate_bonus_used(self):
|
def annotate_bonus_used(self):
|
||||||
from account.models import BonusProgramTransaction, BonusType
|
from bonus_program.models import BonusProgramTransaction, BonusType
|
||||||
|
|
||||||
amount_subquery = Subquery(
|
amount_subquery = Subquery(
|
||||||
BonusProgramTransaction.objects.all()
|
BonusProgramTransaction.objects.all()
|
||||||
|
|
@ -606,7 +605,7 @@ class Checklist(models.Model):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if any BonusProgramTransaction bound to current order exists
|
# Check if any BonusProgramTransaction bound to current order exists
|
||||||
from account.models import BonusProgramTransaction
|
from bonus_program.models import BonusProgramTransaction, BonusProgram
|
||||||
if BonusProgramTransaction.objects.filter(order_id=self.id).exists():
|
if BonusProgramTransaction.objects.filter(order_id=self.id).exists():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from django.db.transaction import atomic
|
||||||
from drf_extra_fields.fields import Base64ImageField
|
from drf_extra_fields.fields import Base64ImageField
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from account.models.bonus import BonusProgram
|
from bonus_program.models import BonusProgram
|
||||||
from account.serializers import UserSerializer
|
from account.serializers import UserSerializer
|
||||||
from utils.exceptions import CRMException
|
from utils.exceptions import CRMException
|
||||||
from store.models import Checklist, Category, PaymentMethod, Promocode, Image, Gift
|
from store.models import Checklist, Category, PaymentMethod, Promocode, Image, Gift
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ router.register(r'gifts', views.GiftAPI, basename='gifts')
|
||||||
router.register(r'poizon', views.PoizonAPI, basename='poizon')
|
router.register(r'poizon', views.PoizonAPI, basename='poizon')
|
||||||
router.register(r'promo', views.PromoCodeAPI, basename='promo')
|
router.register(r'promo', views.PromoCodeAPI, basename='promo')
|
||||||
router.register(r'category', views.CategoryAPI, basename='category')
|
router.register(r'category', views.CategoryAPI, basename='category')
|
||||||
router.register(r'settings/payment', views.PaymentMethodsAPI, basename='payment')
|
router.register(r'payment', views.PaymentMethodsAPI, basename='payment')
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user