Compare commits
10
Commits
e983e0cc43
...
8941fded53
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8941fded53 | ||
|
|
0d0c2452c8 | ||
|
|
813e5055b2 | ||
|
|
076ba42ab2 | ||
|
|
fc914d6f6d | ||
|
|
db708a662e | ||
|
|
5e396c0e32 | ||
|
|
43f5dd4594 | ||
|
|
ef18434b86 | ||
|
|
f7dbd02a6c |
No files matched your search
@@ -0,0 +1,6 @@
|
||||
.git
|
||||
.gitignore
|
||||
__pycache__/
|
||||
*.pyc
|
||||
venv/
|
||||
.venv/
|
||||
@@ -7,6 +7,8 @@ __pycache__/
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
*.xlsx
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
|
||||
Generated
+10
@@ -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
|
||||
Generated
+20
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="accountSettings">
|
||||
<option name="activeProfile" value="profile:default" />
|
||||
<option name="activeRegion" value="us-east-1" />
|
||||
<option name="recentlyUsedProfiles">
|
||||
<list>
|
||||
<option value="profile:default" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="recentlyUsedRegions">
|
||||
<list>
|
||||
<option value="us-east-1" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="connectionManager">
|
||||
<option name="activeConnectionId" value="sso;us-east-1;https://view.awsapps.com/start" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+5
-2
@@ -13,8 +13,11 @@
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
|
||||
Generated
+4
-1
@@ -1,4 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="crmApiEnv" project-jdk-type="Python SDK" />
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.12 (venv)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
Generated
+166
-18
@@ -1,14 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="87c5db51-3e89-4a98-9bbb-121c9c52ab3c" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/cuser/cuser_model.py" beforeDir="false" afterPath="$PROJECT_DIR$/apps/cuser/cuser_model.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/cuser/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/apps/cuser/models.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/customer/services.py" beforeDir="false" afterPath="$PROJECT_DIR$/apps/customer/services.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/customer/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/apps/customer/urls.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/customer/views/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/apps/customer/views/__init__.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/customer/views/customer.py" beforeDir="false" afterPath="$PROJECT_DIR$/apps/customer/views/customer.py" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -31,23 +28,35 @@
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"associatedIndex": 3
|
||||
}</component>
|
||||
<component name="ProjectId" id="2SvKNIPBcTXVjDKPSdS8NHW9I0w" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"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"
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"Django Server.crmApi.executor": "Run",
|
||||
"RunOnceActivity.OpenDjangoStructureViewOnStart": "true",
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"WebServerToolWindowFactoryState": "false",
|
||||
"git-widget-placeholder": "main",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"last_opened_file_path": "C:/Users/mjavad/Projects/crmProject/Project/api-Project/crmApi",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</component>
|
||||
}]]></component>
|
||||
<component name="RecentsManager">
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="E:\Projects\crmProject\Project\api-Project\crmApi\utils" />
|
||||
@@ -57,13 +66,14 @@
|
||||
<component name="RunManager">
|
||||
<configuration name="crmApi" type="Python.DjangoServer" factoryName="Django server">
|
||||
<module name="crmApi" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="WORKING_DIRECTORY" value="C:\Users\mjavad\Projects\crmProject\Project\api-Project\crmApi" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
@@ -79,6 +89,14 @@
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-js-predefined-1d06a55b98c1-74d2a5396914-JavaScript-PY-241.14494.241" />
|
||||
<option value="bundled-python-sdk-0509580d9d50-28c9f5db9ffe-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-241.14494.241" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
@@ -96,7 +114,49 @@
|
||||
<workItem from="1697269439761" duration="66295000" />
|
||||
<workItem from="1702900258020" duration="63755000" />
|
||||
<workItem from="1704088148329" duration="105568000" />
|
||||
<workItem from="1704951046597" duration="99812000" />
|
||||
<workItem from="1704951046597" duration="135372000" />
|
||||
<workItem from="1706950546279" duration="21524000" />
|
||||
<workItem from="1707974605580" duration="43207000" />
|
||||
<workItem from="1710141658112" duration="240000" />
|
||||
<workItem from="1710142130443" duration="1078000" />
|
||||
<workItem from="1710150399673" duration="961000" />
|
||||
<workItem from="1710419485683" duration="68525000" />
|
||||
<workItem from="1710488609275" duration="177000" />
|
||||
<workItem from="1710488798818" duration="2376000" />
|
||||
<workItem from="1710491283739" duration="274000" />
|
||||
<workItem from="1710491571470" duration="2407000" />
|
||||
<workItem from="1710859420770" duration="5021000" />
|
||||
<workItem from="1711518197148" duration="371000" />
|
||||
<workItem from="1711518633367" duration="2351000" />
|
||||
<workItem from="1711525074800" duration="90000" />
|
||||
<workItem from="1711525175741" duration="553000" />
|
||||
<workItem from="1711525746440" duration="138000" />
|
||||
<workItem from="1711525904502" duration="187000" />
|
||||
<workItem from="1711526396806" duration="5937000" />
|
||||
<workItem from="1711602888442" duration="717000" />
|
||||
<workItem from="1711606336704" duration="5357000" />
|
||||
<workItem from="1711869672173" duration="628000" />
|
||||
<workItem from="1711878111438" duration="700000" />
|
||||
<workItem from="1711880635851" duration="981000" />
|
||||
<workItem from="1712055178474" duration="84000" />
|
||||
<workItem from="1713166182071" duration="22113000" />
|
||||
<workItem from="1714581267648" duration="6000" />
|
||||
<workItem from="1714884894390" duration="1477000" />
|
||||
<workItem from="1715065792878" duration="1238000" />
|
||||
<workItem from="1715426896536" duration="10640000" />
|
||||
<workItem from="1719038043515" duration="2436000" />
|
||||
<workItem from="1720441183640" duration="1046000" />
|
||||
<workItem from="1720442591368" duration="302000" />
|
||||
<workItem from="1721885637579" duration="1931000" />
|
||||
<workItem from="1722924760522" duration="1012000" />
|
||||
<workItem from="1724485712064" duration="3533000" />
|
||||
<workItem from="1724504428300" duration="205000" />
|
||||
<workItem from="1724504644170" duration="64000" />
|
||||
<workItem from="1724504724350" duration="43000" />
|
||||
<workItem from="1724504786406" duration="1429000" />
|
||||
<workItem from="1724678669565" duration="55000" />
|
||||
<workItem from="1724678749300" duration="2110000" />
|
||||
<workItem from="1727674001765" duration="421000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
@@ -114,4 +174,92 @@
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/shop/views/excel_import.py</url>
|
||||
<line>16</line>
|
||||
<option name="timeStamp" value="2" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/shop/views/excel_import.py</url>
|
||||
<line>19</line>
|
||||
<option name="timeStamp" value="3" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/shop/views/excel_import.py</url>
|
||||
<line>21</line>
|
||||
<option name="timeStamp" value="4" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/shop/views/excel_import.py</url>
|
||||
<line>23</line>
|
||||
<option name="timeStamp" value="5" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/shop/views/excel_import.py</url>
|
||||
<line>29</line>
|
||||
<option name="timeStamp" value="6" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/shop/views/excel_import.py</url>
|
||||
<line>30</line>
|
||||
<option name="timeStamp" value="7" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/shop/views/excel_import.py</url>
|
||||
<line>39</line>
|
||||
<option name="timeStamp" value="8" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/jwt_auth/services.py</url>
|
||||
<line>14</line>
|
||||
<option name="timeStamp" value="13" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/jwt_auth/services.py</url>
|
||||
<line>17</line>
|
||||
<option name="timeStamp" value="14" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/jwt_auth/services.py</url>
|
||||
<line>19</line>
|
||||
<option name="timeStamp" value="15" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/jwt_auth/services.py</url>
|
||||
<line>20</line>
|
||||
<option name="timeStamp" value="16" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/jwt_auth/services.py</url>
|
||||
<line>37</line>
|
||||
<option name="timeStamp" value="17" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/jwt_auth/services.py</url>
|
||||
<line>38</line>
|
||||
<option name="timeStamp" value="18" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/jwt_auth/views.py</url>
|
||||
<line>116</line>
|
||||
<option name="timeStamp" value="19" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
|
||||
<url>file://$PROJECT_DIR$/apps/jwt_auth/views.py</url>
|
||||
<line>118</line>
|
||||
<option name="timeStamp" value="20" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
<default-breakpoints>
|
||||
<breakpoint type="python-exception">
|
||||
<properties notifyOnTerminate="true" exception="BaseException">
|
||||
<option name="notifyOnTerminate" value="true" />
|
||||
</properties>
|
||||
</breakpoint>
|
||||
</default-breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
# ==========================================
|
||||
# Stage 1: Build dependencies
|
||||
# ==========================================
|
||||
FROM python:3.11-slim AS builder
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# بهینهسازی ۱: استفاده از کش سیستمعامل برای apt
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
libpq-dev
|
||||
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
# بهینهسازی ۲: استفاده از مکانیزم کش BuildKit برای pip
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install --default-timeout=1000 -i https://package-mirror.liara.ir/repository/pypi/simple -r requirements.txt
|
||||
|
||||
# ==========================================
|
||||
# Stage 2: Final Production Image
|
||||
# ==========================================
|
||||
FROM python:3.11-slim
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# بهینهسازی ۳: ساخت کاربر سیستم غیر ریشه در بالاترین بخش برای حفظ کِش داکر
|
||||
RUN useradd -m -u 1000 django
|
||||
|
||||
# بهینهسازی ۴: استفاده از کش apt و ساخت دایرکتوریها به صورت یکپارچه
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
libpq5 \
|
||||
supervisor && \
|
||||
mkdir -p /app/staticfiles /app/mediafiles /etc/supervisor /var/log/supervisor && \
|
||||
chown -R django:django /app /etc/supervisor /var/log/supervisor
|
||||
|
||||
# کپی کردن و واگذاری مالکیت محیط مجازی به کاربر django
|
||||
COPY --from=builder --chown=django:django /opt/venv /opt/venv
|
||||
|
||||
|
||||
# کپی کردن تمام کدهای پروژه با مالکیت کاربر محدود شده
|
||||
COPY --chown=django:django . .
|
||||
|
||||
# حل مشکل خطای Permission Denied اسکریپت ورود
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
|
||||
# سوئیچ به کاربر غیر ریشه برای امنیت پروداکشن
|
||||
USER django
|
||||
|
||||
# اکسپوز پورت وبسرور برای وبپروکسی Coolify
|
||||
EXPOSE 8000
|
||||
|
||||
# نقطه ورود اصلی کانتینر
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
+1
-1
@@ -13,7 +13,7 @@ class CUserAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
class CUserRoleAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
readonly_fields = ('created_at', 'updated_at')
|
||||
|
||||
|
||||
class RoleTypeAdmin(admin.ModelAdmin):
|
||||
|
||||
@@ -24,7 +24,7 @@ class CUserManager(BaseUserManager):
|
||||
class CUser(BaseModel, AbstractBaseUser, PermissionsMixin):
|
||||
username = models.CharField(max_length=50, null=False, blank=False, unique=True)
|
||||
mobile = models.PositiveBigIntegerField(null=False, blank=False, unique=True)
|
||||
name_family = models.CharField(max_length=50, null=True, blank=True)
|
||||
name_family = models.CharField(max_length=100, null=True, blank=True)
|
||||
is_active = models.BooleanField(default=False)
|
||||
is_staff = models.BooleanField(default=False)
|
||||
is_superuser = models.BooleanField(default=False)
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cuser', '0012_cuserrole_is_admin'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuser',
|
||||
name='name_family',
|
||||
field=models.CharField(blank=True, max_length=100, null=True),
|
||||
),
|
||||
]
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('customer', '0006_alter_customernote_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='customer',
|
||||
name='name_family',
|
||||
field=models.CharField(max_length=100),
|
||||
),
|
||||
]
|
||||
@@ -49,7 +49,7 @@ class CustomerGroup(BaseModel):
|
||||
|
||||
|
||||
class Customer(BaseModel):
|
||||
name_family = models.CharField(max_length=25, null=False, blank=False)
|
||||
name_family = models.CharField(max_length=100, null=False, blank=False)
|
||||
mobile = models.PositiveBigIntegerField(null=True, blank=True)
|
||||
phone = models.PositiveBigIntegerField(null=True, blank=True)
|
||||
address = models.CharField(max_length=100, null=True, blank=True)
|
||||
|
||||
@@ -77,10 +77,10 @@ def list_customer_v2(request):
|
||||
user_workspace_uuid = get_user_workspace_uuid(request=request)
|
||||
user_cuser_role_uuid = get_cuser_role_uuid(request=request)
|
||||
|
||||
customer_responsible = CustomerResponsibleModel.objects.filter(cuser_role__uuid=user_cuser_role_uuid)
|
||||
|
||||
customer_objs = CustomerModel.objects.filter(sys_ws__uuid=user_workspace_uuid,
|
||||
responsible_group__customer_responsible__in=customer_responsible)
|
||||
# customer_responsible = CustomerResponsibleModel.objects.filter(cuser_role__uuid=user_cuser_role_uuid)
|
||||
# customer_objs = CustomerModel.objects.filter(sys_ws__uuid=user_workspace_uuid, responsible_group__customer_responsible__in=customer_responsible)
|
||||
|
||||
customer_objs = CustomerModel.objects.filter(sys_ws__uuid=user_workspace_uuid)
|
||||
|
||||
return customer_objs
|
||||
except Exception as exp:
|
||||
@@ -101,7 +101,6 @@ def customer_form_item(request):
|
||||
'shahr': shahr,
|
||||
'responsible_groups': responsible_groups
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 09:24
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0074_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('7652353e-6437-4f8d-aa3d-b1ff9de99aac'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 11:50
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0075_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('f97fef73-113f-42f4-bd03-893cd0a6c4cd'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 12:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0076_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('21a181c7-140b-4044-b43a-310712b904ba'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 10:23
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0077_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('78001c0b-3608-492f-b7c6-0a834b160c85'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 10:25
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0078_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('66663299-ba4b-46f8-8e68-62c6be077d93'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 11:44
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0079_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('b639ab0a-7a39-41f2-a2cf-d65736eb71ef'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 12:30
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0080_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('8f0b7e63-3d78-4de2-9e59-931a8734fc02'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:38
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0086_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('0fc1ec70-e817-495e-91c9-e98666cbc2c1'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:42
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0087_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('35e24d20-a3c0-4e33-9307-aff890cfd593'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-24 13:14
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0088_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('70141bbf-e757-4eae-a6a4-7d430084c8a6'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-24 13:21
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0089_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('48476cd6-6133-4355-a10b-319b7de479ee'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-27 06:14
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0090_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('2072fa9d-9601-4c50-b1ee-bd2b437bee2c'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-27 06:38
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('jwt_auth', '0091_alter_cuserroleloginopt_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cuserroleloginopt',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.UUID('52471ac1-6299-4ffa-b56f-8b1e8a343d18'), unique=True),
|
||||
),
|
||||
]
|
||||
@@ -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)})
|
||||
@@ -33,4 +33,8 @@ class LeadReasonAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
@admin.register(LeadEvent)
|
||||
class LeadEventAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 09:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0028_alter_lead_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, choices=[('UN', 'unknown'), ('FA', 'FAIL'), ('SU', 'OK')], default='UN', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 11:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0029_alter_lead_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, choices=[('SU', 'OK'), ('FA', 'FAIL'), ('UN', 'unknown')], default='UN', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 12:04
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0030_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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 10:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0031_alter_lead_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, choices=[('UN', 'unknown'), ('FA', 'FAIL'), ('SU', 'OK')], default='UN', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 10:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0032_alter_lead_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, choices=[('SU', 'OK'), ('FA', 'FAIL'), ('UN', 'unknown')], default='UN', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 11:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0033_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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 12:30
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0034_alter_lead_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, choices=[('SU', 'OK'), ('FA', 'FAIL'), ('UN', 'unknown')], default='UN', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0040_alter_lead_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, choices=[('UN', 'unknown'), ('FA', 'FAIL'), ('SU', 'OK')], default='UN', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0041_alter_lead_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='desc',
|
||||
field=models.TextField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, choices=[('SU', 'OK'), ('FA', 'FAIL'), ('UN', 'unknown')], default='UN', max_length=2, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='title',
|
||||
field=models.CharField(max_length=300),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='leadcomment',
|
||||
name='desc',
|
||||
field=models.TextField(),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-24 13:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0042_alter_lead_desc_alter_lead_status_alter_lead_title_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='lead',
|
||||
name='mobile1',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='lead',
|
||||
name='mobile2',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='lead',
|
||||
name='phone',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-24 13:21
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('workspace', '0016_remove_workspace_cuser_owner'),
|
||||
('lead', '0043_lead_mobile1_lead_mobile2_lead_phone_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='LeadEvent',
|
||||
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)),
|
||||
('name', models.CharField(max_length=50)),
|
||||
('sys_ws', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='workspace.workspace')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-27 06:14
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0044_leadevent'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='lead',
|
||||
name='lead_event',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='lead.leadevent'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='lead',
|
||||
name='status',
|
||||
field=models.CharField(blank=True, choices=[('FA', 'FAIL'), ('UN', 'unknown'), ('SU', 'OK')], default='UN', max_length=2, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-27 06:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lead', '0045_lead_lead_event_alter_lead_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='leadevent',
|
||||
name='message',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='leadevent',
|
||||
name='send_sms',
|
||||
field=models.BooleanField(blank=True, default=False, null=True),
|
||||
),
|
||||
]
|
||||
+15
-3
@@ -30,6 +30,14 @@ class LeadStep(BaseModel):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class LeadEvent(BaseModel):
|
||||
name = models.CharField(max_length=50)
|
||||
message = models.TextField(null=True, blank=True)
|
||||
send_sms = models.BooleanField(default=False, null=True, blank=True)
|
||||
sys_ws = models.ForeignKey(WorkspaceModel, on_delete=models.CASCADE, null=False, blank=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class LeadReason(BaseModel):
|
||||
name = models.CharField(max_length=50)
|
||||
@@ -48,9 +56,13 @@ class Lead(BaseModel):
|
||||
("UN", "unknown"),
|
||||
}
|
||||
|
||||
title = models.CharField(max_length=100)
|
||||
desc = models.CharField(max_length=300)
|
||||
title = models.CharField(max_length=300)
|
||||
desc = models.TextField()
|
||||
mobile1 = models.PositiveBigIntegerField(null=True, blank=True)
|
||||
mobile2 = models.PositiveBigIntegerField(null=True, blank=True)
|
||||
phone = models.PositiveBigIntegerField(null=True, blank=True)
|
||||
customer = models.ForeignKey(CustomerModel, on_delete=models.CASCADE, null=False, blank=False)
|
||||
lead_event = models.ForeignKey(LeadEvent, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
product_type = models.ForeignKey(ProductTypeModel, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
type = models.ForeignKey(LeadType, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
source = models.ForeignKey(LeadSource, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
@@ -68,7 +80,7 @@ class Lead(BaseModel):
|
||||
class LeadComment(BaseModel):
|
||||
|
||||
lead = models.ForeignKey(Lead, on_delete=models.CASCADE, null=False, blank=False, related_name='lead_comment')
|
||||
desc = models.CharField(max_length=300)
|
||||
desc = models.TextField()
|
||||
cuser_role = models.ForeignKey(CuserRoleModel, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
sys_ws = models.ForeignKey(WorkspaceModel, on_delete=models.CASCADE, null=False, blank=False)
|
||||
|
||||
|
||||
+24
-4
@@ -1,9 +1,9 @@
|
||||
from apps.lead.models import Lead as LeadModel, LeadType as LeadTypeModel,\
|
||||
LeadSource as LeadSourceModel, LeadStep as LeadStepModel
|
||||
LeadSource as LeadSourceModel, LeadStep as LeadStepModel, LeadEvent as LeadEventModel
|
||||
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}'
|
||||
@@ -66,6 +84,7 @@ def fields_new_lead_form(request):
|
||||
product_types = ProductTypeModel.objects.filter(sys_ws__uuid=workspace_uuid)
|
||||
lead_source = LeadSourceModel.objects.filter(sys_ws__uuid=workspace_uuid)
|
||||
lead_step = LeadStepModel.objects.filter(sys_ws__uuid=workspace_uuid)
|
||||
lead_event = LeadEventModel.objects.filter(sys_ws__uuid=workspace_uuid)
|
||||
shahr = CityModel.objects.filter()
|
||||
|
||||
data = {
|
||||
@@ -73,6 +92,7 @@ def fields_new_lead_form(request):
|
||||
'lead_types': lead_type,
|
||||
'lead_source': lead_source,
|
||||
'lead_steps': lead_step,
|
||||
'lead_event': lead_event,
|
||||
'shahr': shahr,
|
||||
}
|
||||
return data
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from rest_framework import serializers
|
||||
from apps.lead.models import (
|
||||
LeadType as LeadTypeModel, LeadSource as LeadSourceModel,
|
||||
LeadStep as LeadStepModel, LeadReason as LeadReasonModel
|
||||
LeadStep as LeadStepModel, LeadReason as LeadReasonModel,
|
||||
LeadEvent as LeadEventModel
|
||||
)
|
||||
from apps.shop.models import ProductType as ProductTypeModel
|
||||
from apps.workspace.models import City as CityModel
|
||||
@@ -39,6 +40,12 @@ class LeadReasonSerializers(serializers.ModelSerializer):
|
||||
exclude = ['sys_ws', 'created_at', 'updated_at']
|
||||
|
||||
|
||||
class LeadEventSerializers(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = LeadEventModel
|
||||
exclude = ['sys_ws', 'created_at', 'updated_at']
|
||||
|
||||
|
||||
class ShahrSerializers(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = CityModel
|
||||
|
||||
+41
-11
@@ -1,16 +1,17 @@
|
||||
from apps.lead.models import Lead as LeadModel,\
|
||||
LeadType as LeadTypeModel, LeadStep as LeadStepModel, LeadSource as LeadSourceModel, LeadComment as LeadCommentModel
|
||||
LeadType as LeadTypeModel, LeadStep as LeadStepModel, LeadSource as LeadSourceModel, LeadComment as LeadCommentModel, LeadEvent as LeadEventModel
|
||||
from apps.shop.models import ProductType as ProductTypeModel
|
||||
from utils.get_user_workspace import get_user_workspace
|
||||
from utils.get_cuser_role import get_cuser_role
|
||||
from utils.validations import ObjectValidationById
|
||||
from apps.customer.models import Customer as CustomerModel
|
||||
from apps.workspace.models import City as CityModel
|
||||
from utils.services.sms import DefaultSmsProvider
|
||||
from rest_framework import exceptions
|
||||
|
||||
|
||||
def create_new_lead(request, title: str, customer_id: str, desc: str, product_type_id: int,
|
||||
lead_type_id: int, lead_source_id: int, city_id: int, lead_step_id: int) -> LeadModel:
|
||||
def create_new_lead(request, title: str, customer_id: str, mobile1: int, desc: str, product_type_id: int,
|
||||
lead_type_id: int, lead_source_id: int, city_id: int, lead_step_id: int, mobile2: int = None, phone: int = None, lead_event_id: int = None) -> LeadModel:
|
||||
try:
|
||||
sys_ws = get_user_workspace(request=request)
|
||||
cuser_role = get_cuser_role(request=request)
|
||||
@@ -22,9 +23,20 @@ def create_new_lead(request, title: str, customer_id: str, desc: str, product_ty
|
||||
product_type = ObjectValidationById(object_model=ProductTypeModel, request=request).is_valid(product_type_id)
|
||||
city = ObjectValidationById(object_model=CityModel, request=request).is_valid(city_id)
|
||||
|
||||
lead_event_obj = None
|
||||
|
||||
new_lead = LeadModel()
|
||||
new_lead.title = title
|
||||
new_lead.customer = customer
|
||||
if mobile1:
|
||||
new_lead.mobile1 = mobile1
|
||||
if mobile2:
|
||||
new_lead.mobile2 = mobile2
|
||||
if phone:
|
||||
new_lead.phone = phone
|
||||
if lead_event_id and (lead_event_id != '0' or lead_event_id != 0):
|
||||
lead_event_obj = LeadEventModel.objects.get(id=lead_event_id, sys_ws=sys_ws)
|
||||
new_lead.lead_event = lead_event_obj
|
||||
new_lead.desc = desc
|
||||
new_lead.type = lead_type
|
||||
new_lead.step = lead_step
|
||||
@@ -36,6 +48,14 @@ def create_new_lead(request, title: str, customer_id: str, desc: str, product_ty
|
||||
|
||||
new_lead.save()
|
||||
|
||||
# send sms
|
||||
if lead_event_obj and lead_event_obj.send_sms:
|
||||
sms_provider = DefaultSmsProvider()
|
||||
if mobile1:
|
||||
sms_provider.send_sms(str(mobile1), lead_event_obj.message)
|
||||
if mobile2:
|
||||
sms_provider.send_sms(str(mobile2), lead_event_obj.message)
|
||||
|
||||
return new_lead
|
||||
|
||||
except Exception as exp:
|
||||
@@ -45,10 +65,10 @@ def create_new_lead(request, title: str, customer_id: str, desc: str, product_ty
|
||||
|
||||
|
||||
def update_lead(request, lead_id: int, title: str, customer_id: str, desc: str, product_type_id: int,
|
||||
lead_type_id: int, lead_source_id: int, city_id: int, lead_step_id: int) -> LeadModel:
|
||||
lead_type_id: int, lead_source_id: int, city_id: int, lead_step_id: int, mobile1: int = None, mobile2: int = None, phone: int = None) -> LeadModel:
|
||||
try:
|
||||
sys_ws = get_user_workspace(request=request)
|
||||
cuser_role = get_cuser_role(request=request)
|
||||
#cuser_role = get_cuser_role(request=request)
|
||||
|
||||
customer = ObjectValidationById(object_model=CustomerModel, request=request).is_valid(int(customer_id))
|
||||
lead_type = ObjectValidationById(object_model=LeadTypeModel, request=request).is_valid(lead_type_id)
|
||||
@@ -57,9 +77,16 @@ def update_lead(request, lead_id: int, title: str, customer_id: str, desc: str,
|
||||
product_type = ObjectValidationById(object_model=ProductTypeModel, request=request).is_valid(product_type_id)
|
||||
city = ObjectValidationById(object_model=CityModel, request=request).is_valid(city_id)
|
||||
|
||||
lead = LeadModel.objects.get(id=lead_id, sys_ws=sys_ws, cuser_role=cuser_role)
|
||||
#lead = LeadModel.objects.get(id=lead_id, sys_ws=sys_ws, cuser_role=cuser_role)
|
||||
lead = LeadModel.objects.get(id=lead_id, sys_ws=sys_ws)
|
||||
lead.title = title
|
||||
lead.customer = customer
|
||||
if mobile1:
|
||||
lead.mobile1 = mobile1
|
||||
if mobile2:
|
||||
lead.mobile2 = mobile2
|
||||
if phone:
|
||||
lead.phone = phone
|
||||
lead.desc = desc
|
||||
lead.type = lead_type
|
||||
lead.step = lead_step
|
||||
@@ -96,9 +123,10 @@ def update_lead_status(request, lead_id: int, status: str) -> LeadModel:
|
||||
def update_lead_comment(request, lead_comment_id: int, desc: str) -> LeadModel:
|
||||
try:
|
||||
sys_ws = get_user_workspace(request=request)
|
||||
cuser_role = get_cuser_role(request=request)
|
||||
#cuser_role = get_cuser_role(request=request)
|
||||
|
||||
lead_comment = LeadCommentModel.objects.get(id=lead_comment_id, sys_ws=sys_ws, cuser_role=cuser_role)
|
||||
#lead_comment = LeadCommentModel.objects.get(id=lead_comment_id, sys_ws=sys_ws, cuser_role=cuser_role)
|
||||
lead_comment = LeadCommentModel.objects.get(id=lead_comment_id, sys_ws=sys_ws)
|
||||
lead_comment.desc = desc
|
||||
|
||||
lead_comment.save()
|
||||
@@ -116,7 +144,8 @@ def create_lead_comment(request, lead_id, desc: str) -> LeadCommentModel:
|
||||
cuser_role = get_cuser_role(request=request)
|
||||
|
||||
lead_comment = LeadCommentModel()
|
||||
lead_comment.lead = LeadModel.objects.get(id=lead_id, sys_ws=sys_ws, cuser_role=cuser_role)
|
||||
#lead_comment.lead = LeadModel.objects.get(id=lead_id, sys_ws=sys_ws, cuser_role=cuser_role)
|
||||
lead_comment.lead = LeadModel.objects.get(id=lead_id, sys_ws=sys_ws)
|
||||
lead_comment.sys_ws = sys_ws
|
||||
lead_comment.cuser_role = cuser_role
|
||||
lead_comment.desc = desc
|
||||
@@ -132,9 +161,10 @@ def create_lead_comment(request, lead_id, desc: str) -> LeadCommentModel:
|
||||
def delete_lead_comment(request, lead_comment_id: int) -> LeadModel:
|
||||
try:
|
||||
sys_ws = get_user_workspace(request=request)
|
||||
cuser_role = get_cuser_role(request=request)
|
||||
#cuser_role = get_cuser_role(request=request)
|
||||
|
||||
lead_comment = LeadCommentModel.objects.get(id=lead_comment_id, sys_ws=sys_ws, cuser_role=cuser_role)
|
||||
#lead_comment = LeadCommentModel.objects.get(id=lead_comment_id, sys_ws=sys_ws, cuser_role=cuser_role)
|
||||
lead_comment = LeadCommentModel.objects.get(id=lead_comment_id, sys_ws=sys_ws)
|
||||
lead_comment.delete()
|
||||
|
||||
return lead_comment
|
||||
|
||||
+14
-4
@@ -4,7 +4,7 @@ from rest_framework.generics import ListAPIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import serializers
|
||||
from apps.lead.serializers import LeadTypeSerializers, ProductTypeSerializers,\
|
||||
LeadSourceSerializers, LeadStepSerializers, ShahrSerializers
|
||||
LeadSourceSerializers, LeadStepSerializers, ShahrSerializers, LeadEventSerializers
|
||||
from apps.lead.selectors import fields_new_lead_form
|
||||
from apps.lead.services import create_new_lead, update_lead, update_lead_status,\
|
||||
update_lead_comment, delete_lead_comment, create_lead_comment
|
||||
@@ -25,6 +25,7 @@ class LeadFormItemsApi(APIView):
|
||||
lead_types = LeadTypeSerializers(many=True)
|
||||
product_types = ProductTypeSerializers(many=True)
|
||||
lead_source = LeadSourceSerializers(many=True)
|
||||
lead_event = LeadEventSerializers(many=True)
|
||||
lead_steps = LeadStepSerializers(many=True)
|
||||
shahr = ShahrSerializers(many=True)
|
||||
|
||||
@@ -41,7 +42,11 @@ class LeadCreateApi(APIView):
|
||||
class InputSerializer(serializers.Serializer):
|
||||
title = serializers.CharField(max_length=100, required=True)
|
||||
customer_id = serializers.IntegerField(required=True)
|
||||
desc = serializers.CharField(max_length=200, required=True)
|
||||
desc = serializers.CharField(required=True)
|
||||
mobile1 = serializers.IntegerField(required=True)
|
||||
mobile2 = serializers.IntegerField(required=False)
|
||||
lead_event_id = serializers.IntegerField(required=False)
|
||||
phone = serializers.IntegerField(required=False)
|
||||
lead_type_id = serializers.IntegerField(required=True)
|
||||
product_type_id = serializers.IntegerField(required=True)
|
||||
lead_source_id = serializers.IntegerField(required=True)
|
||||
@@ -68,7 +73,7 @@ class LeadUpdateApi(APIView):
|
||||
class InputSerializer(serializers.Serializer):
|
||||
title = serializers.CharField(max_length=100, required=True)
|
||||
customer_id = serializers.IntegerField(required=True)
|
||||
desc = serializers.CharField(max_length=200, required=True)
|
||||
desc = serializers.CharField(max_length=2000, required=True)
|
||||
lead_type_id = serializers.IntegerField(required=True)
|
||||
product_type_id = serializers.IntegerField(required=True)
|
||||
lead_source_id = serializers.IntegerField(required=True)
|
||||
@@ -139,6 +144,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__'
|
||||
@@ -223,7 +233,7 @@ class LeadRetrieveApi(APIView):
|
||||
class LeadCommentCreateApi(APIView):
|
||||
|
||||
class InputSerializer(serializers.Serializer):
|
||||
desc = serializers.CharField(max_length=200, required=True)
|
||||
desc = serializers.CharField(required=True)
|
||||
|
||||
class OutputSerializer(serializers.Serializer):
|
||||
id = serializers.IntegerField(required=True)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 09:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0024_alter_reminder_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='reminder',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('LE', 'LEAD'), ('CU', 'CUSTOMER'), ('UN', 'UNKNOWN'), ('NO', 'NOTE')], default='UN', max_length=2),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 12:04
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0025_alter_reminder_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='reminder',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('UN', 'UNKNOWN'), ('LE', 'LEAD'), ('CU', 'CUSTOMER'), ('NO', 'NOTE')], default='UN', max_length=2),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 10:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0026_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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 10:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0027_alter_reminder_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='reminder',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('LE', 'LEAD'), ('UN', 'UNKNOWN'), ('NO', 'NOTE'), ('CU', 'CUSTOMER')], default='UN', max_length=2),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 12:30
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0028_alter_reminder_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='reminder',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('NO', 'NOTE'), ('UN', 'UNKNOWN'), ('CU', 'CUSTOMER'), ('LE', 'LEAD')], default='UN', max_length=2),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0034_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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0035_alter_reminder_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='reminder',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('NO', 'NOTE'), ('LE', 'LEAD'), ('CU', 'CUSTOMER'), ('UN', 'UNKNOWN')], default='UN', max_length=2),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-24 13:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0036_alter_reminder_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='reminder',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('LE', 'LEAD'), ('CU', 'CUSTOMER'), ('UN', 'UNKNOWN'), ('NO', 'NOTE')], default='UN', max_length=2),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-24 13:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0037_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),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-08-27 06:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('reminder', '0038_alter_reminder_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='reminder',
|
||||
name='type',
|
||||
field=models.CharField(choices=[('CU', 'CUSTOMER'), ('UN', 'UNKNOWN'), ('LE', 'LEAD'), ('NO', 'NOTE')], default='UN', max_length=2),
|
||||
),
|
||||
]
|
||||
Whitespace-only changes.
@@ -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')
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -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'),
|
||||
]
|
||||
@@ -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()
|
||||
+1
-1
@@ -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)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 09:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0013_alter_productcategory_image'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='order',
|
||||
name='total_price',
|
||||
field=models.PositiveIntegerField(),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 11:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0014_alter_order_total_price'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='order',
|
||||
name='view_at',
|
||||
field=models.DateTimeField(blank=True, default=None, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.1 on 2024-01-27 12:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0015_order_view_at'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='orderitem',
|
||||
name='order',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='order_item', to='shop.order'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 10:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0016_alter_orderitem_order'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='order_prd',
|
||||
field=models.PositiveIntegerField(blank=True, default=None, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productcategory',
|
||||
name='order_cat',
|
||||
field=models.PositiveIntegerField(blank=True, default=None, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 11:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0017_product_order_prd_productcategory_order_cat'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='name',
|
||||
field=models.CharField(max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productcategory',
|
||||
name='name',
|
||||
field=models.CharField(max_length=60),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-02-06 12:30
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0018_alter_product_name_alter_productcategory_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='price',
|
||||
field=models.PositiveBigIntegerField(),
|
||||
),
|
||||
]
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
+11
-5
@@ -1,3 +1,5 @@
|
||||
from turtle import mode
|
||||
|
||||
from django.db import models
|
||||
from utils.base_model import BaseModel
|
||||
from apps.workspace.models import Workspace as WorkspaceModel
|
||||
@@ -15,9 +17,10 @@ class ProductType(BaseModel):
|
||||
|
||||
|
||||
class ProductCategory(BaseModel):
|
||||
name = models.CharField(max_length=30, null=False, blank=False)
|
||||
name = models.CharField(max_length=60, null=False, blank=False)
|
||||
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)
|
||||
image = models.ImageField(null=True, blank=True, default=None, upload_to='product-cat/')
|
||||
order_cat = models.PositiveIntegerField(null=True, blank=True, default=None)
|
||||
sys_ws = models.ForeignKey(WorkspaceModel, on_delete=models.CASCADE, null=False, blank=False)
|
||||
|
||||
def __str__(self):
|
||||
@@ -25,11 +28,13 @@ class ProductCategory(BaseModel):
|
||||
|
||||
|
||||
class Product(BaseModel):
|
||||
name = models.CharField(max_length=150, null=False, blank=False)
|
||||
price = models.DecimalField(max_digits=12, decimal_places=2, null=False, blank=False)
|
||||
name = models.CharField(max_length=200, null=False, blank=False)
|
||||
price = models.PositiveBigIntegerField(null=False, blank=False)
|
||||
category = models.ForeignKey(ProductCategory, on_delete=models.CASCADE, null=False, blank=False)
|
||||
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)
|
||||
|
||||
@@ -63,17 +68,18 @@ class Order(BaseModel):
|
||||
|
||||
responsible_group = models.ForeignKey(ResponsibleGroupModel, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
customer = models.ForeignKey(CustomerModel, on_delete=models.CASCADE, null=False, blank=False)
|
||||
total_price = models.DecimalField(max_digits=12, decimal_places=2, null=False, blank=False)
|
||||
total_price = models.PositiveIntegerField(null=False, blank=False)
|
||||
factor_type = models.PositiveSmallIntegerField(choices=FACTOR_TYPE_CHOICE, null=False, blank=False)
|
||||
factor_status = models.PositiveSmallIntegerField(choices=FACTOR_STATUS_CHOICE, null=True, blank=True)
|
||||
sys_ws = models.ForeignKey(WorkspaceModel, on_delete=models.CASCADE, null=False, blank=False)
|
||||
view_at = models.DateTimeField(null=True, blank=True, default=None)
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.customer}'
|
||||
|
||||
|
||||
class OrderItem(BaseModel):
|
||||
order = models.ForeignKey(Order, on_delete=models.CASCADE, null=False, blank=False)
|
||||
order = models.ForeignKey(Order, on_delete=models.CASCADE, null=False, blank=False, related_name='order_item')
|
||||
product = models.ForeignKey(Product, on_delete=models.CASCADE, null=False, blank=False)
|
||||
product_name = models.CharField(max_length=150, null=False, blank=False)
|
||||
price = models.DecimalField(max_digits=12, decimal_places=2, null=False, blank=False)
|
||||
|
||||
@@ -2,7 +2,7 @@ from apps.shop.models import Cart as CartModel
|
||||
|
||||
|
||||
def list_cart(cuser_role_uuid: str, workspace_uuid: str) -> CartModel:
|
||||
return CartModel.objects.filter(sys_ws__uuid=workspace_uuid, cuser_role__uuid=cuser_role_uuid)
|
||||
return CartModel.objects.filter(sys_ws__uuid=workspace_uuid, cuser_role__uuid=cuser_role_uuid).order_by('-created_at')
|
||||
|
||||
|
||||
def clean_cart(cuser_role_uuid: str, workspace_uuid: str) -> CartModel:
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
from apps.shop.models import Order as OrderModel
|
||||
from apps.shop.models import Order as OrderModel, OrderItem as OrderItemModel
|
||||
from apps.customer.models import CustomerResponsible as CustomerResponsibleModel
|
||||
from apps.cuser.models import CuserRole as CuserRoleModel
|
||||
from rest_framework import exceptions
|
||||
from utils.custom_permissions import workspace_admin_up
|
||||
from utils.get_user_workspace import get_user_workspace_uuid, get_user_workspace
|
||||
from utils.get_cuser_role import get_cuser_role, get_cuser_role_uuid
|
||||
from apps.customer.models import Customer as CustomerModel
|
||||
from django.http import HttpResponse
|
||||
import pandas as pd
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
def retrieve_order(cuser_role_uuid: str, order_id: int, workspace_uuid: str) -> OrderModel:
|
||||
@@ -44,3 +49,106 @@ def list_order(cuser_role_uuid: str, workspace_uuid: str) -> OrderModel:
|
||||
except Exception as exp:
|
||||
message = f'Error Fetching List Order: {exp}'
|
||||
raise exceptions.ValidationError({'error': message})
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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}'
|
||||
raise exceptions.ValidationError({'error': message})
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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:
|
||||
message = f'Error Retrive Order: {exp}'
|
||||
raise exceptions.ValidationError({'error': message})
|
||||
|
||||
|
||||
def retrieve_order_item_excel(request, order_id):
|
||||
try:
|
||||
workspace_uuid = get_user_workspace_uuid(request)
|
||||
cuser_role_uuid = get_cuser_role_uuid(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_items = OrderItemModel.objects.filter(order_id=order_id,
|
||||
# order__responsible_group_id__in=responsible_group_ids)
|
||||
|
||||
|
||||
order_items = OrderItemModel.objects.filter(order_id=order_id)
|
||||
|
||||
|
||||
df = pd.DataFrame(list(order_items.values('product__acc_code', 'product__category__name', 'product_name', 'amount', 'product__attr__acc_vahed')))
|
||||
|
||||
#df['واحد سنجش'] = ''
|
||||
df['عامل کنترل موجودی اول'] = ''
|
||||
df['عامل کنترل موجودی دوم'] = ''
|
||||
df['عامل کنترل موجودی سوم'] = ''
|
||||
df['عامل کنترل موجودی سوم'] = ''
|
||||
df['عامل کنترل موجودی چهارم'] = ''
|
||||
df['عامل کنترل موجودی پنجم'] = ''
|
||||
|
||||
df['محصول'] = df['product__category__name'] + df['product_name']
|
||||
df = df.drop(columns=['product__category__name', 'product_name'])
|
||||
|
||||
df.rename(columns={
|
||||
'product__acc_code': ' کد محصول',
|
||||
'amount': 'مقدار',
|
||||
'product__attr__acc_vahed': 'واحد سنجش'
|
||||
|
||||
}, inplace=True)
|
||||
|
||||
df = df[['محصول',
|
||||
' کد محصول',
|
||||
'واحد سنجش',
|
||||
'عامل کنترل موجودی اول',
|
||||
'عامل کنترل موجودی دوم',
|
||||
'عامل کنترل موجودی سوم',
|
||||
'عامل کنترل موجودی چهارم',
|
||||
'عامل کنترل موجودی پنجم',
|
||||
'مقدار',
|
||||
]]
|
||||
|
||||
return df
|
||||
except Exception as exp:
|
||||
message = f'Error Retrive Order Items for excel: {exp}'
|
||||
raise exceptions.ValidationError({'error': message})
|
||||
@@ -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()
|
||||
|
||||
+7
-1
@@ -23,7 +23,9 @@ urlpatterns = [
|
||||
path('order/update/<int:order_id>/', OrderUpdateApi.as_view(), name='update_order'),
|
||||
path('order/delete/<int:order_id>/', OrderDeleteApi.as_view(), name='delete_order'),
|
||||
path('order/list/', OrderListApi.as_view(), name='list_order'),
|
||||
|
||||
path('order/list-operator/', OrderListOperatorApi.as_view(), name='list_order_operator'),
|
||||
path('order/<int:order_id>/operator/', OrderRetrieveOperatorApi.as_view(), name='order_retrieve_operator'),
|
||||
path('order/<int:order_id>/operator/excel/', OrderRetrieveOperatorExcelApi.as_view(), name='order_retrieve_operator_excel'),
|
||||
|
||||
path('order/iteams/list/<int:order_id>/', OrderItemsListApi.as_view(), name='list_order_items'),
|
||||
|
||||
@@ -31,4 +33,8 @@ urlpatterns = [
|
||||
path('cart/', CartListApi.as_view(), name='list_cart'),
|
||||
path('cart/add/', CartCreateApi.as_view(), name='add_cart'),
|
||||
path('cart/delete/<int:cart_id>/', CartDeleteApi.as_view(), name='delete_cart'),
|
||||
|
||||
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'),
|
||||
]
|
||||
@@ -8,9 +8,12 @@ from .product import (
|
||||
)
|
||||
|
||||
from .order import (
|
||||
OrderListOperatorApi, OrderRetrieveOperatorApi, OrderRetrieveOperatorExcelApi,
|
||||
OrderCreateApi, OrderUpdateApi, OrderDeleteApi, OrderRetrieveApi, OrderListApi, OrderAndItemCreateApi
|
||||
)
|
||||
|
||||
from .cart import (CartListApi, CartCreateApi, CartDeleteApi)
|
||||
|
||||
from .order_item import (OrderItemsListApi, )
|
||||
|
||||
from .excel_import import ImportExcelView, ImportExcelCitysView, ImportExcelCustomersView
|
||||
@@ -0,0 +1,114 @@
|
||||
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, City as CityModel
|
||||
from apps.customer.models import Customer as CustomerModel
|
||||
from apps.customer.models import ResponsibleGroup as ResponsibleGroupModel
|
||||
import os
|
||||
|
||||
|
||||
class ImportExcelView(APIView):
|
||||
|
||||
def get(self, request):
|
||||
|
||||
df = pd.read_excel('pe.xlsx')
|
||||
for index, row in df.iterrows():
|
||||
cate_name = row['cate_name']
|
||||
#order_cat = row['order_cat']
|
||||
acc_code = row['acc_code']
|
||||
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)
|
||||
except ProductCategoryModel.DoesNotExist as exp:
|
||||
prd_ct = ProductCategoryModel.objects.create(name=cate_name, sys_ws=workspace)
|
||||
|
||||
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'})
|
||||
@@ -11,6 +11,9 @@ from rest_framework import generics
|
||||
from apps.customer.models import Customer as CustomerModel
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from utils import custom_permissions
|
||||
from utils.tools import inline_serializer
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
|
||||
class OrderCreateApi(APIView):
|
||||
@@ -121,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)
|
||||
@@ -136,7 +139,7 @@ class OrderDeleteApi(APIView):
|
||||
|
||||
|
||||
class OrderListApi(generics.ListAPIView):
|
||||
|
||||
permission_classes = (IsAuthenticated,)
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = OrderModel
|
||||
@@ -150,3 +153,77 @@ class OrderListApi(generics.ListAPIView):
|
||||
|
||||
return list_order(cuser_role_uuid=cuser_role_uuid, workspace_uuid=user_workspace_uuid)
|
||||
|
||||
|
||||
class OrderListOperatorApi(generics.ListAPIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
customer = inline_serializer(fields={
|
||||
'id': serializers.IntegerField(),
|
||||
'name_family': serializers.CharField(),
|
||||
})
|
||||
class Meta:
|
||||
model = OrderModel
|
||||
exclude = ('sys_ws', )
|
||||
|
||||
serializer_class = OutputSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
return list_order_operators(self.request)
|
||||
|
||||
|
||||
class OrderRetrieveOperatorApi(APIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
class OutputSerializer(serializers.ModelSerializer):
|
||||
|
||||
customer = inline_serializer(fields={
|
||||
'id': serializers.IntegerField(),
|
||||
'name_family': serializers.CharField(),
|
||||
})
|
||||
|
||||
order_item = inline_serializer(many=True, fields={
|
||||
'id': serializers.IntegerField(),
|
||||
'product': inline_serializer(fields={
|
||||
'id': serializers.IntegerField(),
|
||||
'name': serializers.CharField(),
|
||||
'category': inline_serializer(fields={
|
||||
'id': serializers.IntegerField(),
|
||||
'name': serializers.CharField(),
|
||||
})
|
||||
}),
|
||||
'product_name': serializers.CharField(),
|
||||
'price': serializers.IntegerField(),
|
||||
'amount': serializers.IntegerField(),
|
||||
})
|
||||
|
||||
class Meta:
|
||||
model = OrderModel
|
||||
exclude = ('sys_ws', )
|
||||
|
||||
serializer_class = OutputSerializer
|
||||
|
||||
def get(self, request, order_id):
|
||||
|
||||
order = retrieve_order_operators(request, order_id=order_id)
|
||||
|
||||
output = self.OutputSerializer(order)
|
||||
|
||||
return Response(data=output.data, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class OrderRetrieveOperatorExcelApi(APIView):
|
||||
permission_classes = (IsAuthenticated, )
|
||||
def get(self, request, order_id):
|
||||
|
||||
order_df = retrieve_order_item_excel(request=request, order_id=order_id)
|
||||
|
||||
excel_file = BytesIO()
|
||||
order_df.to_excel(excel_file, engine='xlsxwriter', index=False)
|
||||
excel_file.seek(0)
|
||||
|
||||
response = HttpResponse(excel_file.read(), content_type='application/ms-excel')
|
||||
response['Content-Disposition'] = 'attachment; filename="output.xlsx"'
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@@ -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(
|
||||
@@ -151,9 +154,15 @@ class ProductListCategoryApi(generics.ListAPIView):
|
||||
)
|
||||
data = {
|
||||
"category_name": category.name,
|
||||
"products": serializer.data
|
||||
"category_img": category.image.url,
|
||||
"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):
|
||||
|
||||
@@ -156,7 +156,7 @@ class ProductsCategoryApi(APIView):
|
||||
|
||||
def get(self, request):
|
||||
|
||||
p_cate = ProductCategoryModel.objects.annotate(product_count=Count('product')).filter(product_count__gte=1)
|
||||
p_cate = ProductCategoryModel.objects.annotate(product_count=Count('product')).filter(product_count__gte=1).order_by('order_cat')
|
||||
output = self.OutputSerializer(p_cate, many=True)
|
||||
|
||||
return Response(data=output.data, status=status.HTTP_200_OK)
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.1 on 2024-07-25 05:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ticket', '0008_alter_ticketcommentfile_ticket_comment'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='ticketcomment',
|
||||
name='desc',
|
||||
field=models.TextField(),
|
||||
),
|
||||
]
|
||||
@@ -25,7 +25,7 @@ class Ticket(BaseModel):
|
||||
class TicketComment(BaseModel):
|
||||
|
||||
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE, null=False, blank=False)
|
||||
desc = models.CharField(max_length=500)
|
||||
desc = models.TextField()
|
||||
cuser_role = models.ForeignKey(CuserRole, on_delete=models.CASCADE, null=False, blank=False)
|
||||
sys_ws = models.ForeignKey(Workspace, on_delete=models.CASCADE, null=False, blank=False)
|
||||
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
Loaded 100 of 115 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user