first commit

This commit is contained in:
javad committed 2026-06-15 10:57:28 +03:30
commit 3e4574dcdd
163 files changed
+3559

No files matched your search

View File
Whitespace-only changes.
+13
View File
@@ -0,0 +1,13 @@
from django.contrib import admin
from apps.project.models import Project as ProjectModel, ProjectImage as ProjectImageModel
# Register your models here.
@admin.register(ProjectModel)
class ProjectAdmin(admin.ModelAdmin):
search_fields = ['cuser__name_family', ]
@admin.register(ProjectImageModel)
class ProjectImageAdmin(admin.ModelAdmin):
pass
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class ProjectConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.project'
+50
View File
@@ -0,0 +1,50 @@
# Generated by Django 4.2.1 on 2024-03-28 05:05
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('appsetting', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Project',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('address', models.CharField(max_length=200)),
('factor_price', models.PositiveIntegerField()),
('seller_name', models.CharField(blank=True, max_length=50, null=True)),
('seller_mobile', models.PositiveBigIntegerField(blank=True, null=True)),
('seller_address', models.CharField(blank=True, max_length=200, null=True)),
('ax_factor', models.ImageField(blank=True, null=True, upload_to='project-factor/')),
('city', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='appsetting.city')),
('cuser', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='ProjectImage',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('image', models.ImageField(upload_to='project/')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='project.project')),
],
options={
'abstract': False,
},
),
]
@@ -0,0 +1,18 @@
# Generated by Django 4.2.1 on 2024-04-07 09:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='project',
name='factor_price',
field=models.PositiveBigIntegerField(),
),
]
@@ -0,0 +1,22 @@
# Generated by Django 4.2.1 on 2024-04-07 11:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0002_alter_project_factor_price'),
]
operations = [
migrations.AlterModelOptions(
name='project',
options={'ordering': ['-created_at']},
),
migrations.AddField(
model_name='project',
name='status',
field=models.CharField(choices=[('waiting', 'Waiting'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='waiting', max_length=10),
),
]
@@ -0,0 +1,21 @@
# Generated by Django 4.2.1 on 2024-04-07 11:55
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('project', '0003_alter_project_options_project_status'),
]
operations = [
migrations.AddField(
model_name='project',
name='op_cuser',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projects', to=settings.AUTH_USER_MODEL),
),
]
@@ -0,0 +1,24 @@
# Generated by Django 4.2.1 on 2024-04-08 06:49
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('project', '0004_project_op_cuser'),
]
operations = [
migrations.AlterField(
model_name='project',
name='status',
field=models.CharField(choices=[('AwaitComp', 'Awaiting completion'), ('waiting', 'Waiting'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='waiting', max_length=10),
),
migrations.AlterField(
model_name='projectimage',
name='project',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_image', to='project.project'),
),
]
@@ -0,0 +1,21 @@
# Generated by Django 4.2.1 on 2024-04-08 10:00
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('project', '0005_alter_project_status_alter_projectimage_project'),
]
operations = [
migrations.AlterField(
model_name='project',
name='cuser',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mojri_projects', to=settings.AUTH_USER_MODEL),
),
]
@@ -0,0 +1,33 @@
# Generated by Django 4.2.1 on 2024-04-08 11:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0006_alter_project_cuser'),
]
operations = [
migrations.AddField(
model_name='project',
name='tabaghat',
field=models.PositiveIntegerField(default=0),
),
migrations.AddField(
model_name='project',
name='vahed',
field=models.PositiveIntegerField(default=0),
),
migrations.AddField(
model_name='project',
name='zirbana',
field=models.PositiveIntegerField(default=0),
),
migrations.AlterField(
model_name='project',
name='status',
field=models.CharField(choices=[('AwaitComp', 'Awaiting completion'), ('waiting', 'Waiting'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='AwaitComp', max_length=10),
),
]
@@ -0,0 +1,28 @@
# Generated by Django 4.2.1 on 2024-04-09 05:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0007_project_tabaghat_project_vahed_project_zirbana_and_more'),
]
operations = [
migrations.AlterField(
model_name='project',
name='tabaghat',
field=models.PositiveIntegerField(blank=True, default=0, null=True),
),
migrations.AlterField(
model_name='project',
name='vahed',
field=models.PositiveIntegerField(blank=True, default=0, null=True),
),
migrations.AlterField(
model_name='project',
name='zirbana',
field=models.PositiveIntegerField(blank=True, default=0, null=True),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 4.2.1 on 2024-04-17 11:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0008_alter_project_tabaghat_alter_project_vahed_and_more'),
]
operations = [
migrations.AlterField(
model_name='projectimage',
name='image',
field=models.ImageField(upload_to='media/project/'),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 4.2.1 on 2024-04-17 11:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0009_alter_projectimage_image'),
]
operations = [
migrations.AddField(
model_name='project',
name='emtiyaz',
field=models.IntegerField(blank=True, null=True),
),
]
@@ -0,0 +1,20 @@
# Generated by Django 4.2.1 on 2024-05-02 06:39
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('projectcode', '0003_alter_projectcode_options_and_more'),
('project', '0010_project_emtiyaz'),
]
operations = [
migrations.AddField(
model_name='project',
name='projectcode',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='projectcode.projectcode'),
),
]
View File
Whitespace-only changes.
+44
View File
@@ -0,0 +1,44 @@
from django.contrib.auth import get_user_model
from django.db import models
from utils.base_model import BaseModel
from apps.appsetting.models import City as CityModel
from apps.projectcode.models import ProjectCode as ProjectCodeModel
# Create your models here.
CUserModel = get_user_model()
class Project(BaseModel):
status_choices = [
('AwaitComp', 'Awaiting completion'),
('waiting', 'Waiting'),
('approved', 'Approved'),
('rejected', 'Rejected'),
]
cuser = models.ForeignKey(CUserModel, on_delete=models.CASCADE, null=False, blank=False, related_name='mojri_projects')
city = models.ForeignKey(CityModel, on_delete=models.SET_NULL, null=True, blank=True)
address = models.CharField(max_length=200, null=False, blank=False)
zirbana = models.PositiveIntegerField(null=True, blank=True, default=0)
tabaghat = models.PositiveIntegerField(null=True, blank=True, default=0)
vahed = models.PositiveIntegerField(null=True, blank=True, default=0)
factor_price = models.PositiveBigIntegerField(null=False, blank=False)
seller_name = models.CharField(max_length=50, null=True, blank=True)
seller_mobile = models.PositiveBigIntegerField(null=True, blank=True)
seller_address = models.CharField(max_length=200, null=True, blank=True)
status = models.CharField(max_length=10, choices=status_choices, default='AwaitComp')
op_cuser = models.ForeignKey(CUserModel, on_delete=models.SET_NULL, null=True, blank=True, related_name='projects')
ax_factor = models.ImageField(upload_to='project-factor/', null=True, blank=True)
emtiyaz = models.IntegerField(null=True, blank=True)
projectcode = models.ForeignKey(ProjectCodeModel, on_delete=models.SET_NULL, null=True, blank=True)
def __str__(self):
return f'{self.cuser.name_family} - {self.city.name}'
class Meta:
ordering = ['-created_at']
class ProjectImage(BaseModel):
project = models.ForeignKey(Project, models.CASCADE, null=False, blank=False, related_name='project_image')
image = models.ImageField(upload_to='media/project/', null=False, blank=False)
+20
View File
@@ -0,0 +1,20 @@
from apps.project.models import Project as ProjectModel
from rest_framework.exceptions import ValidationError
def op_list_project(status: str = 'waiting') -> ProjectModel:
projects = ProjectModel.objects.filter(status=status)
return projects
def list_project(user) -> ProjectModel:
projects = ProjectModel.objects.filter(cuser=user)
return projects
def get_project(project_id: int) -> ProjectModel:
try:
project = ProjectModel.objects.get(id=project_id)
return project
except Exception as e:
raise ValidationError({'error': f'error on get project {str(e)}'})
+52
View File
@@ -0,0 +1,52 @@
from apps.project.models import Project as ProjectModel, ProjectImage as ProjectImageModel
from apps.cuser.models import CUser as CUserModel
from rest_framework.validators import ValidationError
from utils.services.sms import DefaultSmsProvider
from utils.services.sms_task import task_send_sms
def create_project(cuser: CUserModel, city: int, address: str, factor_price: int, project_images: list,
tabaghat: int, zirbana: int, vahed:int):
try:
project = ProjectModel.objects.create(
cuser=cuser,
city_id=city,
tabaghat=tabaghat,
zirbana=zirbana,
vahed=vahed,
address=address,
factor_price=factor_price
)
for image in project_images:
ProjectImageModel.objects.create(project=project, image=image)
message = f'پروژه شما با موفقیت در باشگاه مجریان لوله گستر گلپایگان ثبت شد، لطفا اطلاعات مربوط به فروشنده را تکمیل کنید.'
task_send_sms.delay(message=message, mobile=str(cuser.mobile))
return project
except Exception as e:
raise ValidationError({'error': f'error on create project {str(e)}'})
def update_seller_project(project_id: int, **kwargs):
try:
project = ProjectModel.objects.filter(id=project_id).update(status='waiting', **kwargs)
project_obj = ProjectModel.objects.get(id=project_id)
return project_obj
except Exception as e:
raise ValidationError({'error': f'error on update project {str(e)}'})
def send_sms_to_seller(seller_mobile: int, message: str):
sms = DefaultSmsProvider()
sms.send_sms(str(seller_mobile), message)
def update_seller_va_send_message(project_id: int, **kwargs):
project = update_seller_project(project_id, **kwargs)
message = f'پس از برسی و تایید پروژه توسط کارشناسان شرکت امتیاز به پروفایل شما اضافه خواهد شد'
task_send_sms.delay(message=message, mobile=str(project.cuser.mobile))
#send_sms_to_seller(9384999655, message)
return project
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
+12
View File
@@ -0,0 +1,12 @@
from django.urls import path
from apps.project.views import (CityListApiView, CreateProjectApiview, ListProjectApiview, RetrieveProjectApiview,
UpdateSellerProjectApiview, OpListProjectApiview)
urlpatterns = [
path('city-list/', CityListApiView.as_view(), name='city-list'),
path('create/', CreateProjectApiview.as_view(), name='create-project'),
path('list/', ListProjectApiview.as_view(), name='project-list'),
path('op-list/', OpListProjectApiview.as_view(), name='op-project-list'),
path('<int:project_id>/', RetrieveProjectApiview.as_view(), name='project-detail'),
path('<int:project_id>/update-seller/', UpdateSellerProjectApiview.as_view(), name='update-seller-project'),
]
+159
View File
@@ -0,0 +1,159 @@
from django.shortcuts import render
from rest_framework.views import APIView
from apps.appsetting.models import City as CityModel
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from apps.project.models import Project as ProjectModel, ProjectImage as ProjectImageModel
from apps.appsetting.models import City as CityModel
from apps.cuser.models import CUser as CUserModel
from apps.project.services import create_project, update_seller_project, update_seller_va_send_message
from apps.project.selector import list_project, get_project, op_list_project
from apps.projectcode.selector import project_code_validation, update_project_code_used
from apps.appsetting.selector import get_city_list
from rest_framework import status
# Create your views here.
class CityListApiView(APIView):
permission_classes = (IsAuthenticated,)
class OutputSerializer(serializers.ModelSerializer):
class Meta:
model = CityModel
fields = '__all__'
def get(self, request):
cities = get_city_list()
output = self.OutputSerializer(cities, many=True)
return Response(data=output.data)
# create project with project images
class CreateProjectApiview(APIView):
permission_classes = (IsAuthenticated,)
class InputSerializer(serializers.Serializer):
city = serializers.IntegerField(required=True)
address = serializers.CharField(max_length=200, required=True)
factor_price = serializers.IntegerField(required=True)
zirbana = serializers.IntegerField(required=True)
tabaghat = serializers.IntegerField(required=True)
vahed = serializers.IntegerField(required=True)
project_images = serializers.ListField(child=serializers.ImageField(), required=True)
def post(self, request):
serializer = self.InputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
project_obj = create_project(cuser=request.user, **serializer.validated_data)
return Response({'project_id': f'{str(project_obj.id)}'}, status=status.HTTP_201_CREATED)
class ListProjectApiview(APIView):
permission_classes = (IsAuthenticated,)
class OutputSerializer(serializers.ModelSerializer):
class Meta:
model = ProjectModel
fields = '__all__'
def get(self, request):
projects = list_project(user=request.user)
output = self.OutputSerializer(projects, many=True)
return Response(data=output.data, status=status.HTTP_200_OK)
class RetrieveProjectApiview(APIView):
permission_classes = (IsAuthenticated,)
class OutputSerializer(serializers.ModelSerializer):
class ProjectImageSerializer(serializers.ModelSerializer):
class Meta:
model = ProjectImageModel
fields = '__all__'
project_image = ProjectImageSerializer(many=True)
class Meta:
model = ProjectModel
fields = '__all__'
def get(self, request, project_id):
project = get_project(project_id=project_id)
output = self.OutputSerializer(project)
return Response(data=output.data, status=status.HTTP_200_OK)
class UpdateSellerProjectApiview(APIView):
permission_classes = (IsAuthenticated,)
class InputSerializer(serializers.Serializer):
seller_name = serializers.CharField(max_length=50, required=True)
seller_mobile = serializers.IntegerField(required=True)
seller_address = serializers.CharField(max_length=500, required=True)
projectcode = serializers.CharField(max_length=20, required=True)
def patch(self, request, project_id):
serializer = self.InputSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
seller_name = serializer.validated_data.get('seller_name')
seller_mobile = serializer.validated_data.get('seller_mobile')
seller_address = serializer.validated_data.get('seller_address')
projectcode = serializer.validated_data.get('projectcode')
user = request.user
projectcode_obj = update_project_code_used(code=projectcode, user=user)
update_seller_va_send_message(
project_id=project_id, seller_name=seller_name,
seller_mobile=seller_mobile, seller_address=seller_address,
projectcode=projectcode_obj
)
return Response({'message': 'project updated successfully'}, status=status.HTTP_200_OK)
class OpListProjectApiview(APIView):
permission_classes = (IsAuthenticated,)
class OutputSerializer(serializers.ModelSerializer):
class CitySerializer(serializers.ModelSerializer):
class OstanSerializer(serializers.ModelSerializer):
class Meta:
model = CityModel
fields = '__all__'
ostan = OstanSerializer()
class Meta:
model = CityModel
fields = '__all__'
class CUserSerializer(serializers.ModelSerializer):
class Meta:
model = CUserModel
fields = ('name_family', 'mobile',)
city = CitySerializer()
cuser = CUserSerializer()
class Meta:
model = ProjectModel
fields = '__all__'
def get(self, request):
project_status = request.query_params.get('status')
projects = op_list_project(status=project_status)
output = self.OutputSerializer(projects, many=True)
return Response(data=output.data, status=status.HTTP_200_OK)