diff --git a/.gitignore b/.gitignore
index f8dd262..8469dc6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@ __pycache__/
# C extensions
*.so
+*.xlsx
+
# Distribution / packaging
.Python
build/
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..a9d7db9
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# GitHub Copilot persisted chat sessions
+/copilot/chatSessions
diff --git a/.idea/aws.xml b/.idea/aws.xml
new file mode 100644
index 0000000..3b7efc8
--- /dev/null
+++ b/.idea/aws.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/crmApi.iml b/.idea/crmApi.iml
index bf29436..9fb8a3e 100644
--- a/.idea/crmApi.iml
+++ b/.idea/crmApi.iml
@@ -13,8 +13,11 @@
-
-
+
+
+
+
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 6b0bed8..1dbe7d0 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,7 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 309a9d2..8ff1770 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -1,16 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
+
+
+
+
+
+
@@ -34,23 +54,35 @@
+ {
+ "associatedIndex": 3
+}
- {
- "keyToString": {
- "RunOnceActivity.OpenProjectViewOnStart": "true",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "WebServerToolWindowFactoryState": "false",
- "last_opened_file_path": "E:/Projects/crmProject/Project/api-Project/crmApi",
- "node.js.detected.package.eslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"
+
+}]]>
@@ -60,13 +92,14 @@
+
-
+
@@ -82,6 +115,14 @@
+
+
+
+
+
+
+
+
@@ -100,7 +141,38 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -118,4 +190,92 @@
+
+
+
+
+ file://$PROJECT_DIR$/apps/shop/views/excel_import.py
+ 16
+
+
+
+ file://$PROJECT_DIR$/apps/shop/views/excel_import.py
+ 19
+
+
+
+ file://$PROJECT_DIR$/apps/shop/views/excel_import.py
+ 21
+
+
+
+ file://$PROJECT_DIR$/apps/shop/views/excel_import.py
+ 23
+
+
+
+ file://$PROJECT_DIR$/apps/shop/views/excel_import.py
+ 29
+
+
+
+ file://$PROJECT_DIR$/apps/shop/views/excel_import.py
+ 30
+
+
+
+ file://$PROJECT_DIR$/apps/shop/views/excel_import.py
+ 39
+
+
+
+ file://$PROJECT_DIR$/apps/jwt_auth/services.py
+ 14
+
+
+
+ file://$PROJECT_DIR$/apps/jwt_auth/services.py
+ 17
+
+
+
+ file://$PROJECT_DIR$/apps/jwt_auth/services.py
+ 19
+
+
+
+ file://$PROJECT_DIR$/apps/jwt_auth/services.py
+ 20
+
+
+
+ file://$PROJECT_DIR$/apps/jwt_auth/services.py
+ 37
+
+
+
+ file://$PROJECT_DIR$/apps/jwt_auth/services.py
+ 38
+
+
+
+ file://$PROJECT_DIR$/apps/jwt_auth/views.py
+ 116
+
+
+
+ file://$PROJECT_DIR$/apps/jwt_auth/views.py
+ 118
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/cuser/migrations/0012_cuserrole_is_admin.py b/apps/cuser/migrations/0012_cuserrole_is_admin.py
new file mode 100644
index 0000000..eaad38c
--- /dev/null
+++ b/apps/cuser/migrations/0012_cuserrole_is_admin.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-04-16 06:28
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('cuser', '0011_cuserrole_customer_panel'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='cuserrole',
+ name='is_admin',
+ field=models.BooleanField(blank=True, default=None, null=True),
+ ),
+ ]
diff --git a/apps/cuser/models.py b/apps/cuser/models.py
index ddfd217..4c07096 100644
--- a/apps/cuser/models.py
+++ b/apps/cuser/models.py
@@ -26,6 +26,7 @@ class CuserRole(BaseModel):
mobile = models.PositiveBigIntegerField(null=False, blank=False)
mobile_verify = models.BooleanField(default=False)
customer_panel = models.BooleanField(default=None, blank=True, null=True)
+ is_admin = models.BooleanField(default=None, blank=True, null=True)
sys_ws = models.ForeignKey(WorkspaceModel, on_delete=models.CASCADE, null=True, blank=True, default=None)
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
diff --git a/apps/customer/selectors.py b/apps/customer/selectors.py
index 7c3b2cd..213379a 100644
--- a/apps/customer/selectors.py
+++ b/apps/customer/selectors.py
@@ -101,7 +101,6 @@ def customer_form_item(request):
'shahr': shahr,
'responsible_groups': responsible_groups
}
-
return data
diff --git a/apps/jwt_auth/migrations/0082_alter_cuserroleloginopt_uuid.py b/apps/jwt_auth/migrations/0082_alter_cuserroleloginopt_uuid.py
new file mode 100644
index 0000000..20cfcde
--- /dev/null
+++ b/apps/jwt_auth/migrations/0082_alter_cuserroleloginopt_uuid.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.2.1 on 2024-02-10 09:59
+
+from django.db import migrations, models
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('jwt_auth', '0081_alter_cuserroleloginopt_uuid'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cuserroleloginopt',
+ name='uuid',
+ field=models.UUIDField(default=uuid.UUID('6537ef3d-8ef9-486d-a1b6-7892e021dc19'), unique=True),
+ ),
+ ]
diff --git a/apps/jwt_auth/migrations/0083_alter_cuserroleloginopt_uuid.py b/apps/jwt_auth/migrations/0083_alter_cuserroleloginopt_uuid.py
new file mode 100644
index 0000000..7fe0a9b
--- /dev/null
+++ b/apps/jwt_auth/migrations/0083_alter_cuserroleloginopt_uuid.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.2.1 on 2024-02-10 11:06
+
+from django.db import migrations, models
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('jwt_auth', '0082_alter_cuserroleloginopt_uuid'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cuserroleloginopt',
+ name='uuid',
+ field=models.UUIDField(default=uuid.UUID('745db968-c736-42cd-ad3d-4de41e8e5b98'), unique=True),
+ ),
+ ]
diff --git a/apps/jwt_auth/migrations/0084_alter_cuserroleloginopt_uuid.py b/apps/jwt_auth/migrations/0084_alter_cuserroleloginopt_uuid.py
new file mode 100644
index 0000000..2fd76d8
--- /dev/null
+++ b/apps/jwt_auth/migrations/0084_alter_cuserroleloginopt_uuid.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.2.1 on 2024-02-18 09:44
+
+from django.db import migrations, models
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('jwt_auth', '0083_alter_cuserroleloginopt_uuid'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cuserroleloginopt',
+ name='uuid',
+ field=models.UUIDField(default=uuid.UUID('96211808-5203-451b-a6ce-eee394e02afc'), unique=True),
+ ),
+ ]
diff --git a/apps/jwt_auth/migrations/0085_alter_cuserroleloginopt_uuid.py b/apps/jwt_auth/migrations/0085_alter_cuserroleloginopt_uuid.py
new file mode 100644
index 0000000..472063a
--- /dev/null
+++ b/apps/jwt_auth/migrations/0085_alter_cuserroleloginopt_uuid.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.2.1 on 2024-02-27 09:59
+
+from django.db import migrations, models
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('jwt_auth', '0084_alter_cuserroleloginopt_uuid'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cuserroleloginopt',
+ name='uuid',
+ field=models.UUIDField(default=uuid.UUID('561d07a5-fff4-436f-bab3-4e3b16e05fba'), unique=True),
+ ),
+ ]
diff --git a/apps/jwt_auth/migrations/0086_alter_cuserroleloginopt_uuid.py b/apps/jwt_auth/migrations/0086_alter_cuserroleloginopt_uuid.py
new file mode 100644
index 0000000..2b3c998
--- /dev/null
+++ b/apps/jwt_auth/migrations/0086_alter_cuserroleloginopt_uuid.py
@@ -0,0 +1,19 @@
+# Generated by Django 4.2.1 on 2024-04-16 06:28
+
+from django.db import migrations, models
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('jwt_auth', '0085_alter_cuserroleloginopt_uuid'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cuserroleloginopt',
+ name='uuid',
+ field=models.UUIDField(default=uuid.UUID('b5346fad-8d28-482d-8ed9-2807850b6a4d'), unique=True),
+ ),
+ ]
diff --git a/apps/jwt_auth/services.py b/apps/jwt_auth/services.py
index 24c375b..7ec9ace 100644
--- a/apps/jwt_auth/services.py
+++ b/apps/jwt_auth/services.py
@@ -5,14 +5,16 @@ from apps.jwt_auth.models import CUserRoleLoginOpt
from apps.cuser.models import CuserRole as CuserRoleModel, SmsOpt as SmsOptModel
from django.utils import timezone
from rest_framework import exceptions
-CUser = get_user_model()
+import requests
+from datetime import timedelta
+CUser = get_user_model()
def login_by_username(username: str, password: str) -> CUserRoleLoginOpt:
try:
print(username)
user = CUser.objects.get(username=username)
- print(user)
+
if user and user.check_password(password):
cuser_roles = CuserRoleModel.objects.filter(cuser=user)
@@ -52,21 +54,35 @@ def login_by_mobile(mobile: int):
random_number = random.randint(100000, 999999)
+
try:
SmsOptModel.objects.filter(mobile=mobile).delete()
except Exception as exp:
pass
- opt_code = SmsOptModel(mobile=mobile, opt=123456)
+ expire_time = timezone.now() + timedelta(minutes=3)
+ opt_code = SmsOptModel(mobile=mobile, opt=random_number, expire=expire_time)
opt_code.save()
+ sms_text = f' کد ورود شما: {random_number}'
+
+ payload = {
+ 'USERNAME': 'vsms7937',
+ 'PASSWORD': '335577775533',
+ 'FROM': '30005367',
+ 'TO': int(mobile),
+ 'TEXT': f'{sms_text}'
+ }
+ r = requests.get('http://www.0098sms.com/sendsmslink.aspx', params=payload)
+
except Exception as exp:
raise exceptions.ValidationError({'error': "mobile not found"})
def verify_mobile_and_get_token(mobile: int, opt: int) -> CUserRoleLoginOpt:
try:
- opt_obj = SmsOptModel.objects.filter(mobile=mobile, opt=opt)[0]
+ time_now = timezone.now()
+ opt_obj = SmsOptModel.objects.filter(mobile=mobile, opt=opt, expire__gte=time_now)[0]
if opt_obj:
cuser_roles = CuserRoleModel.objects.filter(cuser__mobile=mobile, is_active=True)
@@ -87,4 +103,8 @@ def verify_mobile_and_get_token(mobile: int, opt: int) -> CUserRoleLoginOpt:
SmsOptModel.objects.filter(mobile=mobile).delete()
return login_opts
except Exception as exp:
+ try:
+ SmsOptModel.objects.filter(mobile=mobile).delete()
+ except Exception as exp:
+ pass
raise exceptions.ValidationError({'error': "cannot verify this mobile and opt code:"+str(exp)})
diff --git a/apps/lead/migrations/0036_alter_lead_status.py b/apps/lead/migrations/0036_alter_lead_status.py
new file mode 100644
index 0000000..c35c80e
--- /dev/null
+++ b/apps/lead/migrations/0036_alter_lead_status.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-10 09:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lead', '0035_alter_lead_status'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='lead',
+ name='status',
+ field=models.CharField(blank=True, choices=[('SU', 'OK'), ('UN', 'unknown'), ('FA', 'FAIL')], default='UN', max_length=2, null=True),
+ ),
+ ]
diff --git a/apps/lead/migrations/0037_alter_lead_status.py b/apps/lead/migrations/0037_alter_lead_status.py
new file mode 100644
index 0000000..7d54b15
--- /dev/null
+++ b/apps/lead/migrations/0037_alter_lead_status.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-10 11:06
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lead', '0036_alter_lead_status'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='lead',
+ name='status',
+ field=models.CharField(blank=True, choices=[('UN', 'unknown'), ('SU', 'OK'), ('FA', 'FAIL')], default='UN', max_length=2, null=True),
+ ),
+ ]
diff --git a/apps/lead/migrations/0038_alter_lead_status.py b/apps/lead/migrations/0038_alter_lead_status.py
new file mode 100644
index 0000000..0388295
--- /dev/null
+++ b/apps/lead/migrations/0038_alter_lead_status.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-18 09:44
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lead', '0037_alter_lead_status'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='lead',
+ name='status',
+ field=models.CharField(blank=True, choices=[('FA', 'FAIL'), ('SU', 'OK'), ('UN', 'unknown')], default='UN', max_length=2, null=True),
+ ),
+ ]
diff --git a/apps/lead/migrations/0039_alter_lead_status.py b/apps/lead/migrations/0039_alter_lead_status.py
new file mode 100644
index 0000000..e64727d
--- /dev/null
+++ b/apps/lead/migrations/0039_alter_lead_status.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-27 09:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lead', '0038_alter_lead_status'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='lead',
+ name='status',
+ field=models.CharField(blank=True, choices=[('SU', 'OK'), ('UN', 'unknown'), ('FA', 'FAIL')], default='UN', max_length=2, null=True),
+ ),
+ ]
diff --git a/apps/lead/migrations/0040_alter_lead_status.py b/apps/lead/migrations/0040_alter_lead_status.py
new file mode 100644
index 0000000..8cacb80
--- /dev/null
+++ b/apps/lead/migrations/0040_alter_lead_status.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-04-16 06:28
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lead', '0039_alter_lead_status'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='lead',
+ name='status',
+ field=models.CharField(blank=True, choices=[('FA', 'FAIL'), ('SU', 'OK'), ('UN', 'unknown')], default='UN', max_length=2, null=True),
+ ),
+ ]
diff --git a/apps/lead/selectors.py b/apps/lead/selectors.py
index 36eba2b..4e594da 100644
--- a/apps/lead/selectors.py
+++ b/apps/lead/selectors.py
@@ -3,7 +3,7 @@ from apps.lead.models import Lead as LeadModel, LeadType as LeadTypeModel,\
from apps.shop.models import ProductType as ProductTypeModel
from apps.workspace.models import City as CityModel
from utils.get_user_workspace import get_user_workspace_uuid
-from utils.get_cuser_role import get_cuser_role_uuid
+from utils.get_cuser_role import get_cuser_role_uuid, get_cuser_role
from rest_framework import exceptions
@@ -12,7 +12,16 @@ def list_leads(request) -> LeadModel:
try:
workspace_uuid = get_user_workspace_uuid(request)
cuser_role_uuid = get_cuser_role_uuid(request)
- leads = LeadModel.objects.filter(sys_ws__uuid=workspace_uuid, cuser_role__uuid=cuser_role_uuid).order_by('-created_at')
+ cuser_role = get_cuser_role(request)
+
+ base_filter = {
+ 'sys_ws__uuid': workspace_uuid,
+ }
+
+ if not cuser_role.is_admin:
+ base_filter['cuser_role__uuid'] = cuser_role_uuid
+
+ leads = LeadModel.objects.filter(**base_filter).order_by('-created_at')
return leads
except Exception as exp:
@@ -25,7 +34,16 @@ def retrieve_lead(request, id: int) -> LeadModel:
try:
workspace_uuid = get_user_workspace_uuid(request)
cuser_role_uuid = get_cuser_role_uuid(request)
- lead = LeadModel.objects.get(id=id, sys_ws__uuid=workspace_uuid, cuser_role__uuid=cuser_role_uuid)
+
+ cuser_role = get_cuser_role(request)
+ base_filter = {
+ 'sys_ws__uuid': workspace_uuid,
+ }
+
+ if not cuser_role.is_admin:
+ base_filter['cuser_role__uuid'] = cuser_role_uuid
+
+ lead = LeadModel.objects.get(id=id, **base_filter)
return lead
except Exception as exp:
message = f'Error retrieve Leads: {exp}'
diff --git a/apps/lead/views.py b/apps/lead/views.py
index ec33d90..0cb27ed 100644
--- a/apps/lead/views.py
+++ b/apps/lead/views.py
@@ -139,6 +139,11 @@ class LeadListApi(ListAPIView):
'ostan': inline_serializer(many=False, fields={'name': serializers.CharField() })
})
+ cuser_role = inline_serializer(many=False, fields={
+ 'id': serializers.IntegerField(),
+ 'name_family': serializers.CharField()
+ })
+
class Meta:
model = LeadModel
fields = '__all__'
diff --git a/apps/reminder/migrations/0030_alter_reminder_type.py b/apps/reminder/migrations/0030_alter_reminder_type.py
new file mode 100644
index 0000000..5aa0e2c
--- /dev/null
+++ b/apps/reminder/migrations/0030_alter_reminder_type.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-10 09:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('reminder', '0029_alter_reminder_type'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='reminder',
+ name='type',
+ field=models.CharField(choices=[('LE', 'LEAD'), ('NO', 'NOTE'), ('UN', 'UNKNOWN'), ('CU', 'CUSTOMER')], default='UN', max_length=2),
+ ),
+ ]
diff --git a/apps/reminder/migrations/0031_alter_reminder_type.py b/apps/reminder/migrations/0031_alter_reminder_type.py
new file mode 100644
index 0000000..e8082d2
--- /dev/null
+++ b/apps/reminder/migrations/0031_alter_reminder_type.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-10 11:06
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('reminder', '0030_alter_reminder_type'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='reminder',
+ name='type',
+ field=models.CharField(choices=[('CU', 'CUSTOMER'), ('NO', 'NOTE'), ('LE', 'LEAD'), ('UN', 'UNKNOWN')], default='UN', max_length=2),
+ ),
+ ]
diff --git a/apps/reminder/migrations/0032_alter_reminder_type.py b/apps/reminder/migrations/0032_alter_reminder_type.py
new file mode 100644
index 0000000..d4d82ea
--- /dev/null
+++ b/apps/reminder/migrations/0032_alter_reminder_type.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-18 09:44
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('reminder', '0031_alter_reminder_type'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='reminder',
+ name='type',
+ field=models.CharField(choices=[('UN', 'UNKNOWN'), ('CU', 'CUSTOMER'), ('LE', 'LEAD'), ('NO', 'NOTE')], default='UN', max_length=2),
+ ),
+ ]
diff --git a/apps/reminder/migrations/0033_alter_reminder_type.py b/apps/reminder/migrations/0033_alter_reminder_type.py
new file mode 100644
index 0000000..259d448
--- /dev/null
+++ b/apps/reminder/migrations/0033_alter_reminder_type.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-27 09:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('reminder', '0032_alter_reminder_type'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='reminder',
+ name='type',
+ field=models.CharField(choices=[('LE', 'LEAD'), ('UN', 'UNKNOWN'), ('CU', 'CUSTOMER'), ('NO', 'NOTE')], default='UN', max_length=2),
+ ),
+ ]
diff --git a/apps/reminder/migrations/0034_alter_reminder_type.py b/apps/reminder/migrations/0034_alter_reminder_type.py
new file mode 100644
index 0000000..61846d4
--- /dev/null
+++ b/apps/reminder/migrations/0034_alter_reminder_type.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-04-16 06:28
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('reminder', '0033_alter_reminder_type'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='reminder',
+ name='type',
+ field=models.CharField(choices=[('CU', 'CUSTOMER'), ('NO', 'NOTE'), ('UN', 'UNKNOWN'), ('LE', 'LEAD')], default='UN', max_length=2),
+ ),
+ ]
diff --git a/apps/report/__init__.py b/apps/report/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/apps/report/selector.py b/apps/report/selector.py
new file mode 100644
index 0000000..963bff6
--- /dev/null
+++ b/apps/report/selector.py
@@ -0,0 +1,41 @@
+from apps.lead.models import Lead as LeadModel
+from apps.cuser.models import CuserRole as CuserRoleModel, RoleType as RoleTypeModel
+from rest_framework import serializers
+from django.db.models import Count
+from django.db.models import Count
+from rest_framework import exceptions
+
+
+def list_leads_api() -> LeadModel:
+
+ try:
+ base_filter = {
+ 'sys_ws__uuid': 'ca918836-ddf2-4d88-8d76-033d285062e4',
+ }
+
+ leads = LeadModel.objects.filter(**base_filter).order_by('-created_at')
+
+ return leads
+
+ except Exception as exp:
+ message = f'Error Fetching List Leads: {exp}'
+ raise exceptions.ValidationError({'error': message})
+
+
+
+
+def user_lead_report_count_by_date(start_datetime, end_datetime, status: str | None = None,):
+
+ base_filer = {
+ 'cuser_role__role_type__role_name_en': 'workspace_operator',
+ 'created_at__range': [start_datetime, end_datetime],
+ }
+ if status:
+ base_filer['status'] = status
+
+ return LeadModel.objects.filter(**base_filer).values('cuser_role__name_family').annotate(
+ count=Count('cuser_role__name_family')).order_by('-count')
+
+
+def operators_cuser_role():
+ return CuserRoleModel.objects.filter(sys_ws_id=2, role_type__role_name_en='workspace_operator')
\ No newline at end of file
diff --git a/apps/report/services.py b/apps/report/services.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/apps/report/services.py
@@ -0,0 +1 @@
+
diff --git a/apps/report/urls.py b/apps/report/urls.py
new file mode 100644
index 0000000..e440054
--- /dev/null
+++ b/apps/report/urls.py
@@ -0,0 +1,8 @@
+from django.urls import path
+from apps.report.views import ReportApiView, LeadListApi
+
+
+urlpatterns = [
+ path('lead/', ReportApiView.as_view(), name='report-lead'),
+ path('lead/list/loolegostar-x89i20/', LeadListApi.as_view(), name='report-lead'),
+]
diff --git a/apps/report/views.py b/apps/report/views.py
new file mode 100644
index 0000000..c26b33b
--- /dev/null
+++ b/apps/report/views.py
@@ -0,0 +1,115 @@
+from django_filters.rest_framework import DjangoFilterBackend
+from rest_framework import serializers
+from rest_framework.generics import ListAPIView
+from rest_framework.views import APIView
+from apps.lead.models import Lead as LeadModel
+from rest_framework.response import Response
+from rest_framework import status
+from apps.report.selector import user_lead_report_count_by_date
+from apps.cuser.models import CuserRole as CuserRoleModel
+from datetime import datetime
+from apps.report.selector import list_leads_api
+from utils.pagination import CustomPagination
+from utils.tools import inline_serializer
+
+
+class ReportApiView(APIView):
+
+ class ResultSerializer(serializers.Serializer):
+
+ class OperatorSerializer(serializers.Serializer):
+ cuser_role__name_family = serializers.CharField()
+ count = serializers.IntegerField()
+
+ su = OperatorSerializer(many=True)
+ un = OperatorSerializer(many=True)
+ fa = OperatorSerializer(many=True)
+ all = OperatorSerializer(many=True)
+
+ def get(self, request):
+ date_format = "%Y-%m-%d"
+ start_datetime = request.query_params.get('start_datetime', None)
+ if start_datetime:
+ start_datetime = start_datetime.replace(" ", "")
+
+ end_datetime = request.query_params.get('end_datetime', None)
+ if end_datetime:
+ end_datetime = end_datetime.replace(" ", "")
+
+ #example start_datetime : 2024-03-20T14:31:16 03:30
+ if start_datetime and end_datetime:
+ start_dt = datetime.strptime(start_datetime, date_format)
+ end_dt = datetime.strptime(end_datetime, date_format)
+ else:
+ start_dt = datetime.now()
+ end_dt = datetime.now()
+
+ # status = request.query_params.get('status')
+
+ #همه
+ users_all_lead_count = user_lead_report_count_by_date(start_datetime=start_dt, end_datetime=end_dt)
+ #موفق
+ users_su_lead_count = user_lead_report_count_by_date(status='SU', start_datetime=start_dt, end_datetime=end_dt)
+ #شکست
+ users_fa_lead_count = user_lead_report_count_by_date(status='FA', start_datetime=start_dt, end_datetime=end_dt)
+ #نا معلوم
+ users_un_lead_count = user_lead_report_count_by_date(status='UN', start_datetime=start_dt, end_datetime=end_dt)
+
+ result = {
+ 'su': users_su_lead_count,
+ 'fa': users_fa_lead_count,
+ 'un': users_un_lead_count,
+ 'all': users_all_lead_count,
+ }
+
+ output_serializer = self.ResultSerializer(result)
+
+ return Response(output_serializer.data)
+
+
+class LeadListApi(ListAPIView):
+
+ #permission_classes = (IsAuthenticated, custom_permissions.WorkspaceOperatorPermission)
+
+ class Pagination(CustomPagination):
+ page_size = 10
+ page_size_query_param = 'page_size'
+ max_page_size = 20
+
+ class OutputSerializer(serializers.ModelSerializer):
+
+ customer = inline_serializer(many=False, fields={'name_family': serializers.CharField(), })
+
+ product_type = inline_serializer(many=False, fields={'name': serializers.CharField(), })
+
+ type = inline_serializer(many=False, fields={'title': serializers.CharField(), })
+
+ source = inline_serializer(many=False, fields={'title': serializers.CharField(), })
+
+ step = inline_serializer(many=False, fields={
+ 'id': serializers.IntegerField(),
+ 'name': serializers.CharField(),
+ })
+
+ city = inline_serializer(many=False, fields={
+ 'name': serializers.CharField(),
+ 'ostan': inline_serializer(many=False, fields={'name': serializers.CharField() })
+ })
+
+ cuser_role = inline_serializer(many=False, fields={
+ 'id': serializers.IntegerField(),
+ 'name_family': serializers.CharField()
+ })
+
+ class Meta:
+ model = LeadModel
+ fields = '__all__'
+
+ serializer_class = OutputSerializer
+ pagination_class = Pagination
+
+ filter_backends = [DjangoFilterBackend]
+ filterset_fields = ['step', 'status', ]
+
+ def get_queryset(self):
+ return list_leads_api()
diff --git a/apps/shop/admin.py b/apps/shop/admin.py
index 0c8095c..e211f1d 100644
--- a/apps/shop/admin.py
+++ b/apps/shop/admin.py
@@ -22,7 +22,7 @@ class ProductCategoryAdmin(admin.ModelAdmin):
@admin.register(ProductModel)
class ProductAdmin(admin.ModelAdmin):
- pass
+ search_fields = ("name", "category__name", "acc_code")
@admin.register(OrderModel)
diff --git a/apps/shop/migrations/0020_product_view_only.py b/apps/shop/migrations/0020_product_view_only.py
new file mode 100644
index 0000000..3b82dc1
--- /dev/null
+++ b/apps/shop/migrations/0020_product_view_only.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-27 09:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('shop', '0019_alter_product_price'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='product',
+ name='view_only',
+ field=models.BooleanField(blank=True, default=False, null=True),
+ ),
+ ]
diff --git a/apps/shop/models.py b/apps/shop/models.py
index 5dfef47..b5777c5 100644
--- a/apps/shop/models.py
+++ b/apps/shop/models.py
@@ -34,6 +34,7 @@ class Product(BaseModel):
acc_code = models.CharField(null=True, blank=True)
order_prd = models.PositiveIntegerField(null=True, blank=True, default=None)
attr = models.JSONField(null=True, blank=True)
+ view_only = models.BooleanField(null=True, blank=True, default=False)
sys_ws = models.ForeignKey(WorkspaceModel, on_delete=models.CASCADE, null=False, blank=False)
diff --git a/apps/shop/selectors/order.py b/apps/shop/selectors/order.py
index ca2c2ed..ac8d96b 100644
--- a/apps/shop/selectors/order.py
+++ b/apps/shop/selectors/order.py
@@ -55,11 +55,18 @@ def list_order_operators(request) -> OrderModel:
try:
workspace_uuid = get_user_workspace_uuid(request)
cuser_role_uuid = get_cuser_role_uuid(request)
+ cuser_role = get_cuser_role(request)
customer_responsibles = CustomerResponsibleModel.objects.filter(cuser_role__uuid=cuser_role_uuid, sys_ws__uuid=workspace_uuid)
responsible_group_ids = customer_responsibles.values_list('responsible_group__id', flat=True)
- orders = OrderModel.objects.filter(sys_ws__uuid=workspace_uuid,
- responsible_group_id__in=responsible_group_ids).order_by('-created_at')[:10]
+ base_filter = {
+ 'sys_ws__uuid': workspace_uuid,
+ }
+
+ if not cuser_role.is_admin:
+ base_filter['responsible_group_id__in'] = responsible_group_ids
+
+ orders = OrderModel.objects.filter(**base_filter).order_by('-created_at')[:50]
return orders
except Exception as exp:
message = f'Error Fetching List Order: {exp}'
@@ -70,13 +77,23 @@ def retrieve_order_operators(request, order_id) -> OrderModel:
try:
workspace_uuid = get_user_workspace_uuid(request)
cuser_role_uuid = get_cuser_role_uuid(request)
+ cuser_role = get_cuser_role(request)
customer_responsibles = CustomerResponsibleModel.objects.filter(cuser_role__uuid=cuser_role_uuid, sys_ws__uuid=workspace_uuid)
responsible_group_ids = customer_responsibles.values_list('responsible_group__id', flat=True)
- order = OrderModel.objects.get(id=order_id, sys_ws__uuid=workspace_uuid,
- responsible_group_id__in=responsible_group_ids)
- order.view_at = timezone.now()
- order.save()
+ base_filter = {
+ 'sys_ws__uuid': workspace_uuid,
+ 'id': order_id,
+ }
+
+ if not cuser_role.is_admin:
+ base_filter['responsible_group_id__in'] = responsible_group_ids
+
+ order = OrderModel.objects.get(**base_filter)
+
+ if not cuser_role.is_admin:
+ order.view_at = timezone.now()
+ order.save()
return order
except Exception as exp:
diff --git a/apps/shop/selectors/product.py b/apps/shop/selectors/product.py
index 87f442f..1d560ca 100644
--- a/apps/shop/selectors/product.py
+++ b/apps/shop/selectors/product.py
@@ -22,13 +22,24 @@ def list_product(workspace_uuid: str) -> ProductModel:
def list_product_by_category(workspace_uuid: str, category_id: int) -> ProductModel:
try:
- product_category_obj = ProductModel.objects.filter(sys_ws__uuid=workspace_uuid, category_id=category_id)
+ product_category_obj = ProductModel.objects.filter(sys_ws__uuid=workspace_uuid, category_id=category_id,
+ view_only=False)
return product_category_obj
except Exception as exp:
message = f'Error Fetching List Product by category: {exp}'
raise exceptions.ValidationError({'error': message})
+def list_view_only_product_by_category(workspace_uuid: str, category_id: int) -> ProductModel:
+ try:
+ view_only_product_category_obj = ProductModel.objects.filter(sys_ws__uuid=workspace_uuid, category_id=category_id,
+ view_only=True)
+ return view_only_product_category_obj
+ except Exception as exp:
+ message = f'Error Fetching View Only List Product by category: {exp}'
+ raise exceptions.ValidationError({'error': message})
+
+
def count_product_in_category(workspace_uuid: str, category_id: int) -> int:
try:
count_product = ProductModel.objects.filter(sys_ws__uuid=workspace_uuid, category_id=category_id).count()
diff --git a/apps/shop/urls.py b/apps/shop/urls.py
index f30f27f..d3b2ad6 100644
--- a/apps/shop/urls.py
+++ b/apps/shop/urls.py
@@ -34,5 +34,7 @@ urlpatterns = [
path('cart/add/', CartCreateApi.as_view(), name='add_cart'),
path('cart/delete//', CartDeleteApi.as_view(), name='delete_cart'),
- #path('import/', ImportExcelView.as_view(), name='import_excel'),
+ path('import/', ImportExcelView.as_view(), name='import_excel'),
+ path('import/customer/', ImportExcelCustomersView.as_view(), name='import_excel_customer'),
+ #path('import/city/', ImportExcelCitysView.as_view(), name='import_excel_city'),
]
diff --git a/apps/shop/views/__init__.py b/apps/shop/views/__init__.py
index 6d4909b..acd4a86 100644
--- a/apps/shop/views/__init__.py
+++ b/apps/shop/views/__init__.py
@@ -16,4 +16,4 @@ from .cart import (CartListApi, CartCreateApi, CartDeleteApi)
from .order_item import (OrderItemsListApi, )
-from .excel_import import ImportExcelView
+from .excel_import import ImportExcelView, ImportExcelCitysView, ImportExcelCustomersView
diff --git a/apps/shop/views/excel_import.py b/apps/shop/views/excel_import.py
index 7511237..3cbe937 100644
--- a/apps/shop/views/excel_import.py
+++ b/apps/shop/views/excel_import.py
@@ -2,7 +2,9 @@ from rest_framework.views import APIView
from rest_framework.response import Response
import pandas as pd
from apps.shop.models import Product as ProductModel, ProductCategory as ProductCategoryModel
-from apps.workspace.models import Workspace as WorkspaceModel
+from apps.workspace.models import Workspace as WorkspaceModel, City as CityModel
+from apps.customer.models import Customer as CustomerModel
+from apps.customer.models import ResponsibleGroup as ResponsibleGroupModel
import os
@@ -13,27 +15,100 @@ class ImportExcelView(APIView):
df = pd.read_excel('pe.xlsx')
for index, row in df.iterrows():
cate_name = row['cate_name']
- order_cat = row['order_cat']
+ #order_cat = row['order_cat']
acc_code = row['acc_code']
- prd_name = row['prd_name']
- order_prd = row['order_prd']
+ prd_name = row['name']
+ order_prd = row['size']
vahed = row['vahed']
workspace = WorkspaceModel.objects.get(id=2)
try:
- prd_ct = ProductCategoryModel.objects.get(name=cate_name, sys_ws=workspace, order_cat=order_cat)
+ prd_ct = ProductCategoryModel.objects.get(name=cate_name, sys_ws=workspace)
except ProductCategoryModel.DoesNotExist as exp:
- prd_ct = ProductCategoryModel.objects.create(name=cate_name, sys_ws=workspace, order_cat=order_cat)
+ prd_ct = ProductCategoryModel.objects.create(name=cate_name, sys_ws=workspace)
- new_product = ProductModel()
- new_product.name = prd_name
- new_product.price = 0
- new_product.category = ProductCategoryModel.objects.get(id=prd_ct.id)
- new_product.acc_code = acc_code
- new_product.order_prd = order_prd
- new_product.attr = {"acc_vahed": vahed}
- new_product.sys_ws = workspace
- new_product.save()
+ if ProductModel.objects.filter(acc_code=acc_code).exists() == False:
+ new_product = ProductModel()
+ new_product.name = prd_name
+ new_product.price = 0
+ new_product.category = ProductCategoryModel.objects.get(id=prd_ct.id)
+ new_product.acc_code = acc_code
+ new_product.order_prd = order_prd
+ new_product.view_only = True
+ new_product.attr = {"acc_vahed": vahed}
+ new_product.sys_ws = workspace
+ new_product.save()
+ else:
+ up_product = ProductModel.objects.get(acc_code=acc_code)
+ up_product.name = prd_name
+ up_product.save()
return Response(data={"result": 'ok'})
+
+class ImportExcelCitysView(APIView):
+
+ def get(self, request):
+
+
+ df = pd.read_excel('cities.xlsx')
+ for index, row in df.iterrows():
+ city_name = row['name']
+ pv_id = row['province_id']
+
+ try:
+ ostan = CityModel.objects.get(pv_id=pv_id, is_ostan=True)
+ except Exception as exp:
+ print(city_name)
+ print(pv_id)
+
+ city_obj = CityModel()
+ city_obj.name = city_name
+ city_obj.is_ostan = False
+ city_obj.ostan = ostan
+ city_obj.save()
+
+
+ return Response(data={"result": 'ok'})
+
+
+class ImportExcelCustomersView(APIView):
+
+ def get(self, request):
+
+ df = pd.read_excel('customersData.xlsx')
+ for index, row in df.iterrows():
+ name = row['name']
+ mobile = row['mobile']
+
+ if name and mobile:
+
+ phone = row['phone']
+ address = row['address']
+ ostan = row['ostan']
+ shahr = row['shar']
+ mantaghe = row['id_mantaghe']
+
+ try:
+ ostan_obj = CityModel.objects.get(name=ostan, is_ostan=True)
+ shahr_obj = CityModel.objects.get(name=shahr, ostan=ostan_obj)
+ except Exception as exp:
+ shahr_obj = CityModel.objects.get(id=1229)
+
+ try:
+ cs = CustomerModel()
+ cs.name_family = name
+ cs.mobile = mobile
+ if phone:
+ cs.phone = phone
+
+ cs.city = shahr_obj
+ if address:
+ cs.address = address
+ cs.responsible_group = ResponsibleGroupModel.objects.get(id=mantaghe)
+ cs.sys_ws = WorkspaceModel.objects.get(id=2)
+ cs.save()
+ except Exception as exp:
+ print(name)
+
+ return Response(data={"result": 'ok'})
diff --git a/apps/shop/views/order.py b/apps/shop/views/order.py
index ba925d7..ab30b07 100644
--- a/apps/shop/views/order.py
+++ b/apps/shop/views/order.py
@@ -124,7 +124,7 @@ class OrderUpdateApi(APIView):
class OrderDeleteApi(APIView):
-
+ permission_classes = (IsAuthenticated,)
def delete(self, request, order_id: int):
user_workspace_uuid = get_user_workspace_uuid(request=request)
@@ -139,7 +139,7 @@ class OrderDeleteApi(APIView):
class OrderListApi(generics.ListAPIView):
-
+ permission_classes = (IsAuthenticated,)
class OutputSerializer(serializers.ModelSerializer):
class Meta:
model = OrderModel
@@ -155,6 +155,7 @@ class OrderListApi(generics.ListAPIView):
class OrderListOperatorApi(generics.ListAPIView):
+ permission_classes = (IsAuthenticated,)
class OutputSerializer(serializers.ModelSerializer):
customer = inline_serializer(fields={
'id': serializers.IntegerField(),
@@ -172,6 +173,7 @@ class OrderListOperatorApi(generics.ListAPIView):
class OrderRetrieveOperatorApi(APIView):
+ permission_classes = (IsAuthenticated,)
class OutputSerializer(serializers.ModelSerializer):
customer = inline_serializer(fields={
@@ -210,6 +212,7 @@ class OrderRetrieveOperatorApi(APIView):
class OrderRetrieveOperatorExcelApi(APIView):
+ permission_classes = (IsAuthenticated, )
def get(self, request, order_id):
order_df = retrieve_order_item_excel(request=request, order_id=order_id)
diff --git a/apps/shop/views/product.py b/apps/shop/views/product.py
index 12e03ea..1b16ec5 100644
--- a/apps/shop/views/product.py
+++ b/apps/shop/views/product.py
@@ -134,6 +134,7 @@ class ProductListCategoryApi(generics.ListAPIView):
id = serializers.IntegerField()
name = serializers.CharField()
price = serializers.FloatField()
+ view_only = serializers.BooleanField()
class Meta:
exclude = ('sys_ws', )
@@ -144,6 +145,8 @@ class ProductListCategoryApi(generics.ListAPIView):
serializer = self.get_serializer(queryset_data, many=True)
workspace_uuid = get_user_workspace_uuid(request=request)
category = retrieve_product_category(category_id=category_id, workspace_uuid=workspace_uuid)
+ view_only_products = list_view_only_product_by_category(category_id=category_id, workspace_uuid=workspace_uuid)
+ view_only_products_serializer = self.get_serializer(view_only_products, many=True)
if len(serializer.data) == 0:
return Response(
@@ -152,9 +155,14 @@ class ProductListCategoryApi(generics.ListAPIView):
data = {
"category_name": category.name,
"category_img": category.image.url,
- "products": serializer.data
+ "products": serializer.data,
}
+ if len(view_only_products_serializer.data) >=1:
+ data['view_only_products'] = view_only_products_serializer.data
+ else:
+ data['view_only_products'] = None
+
return Response(data)
def get_queryset(self):
diff --git a/apps/workspace/migrations/0014_city_pv_id.py b/apps/workspace/migrations/0014_city_pv_id.py
new file mode 100644
index 0000000..f0ef277
--- /dev/null
+++ b/apps/workspace/migrations/0014_city_pv_id.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-10 09:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('workspace', '0013_alter_workspace_cuser_owner'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='city',
+ name='pv_id',
+ field=models.PositiveSmallIntegerField(blank=True, null=True),
+ ),
+ ]
diff --git a/apps/workspace/migrations/0015_alter_city_name.py b/apps/workspace/migrations/0015_alter_city_name.py
new file mode 100644
index 0000000..1ce6098
--- /dev/null
+++ b/apps/workspace/migrations/0015_alter_city_name.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.1 on 2024-02-10 11:06
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('workspace', '0014_city_pv_id'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='city',
+ name='name',
+ field=models.CharField(blank=True, max_length=30, null=True),
+ ),
+ ]
diff --git a/apps/workspace/migrations/0016_remove_workspace_cuser_owner.py b/apps/workspace/migrations/0016_remove_workspace_cuser_owner.py
new file mode 100644
index 0000000..4263224
--- /dev/null
+++ b/apps/workspace/migrations/0016_remove_workspace_cuser_owner.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.1 on 2024-02-18 09:44
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('workspace', '0015_alter_city_name'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='workspace',
+ name='cuser_owner',
+ ),
+ ]
diff --git a/apps/workspace/models.py b/apps/workspace/models.py
index a3853ce..0a2e54a 100644
--- a/apps/workspace/models.py
+++ b/apps/workspace/models.py
@@ -11,7 +11,7 @@ class Workspace(BaseModel):
#cuser_role_owner = models.OneToOneField(CuserRoleModel, on_delete=models.CASCADE,
# related_name='workspace', null=True, blank=True)
- cuser_owner = models.ForeignKey(CUser, on_delete=models.SET_NULL, null=True, blank=True, default=None)
+ #cuser_owner = models.ForeignKey(CUser, on_delete=models.SET_NULL, null=True, blank=True, default=None)
name = models.CharField(max_length=15, null=False, blank=False)
username = models.CharField(max_length=30, null=False, blank=False, unique=True)
expire = models.DateTimeField(null=True, blank=True)
@@ -27,9 +27,10 @@ class Workspace(BaseModel):
class City(BaseModel):
- name = models.CharField(max_length=15, null=True, blank=True)
+ name = models.CharField(max_length=30, null=True, blank=True)
is_ostan = models.BooleanField(default=False, null=False, blank=False)
ostan = models.ForeignKey('self', models.CASCADE, null=True, blank=True)
+ pv_id = models.PositiveSmallIntegerField(null=True, blank=True)
def __str__(self):
return str(self.name)
diff --git a/config/asgi.py b/config/asgi.py
index 072ae9e..4427c6d 100644
--- a/config/asgi.py
+++ b/config/asgi.py
@@ -11,6 +11,6 @@ import os
from django.core.asgi import get_asgi_application
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'crmApi.settings')
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
application = get_asgi_application()
diff --git a/config/settings/base.py b/config/settings/base.py
index e33c440..8dae0fb 100644
--- a/config/settings/base.py
+++ b/config/settings/base.py
@@ -19,8 +19,6 @@ BASE_DIR = Path(__file__).resolve().parent.parent
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR.parent /'media'
-print(MEDIA_ROOT)
-
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
@@ -33,8 +31,22 @@ DEBUG = True
ALLOWED_HOSTS = ['*']
CORS_ALLOWED_ORIGINS = [
+ "http://192.168.138.94:3000",
+ "http://192.168.138.94:3001",
"http://localhost:3001",
+ "http://localhost:3002",
"http://localhost:3000",
+ "https://loolegostar.liara.run",
+ "https://loolegostar-crm.liara.run",
+]
+
+CORS_ALLOW_METHODS = [
+ "DELETE",
+ "GET",
+ "OPTIONS",
+ "PATCH",
+ "POST",
+ "PUT",
]
AUTH_USER_MODEL = 'cuser.CUser'
diff --git a/config/settings/production.py b/config/settings/production.py
index 9b5ed21..b386768 100644
--- a/config/settings/production.py
+++ b/config/settings/production.py
@@ -1 +1,12 @@
from .base import *
+DEBUG = False
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.postgresql',
+ 'NAME': 'crm-api',
+ 'USER': 'root',
+ 'PASSWORD': '1yI0Iw2Fpjm2BXhEnwUKVdDg',
+ 'HOST': 'loolegostar-db',
+ 'PORT': '5432'
+ }
+}
diff --git a/config/urls.py b/config/urls.py
index 5401752..e5abe07 100644
--- a/config/urls.py
+++ b/config/urls.py
@@ -23,6 +23,7 @@ urlpatterns = [
path('admin/', admin.site.urls),
path('auth/', include('apps.jwt_auth.urls')),
path('cuser/', include('apps.cuser.urls')),
+ path('report/', include('apps.report.urls')),
path('customer/', include('apps.customer.urls')),
path('shop/', include('apps.shop.urls')),
path('ticket/', include('apps.ticket.urls')),
diff --git a/config/wsgi.py b/config/wsgi.py
index de5557e..fd9f5ac 100644
--- a/config/wsgi.py
+++ b/config/wsgi.py
@@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'crmApi.settings')
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
application = get_wsgi_application()
diff --git a/liara.json b/liara.json
new file mode 100644
index 0000000..3579ef3
--- /dev/null
+++ b/liara.json
@@ -0,0 +1,10 @@
+{
+ "platform": "django",
+ "app": "loolegostar-api",
+ "disks": [
+ {
+ "name": "media",
+ "mountTo": "media"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/liara_nginx.conf b/liara_nginx.conf
new file mode 100644
index 0000000..d5a7402
--- /dev/null
+++ b/liara_nginx.conf
@@ -0,0 +1,29 @@
+gzip on;
+gzip_disable "msie6";
+gzip_vary on;
+gzip_proxied any;
+gzip_comp_level 6;
+gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
+
+client_max_body_size 250M;
+
+location /media {
+ alias /usr/src/app/media;
+}
+
+location /static {
+ alias /usr/src/app/config/staticfiles;
+}
+
+location / {
+ try_files /dev/null @django_app;
+}
+
+location ~\.sqlite3$ {
+ deny all;
+ error_page 403 =404 /;
+}
+
+location ~ /\.well-known {
+ allow all;
+}
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..20ac44f
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,14 @@
+Django==4.2.1
+djangorestframework==3.14.0
+Markdown==3.4.3
+requests==2.31.0
+django-filter==23.2
+drf-spectacular==0.26.2
+psycopg==3.1.9
+psycopg-binary==3.1.9
+djangorestframework-simplejwt==5.2.2
+django-cors-headers==4.3.1
+openpyxl==3.1.2
+XlsxWriter==3.1.9
+pandas==2.2.0
+pillow==10.2.0
\ No newline at end of file
diff --git a/requirements/base.txt b/requirements/base.txt
index 46927b3..20ac44f 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -1,9 +1,11 @@
Django==4.2.1
djangorestframework==3.14.0
Markdown==3.4.3
+requests==2.31.0
django-filter==23.2
drf-spectacular==0.26.2
psycopg==3.1.9
+psycopg-binary==3.1.9
djangorestframework-simplejwt==5.2.2
django-cors-headers==4.3.1
openpyxl==3.1.2