This commit is contained in:
Ilya Mukhortov 2025-02-12 21:17:07 +10:00
parent 0e3fd06c53
commit a670fae9eb
23 changed files with 334 additions and 198 deletions

View File

@ -1,18 +1,22 @@
FROM python:3.12.2 FROM python:3.12.2 AS python-nginx
RUN apt-get update RUN apt-get update
RUN apt-get install -y \ RUN apt-get install -y \
vim \ vim \
supervisor supervisor \
nginx \
&& rm -rf /var/lib/apt/lists/*
RUN pip install pip==24.0 RUN pip install pip==25.0
WORKDIR /app WORKDIR /app
ADD requirements.txt ./ ADD requirements.txt ./
RUN pip install -r ./requirements.txt RUN pip install -r ./requirements.txt
FROM python-nginx
COPY manage.py wsgi.py ./ COPY manage.py wsgi.py ./
COPY ./appa/ ./appa/ COPY ./appa/ ./appa/
@ -20,8 +24,6 @@ COPY ./appa/ ./appa/
RUN python manage.py collectstatic --noinput RUN python manage.py collectstatic --noinput
RUN chmod -R 777 /app/django_static RUN chmod -R 777 /app/django_static
ADD ./client/build /client
ADD ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf ADD ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf
ADD ./entrypoint.sh /entrypoint.sh ADD ./entrypoint.sh /entrypoint.sh

View File

@ -20,7 +20,8 @@ class CallRequestAdmin(admin.ModelAdmin):
'date', 'date',
'get_status', 'get_status',
'get_request_status', 'get_request_status',
'patient_name', 'patient_last_name',
'patient_first_name',
'patient_phone', 'patient_phone',
'is_active', 'is_active',
) )
@ -31,7 +32,7 @@ class CallRequestAdmin(admin.ModelAdmin):
('date', DateRangeFilterBuilder()), ('date', DateRangeFilterBuilder()),
) )
search_fields = ( search_fields = (
'patient_name', 'patient_last_name',
'patient_phone', 'patient_phone',
) )
form = forms.modelform_factory(CallRequest, fields='__all__', widgets={ form = forms.modelform_factory(CallRequest, fields='__all__', widgets={
@ -41,10 +42,9 @@ class CallRequestAdmin(admin.ModelAdmin):
list_editable = ('is_active',) list_editable = ('is_active',)
readonly_fields = ( readonly_fields = (
'call_id', 'call_id',
'call_data', 'call_result',
'request_time', 'call_text_log',
'response_status_code', 'request_time'
'response_message'
) )
@admin.display(description='Статус приема', ordering='status') @admin.display(description='Статус приема', ordering='status')

View File

@ -5,7 +5,7 @@ from django.apps import AppConfig as DjangoAppConfig
class AppaConfig(DjangoAppConfig): class AppaConfig(DjangoAppConfig):
name = 'appa' name = 'appa'
verbose_name = 'МТС' verbose_name = 'Обзвон'
def ready(self): def ready(self):
import appa.receivers import appa.receivers

131
appa/call_api.py Normal file
View File

@ -0,0 +1,131 @@
import datetime
import json
import requests
from django.utils import timezone
from constance import config
from .models import CallRequest, RequestLog
def auth_request():
r = requests.post(
config.ENTRYPOINT_AUTH,
data=dict(
username=config.USERNAME,
password=config.PASSWORD,
)
)
if r.status_code == 200:
print(r.json())
config.ACCESS_TOKEN = r.json()['accessToken']
config.REFRESH_TOKEN = r.json()['refreshToken']
config.ACCESS_TOKEN_EXPIRED = datetime.datetime.now() + datetime.timedelta(minutes=5)
def get_token():
if not config.ACCESS_TOKEN or config.ACCESS_TOKEN_EXPIRED <= timezone.now():
auth_request()
return config.ACCESS_TOKEN
def delete_call_request(call_request: CallRequest, logging=True):
hooks = None
if logging:
log = RequestLog(
request_url=config.ENTRYPOINT_DELETE % (call_request.call_id,),
)
hooks = {'response': log.response_hook}
r = requests.post(
config.ENTRYPOINT_DELETE % (call_request.call_id,),
headers={'Authorization': f'Bearer {get_token()}'},
hooks=hooks
)
if r.status_code == 200:
call_request.reset_request()
def get_record(call_request: CallRequest, logging=True):
if call_request.call_id:
hooks = None
if logging:
log = RequestLog(
request_url=config.ENTRYPOINT_RECORD % (call_request.call_id,),
)
hooks = {'response': log.response_hook}
r = requests.get(
config.ENTRYPOINT_RECORD % (call_request.call_id,),
headers={'Authorization': f'Bearer {get_token()}'},
hooks=hooks
)
if r.status_code == 200:
result = r.json()
call_request.call_text_log = result['text_log']
call_request.call_result = result['call_result']
if result['confirmed']:
call_request.status = call_request.Status.APPROVED
elif result['call_result_code'] in [3]:
call_request.status = call_request.Status.CANCELED
call_request.save()
def add_call_request(call_request: CallRequest, logging=True, delete=False):
if call_request.request_status == call_request.RequestStatus.SENT:
if delete:
delete_call_request(call_request)
data = dict(records=[dict(
first_name=call_request.patient_first_name,
second_name=call_request.patient_last_name,
middle_name=call_request.patient_middle_name,
phone_number=call_request.patient_phone,
receipt_date=call_request.date.strftime('%Y-%m-%d'),
receipt_time=call_request.date.strftime('%H:%M'),
doctor_specialisation=call_request.doctor_speciality,
doctor_fullname=call_request.doctor_name,
filial=call_request.address,
ext_id=str(call_request.uid)
)])
hooks = None
if logging:
log = RequestLog(
request_url=config.ENTRYPOINT_ADD_RECORDS,
request_body=json.dumps(data, ensure_ascii=False, indent=4),
)
hooks = {'response': log.response_hook}
r = requests.post(
config.ENTRYPOINT_ADD_RECORDS,
headers={'Authorization': f'Bearer {get_token()}'},
json=data,
hooks=hooks
)
call_request.response_status_code = r.status_code
call_request.request_time = timezone.now()
if r.status_code == 200:
record = r.json()['added_records'][0]
call_request.call_id = record['id']
call_request.request_status = CallRequest.RequestStatus.SENT
elif r.status_code == 400:
call_request.request_status = CallRequest.RequestStatus.ERROR
call_request.save(update_fields=(
'call_id',
'request_status',
'request_time',
'response_status_code',
'response_message',
))
def call_history(date_from: datetime.date, date_to: datetime.date):
pass

View File

@ -0,0 +1,20 @@
import datetime
import os
from constance import config
from django.core.management.base import BaseCommand
from appa.call_api import add_call_request, delete_call_request, get_record
from appa.models import CallRequest
class Command(BaseCommand):
def handle(self, *args, **options):
config.ACCESS_TOKEN_EXPIRED = datetime.datetime.now() - datetime.timedelta(days=1)
call_requests = CallRequest.objects.filter(id__in=[2])
for call_request in call_requests:
#add_call_request(call_request)
get_record(call_request)
#delete_call_request(call_request)

View File

@ -1,6 +1,7 @@
# Generated by Django 3.2 on 2024-09-05 19:30 # Generated by Django 3.2 on 2025-02-09 10:07
from django.db import migrations, models from django.db import migrations, models
import uuid
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -32,12 +33,26 @@ class Migration(migrations.Migration):
name='CallRequest', name='CallRequest',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
('status', models.CharField(choices=[('PENDING', 'Обзвон еще не состоялся'), ('APPROVED', 'Прием подтвержден'), ('CANCELED', 'Прием отменен'), ('WITHOUT_ANSWER', 'Не дозвонились')], default='PENDING', max_length=20, verbose_name='Статус приема')),
('request_status', models.CharField(choices=[('PENDING', 'Не отправлен'), ('APPROVED', 'Отправлен'), ('ERROR', 'Ошибка'), ('SERVICE_UNAVAILABLE', 'Сервис недоступен')], default='PENDING', max_length=20, verbose_name='Статус запроса')),
('date', models.DateField(verbose_name='Дата')), ('date', models.DateField(verbose_name='Дата')),
('patient_id', models.IntegerField(verbose_name='ID пациента')), ('patient_id', models.IntegerField(verbose_name='ID пациента')),
('patient_name', models.CharField(max_length=200, verbose_name='ФИО пациента')), ('patient_first_name', models.CharField(max_length=200, verbose_name='Имя')),
('patient_last_name', models.CharField(max_length=200, verbose_name='Фамилия')),
('patient_middle_name', models.CharField(blank=True, max_length=200, null=True, verbose_name='Отчество')),
('patient_phone', models.CharField(max_length=100, verbose_name='Номер телефона')), ('patient_phone', models.CharField(max_length=100, verbose_name='Номер телефона')),
('status', models.CharField(choices=[('PENDING', 'Обзвон еще не состоялся'), ('APPROVED', 'Прием подтвержден'), ('CANCELED', 'Прием отменен'), ('WITHOUT_ANSWER', 'Не дозвонились'), ('SERVICE_UNAVAILABLE', 'Сервис недоступен')], default='PENDING', max_length=20, verbose_name='Статус')), ('doctor_name', models.CharField(max_length=100, null=True, verbose_name='Врач')),
('data', models.JSONField(default=dict, verbose_name='Данные')), ('doctor_speciality', models.CharField(max_length=100, null=True, verbose_name='Специальность врача')),
('service_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Услуга')),
('address', models.CharField(blank=True, max_length=100, null=True, verbose_name='Адрес')),
('data', models.JSONField(blank=True, default=list, verbose_name='Данные')),
('is_active', models.BooleanField(default=True, verbose_name='Активность')),
('call_id', models.CharField(editable=False, max_length=100, null=True, verbose_name='ID')),
('call_data', models.JSONField(blank=True, default=dict, editable=False)),
('request_time', models.DateTimeField(editable=False, null=True)),
('response_status_code', models.IntegerField(editable=False, null=True)),
('response_message', models.TextField(editable=False, null=True)),
], ],
options={ options={
'verbose_name': 'Запрос на звонок', 'verbose_name': 'Запрос на звонок',

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2 on 2024-09-08 11:21 # Generated by Django 3.2 on 2025-02-11 21:57
from django.db import migrations, models from django.db import migrations, models
@ -12,12 +12,12 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='callrequest', model_name='callrequest',
name='is_active', name='call_text_log',
field=models.BooleanField(default=True, verbose_name='Активность'), field=models.TextField(blank=True, editable=False, null=True, verbose_name='Лог'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='callrequest', model_name='callrequest',
name='data', name='data',
field=models.JSONField(blank=True, default=list, verbose_name='Данные'), field=models.JSONField(blank=True, default=dict, verbose_name='Данные'),
), ),
] ]

View File

@ -1,53 +0,0 @@
# Generated by Django 3.2 on 2024-11-03 11:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('appa', '0002_auto_20240908_1121'),
]
operations = [
migrations.AddField(
model_name='callrequest',
name='address',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Адрес'),
),
migrations.AddField(
model_name='callrequest',
name='call_data',
field=models.JSONField(blank=True, default=dict, editable=False),
),
migrations.AddField(
model_name='callrequest',
name='call_id',
field=models.CharField(editable=False, max_length=100, null=True, verbose_name='ID вызова'),
),
migrations.AddField(
model_name='callrequest',
name='doctor_name',
field=models.CharField(max_length=100, null=True, verbose_name='Врач'),
),
migrations.AddField(
model_name='callrequest',
name='request_time',
field=models.DateTimeField(editable=False, null=True),
),
migrations.AddField(
model_name='callrequest',
name='response_message',
field=models.TextField(editable=False, null=True),
),
migrations.AddField(
model_name='callrequest',
name='response_status_code',
field=models.IntegerField(editable=False, null=True),
),
migrations.AddField(
model_name='callrequest',
name='service_name',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Услуга'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2 on 2025-02-11 21:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('appa', '0002_auto_20250211_2157'),
]
operations = [
migrations.AddField(
model_name='callrequest',
name='call_result',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Результат'),
),
]

View File

@ -1,28 +0,0 @@
# Generated by Django 3.2 on 2024-11-03 11:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('appa', '0003_auto_20241103_1105'),
]
operations = [
migrations.AddField(
model_name='callrequest',
name='request_status',
field=models.CharField(choices=[('PENDING', 'Запрос не отправлен'), ('APPROVED', 'Запрос отправлен'), ('ERROR', 'Ошибка'), ('SERVICE_UNAVAILABLE', 'Сервис недоступен')], default='PENDING', max_length=20, verbose_name='Статус запроса'),
),
migrations.AlterField(
model_name='callrequest',
name='call_id',
field=models.CharField(editable=False, max_length=100, null=True, verbose_name='ID'),
),
migrations.AlterField(
model_name='callrequest',
name='status',
field=models.CharField(choices=[('PENDING', 'Обзвон еще не состоялся'), ('APPROVED', 'Прием подтвержден'), ('CANCELED', 'Прием отменен'), ('WITHOUT_ANSWER', 'Не дозвонились')], default='PENDING', max_length=20, verbose_name='Статус приема'),
),
]

View File

@ -1,5 +1,5 @@
import json import uuid
from django.db import models from django.db import models
from .managers import CallRequestManager from .managers import CallRequestManager
@ -38,22 +38,28 @@ class CallRequest(models.Model):
RequestStatus.SERVICE_UNAVAILABLE: '#7961DB', RequestStatus.SERVICE_UNAVAILABLE: '#7961DB',
} }
uid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
status = models.CharField(max_length=20, choices=Status.choices, default=Status.PENDING, status = models.CharField(max_length=20, choices=Status.choices, default=Status.PENDING,
verbose_name='Статус приема') verbose_name='Статус приема')
request_status = models.CharField(max_length=20, choices=RequestStatus.choices, default=RequestStatus.NOT_SENT, request_status = models.CharField(max_length=20, choices=RequestStatus.choices, default=RequestStatus.NOT_SENT,
verbose_name='Статус запроса') verbose_name='Статус запроса')
date = models.DateField(verbose_name='Дата') date = models.DateField(verbose_name='Дата')
patient_id = models.IntegerField(verbose_name='ID пациента') patient_id = models.IntegerField(verbose_name='ID пациента')
patient_name = models.CharField(max_length=200, verbose_name='ФИО пациента') patient_first_name = models.CharField(max_length=200, verbose_name='Имя')
patient_last_name = models.CharField(max_length=200, verbose_name='Фамилия')
patient_middle_name = models.CharField(max_length=200, null=True, blank=True, verbose_name='Отчество')
patient_phone = models.CharField(max_length=100, verbose_name='Номер телефона') patient_phone = models.CharField(max_length=100, verbose_name='Номер телефона')
doctor_name = models.CharField(max_length=100, null=True, verbose_name='Врач') doctor_name = models.CharField(max_length=100, null=True, verbose_name='Врач')
doctor_speciality = models.CharField(max_length=100, null=True, verbose_name='Специальность врача')
service_name = models.CharField(max_length=100, null=True, blank=True, verbose_name='Услуга') service_name = models.CharField(max_length=100, null=True, blank=True, verbose_name='Услуга')
address = models.CharField(max_length=100, null=True, blank=True, verbose_name='Адрес') address = models.CharField(max_length=100, null=True, blank=True, verbose_name='Адрес')
data = models.JSONField(default=list, blank=True, verbose_name='Данные') data = models.JSONField(default=dict, blank=True, verbose_name='Данные')
is_active = models.BooleanField(default=True, verbose_name='Активность') is_active = models.BooleanField(default=True, verbose_name='Активность')
call_id = models.CharField(max_length=100, null=True, editable=False, verbose_name='ID') call_id = models.CharField(max_length=100, null=True, editable=False, verbose_name='ID')
call_data = models.JSONField(default=dict, blank=True, editable=False) call_data = models.JSONField(default=dict, blank=True, editable=False)
call_text_log = models.TextField(null=True, blank=True, editable=False, verbose_name='Лог')
call_result = models.CharField(max_length=100, null=True, editable=False, blank=True, verbose_name='Результат')
request_time = models.DateTimeField(null=True, editable=False) request_time = models.DateTimeField(null=True, editable=False)
response_status_code = models.IntegerField(null=True, editable=False) response_status_code = models.IntegerField(null=True, editable=False)
response_message = models.TextField(null=True, editable=False) response_message = models.TextField(null=True, editable=False)
@ -68,7 +74,7 @@ class CallRequest(models.Model):
objects = CallRequestManager() objects = CallRequestManager()
def __str__(self): def __str__(self):
return f"{self.date.strftime('%d.%m.%Y')} / {self.patient_name}" return f"{self.date.strftime('%d.%m.%Y')} / {self.patient_last_name}"
def get_status_color(self): def get_status_color(self):
return self.STATUS_COLOR.get(self.status) return self.STATUS_COLOR.get(self.status)
@ -77,6 +83,8 @@ class CallRequest(models.Model):
return self.REQUEST_STATUS_COLOR.get(self.request_status) return self.REQUEST_STATUS_COLOR.get(self.request_status)
def reset_request(self): def reset_request(self):
self.call_id = None
self.call_data = dict()
self.request_status = CallRequest.RequestStatus.NOT_SENT self.request_status = CallRequest.RequestStatus.NOT_SENT
self.request_time = None self.request_time = None
self.response_status_code = None self.response_status_code = None

View File

@ -1,58 +0,0 @@
import datetime
import json
import requests
from django.utils import timezone
from constance import config
from .models import CallRequest, RequestLog
def add_call_request(call_request: CallRequest, logging=True):
call_request.reset_request()
data = dict(
number_b=call_request.patient_phone,
name=call_request.patient_name,
date=call_request.date.strftime('%Y-%m-%d'),
time=call_request.date.strftime('%H:%M'),
doctor=call_request.doctor_name,
address=call_request.address,
)
hooks = None
if logging:
log = RequestLog(
request_url=config.HOST,
request_body=json.dumps(data, ensure_ascii=False, indent=4),
)
hooks = {'response': log.response_hook}
r = requests.post(
config.HOST,
auth=(config.USERNAME, config.PASSWORD),
json=data,
hooks=hooks
)
call_request.response_status_code = r.status_code
call_request.request_time = timezone.now()
if r.status_code == 200:
call_request.call_id = r.json()['request_id']
call_request.request_status = CallRequest.RequestStatus.SENT
elif r.status_code == 400:
call_request.call_id = r.json()['request_id']
call_request.response_message = r.json()['error']
call_request.request_status = CallRequest.RequestStatus.ERROR
call_request.save(update_fields=(
'call_id',
'request_status',
'request_time',
'response_status_code',
'response_message',
))
def call_history(date_from: datetime.date, date_to: datetime.date):
pass

View File

@ -15,16 +15,13 @@ SECRET_KEY = 'django-insecure-13n6^zl86r@=9@!z8gsfv(q6wpggo+$box)^tklnoe9auck-)c
root = environ.Path(__file__) - 2 root = environ.Path(__file__) - 2
env = environ.Env( env = environ.Env(
DEBUG=(bool, False),
LANGUAGE_CODE=(str, 'ru-RU'), LANGUAGE_CODE=(str, 'ru-RU'),
TIME_ZONE=(str, 'Asia/Vladivostok'), TIME_ZONE=(str, 'Asia/Vladivostok'),
USE_TZ=(bool, False), USE_TZ=(bool, False),
USE_I18N=(bool, True), USE_I18N=(bool, True),
CORS_ORIGIN_WHITELIST=(list, []),
AUTH_CONVERT_PASSWORD_TO_LOWER_CASE=(bool, False)
) )
DEBUG = env('DEBUG', False) DEBUG = env.bool('DEBUG', False)
REDIS_HOST = env.str('REDIS_HOST', 'medicine-stack-redis') REDIS_HOST = env.str('REDIS_HOST', 'medicine-stack-redis')
REDIS_PORT = env.str('REDIS_PORT', '6379') REDIS_PORT = env.str('REDIS_PORT', '6379')
@ -32,7 +29,7 @@ REDIS_DB = env.str('REDIS_DB', 1)
POSTGRES_HOST = env.str('POSTGRES_HOST', 'medicine-stack-postgres') POSTGRES_HOST = env.str('POSTGRES_HOST', 'medicine-stack-postgres')
POSTGRES_PORT = env.str('POSTGRES_PORT', '5432') POSTGRES_PORT = env.str('POSTGRES_PORT', '5432')
POSTGRES_DB = env.str('POSTGRES_DB', 'medicine_mts') POSTGRES_DB = env.str('POSTGRES_DB', 'medicine_call')
POSTGRES_USER = env.str('POSTGRES_USER', 'postgres') POSTGRES_USER = env.str('POSTGRES_USER', 'postgres')
POSTGRES_PASSWORD = env.str('POSTGRES_PASSWORD', 'password') POSTGRES_PASSWORD = env.str('POSTGRES_PASSWORD', 'password')
@ -126,13 +123,13 @@ USE_I18N = env.bool('USE_I18N')
USE_TZ = env.bool('USE_TZ') USE_TZ = env.bool('USE_TZ')
STATIC_URL = '/medicine-mts/django_static/' STATIC_URL = '/medicine-call/django_static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'django_static') STATIC_ROOT = os.path.join(BASE_DIR, 'django_static')
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
SESSION_COOKIE_NAME = env.str('SESSION_COOKIE_NAME', 'medicine-mts') SESSION_COOKIE_NAME = env.str('SESSION_COOKIE_NAME', 'medicine-call')
CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend' CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend'
@ -150,21 +147,41 @@ CONSTANCE_ADDITIONAL_FIELDS = {
} }
CONSTANCE_CONFIG = { CONSTANCE_CONFIG = {
'HOST': ('https://amniss-ai.ru/api/v.2/', 'Хост', 'char'),
'ENTRYPOINT_ADD_RECORDS': ('https://amniss-ai.ru/api/v.2/records/{scenarioId}', 'Адрес для добавления записей', 'char'),
'ENTRYPOINT_AUTH': ('https://amniss-ai.ru/api/auth', 'Адрес для авторизации', 'char'),
'ENTRYPOINT_DELETE': ('https://amniss-ai.ru/api/v.1/records/delete/%s', 'Адрес для удаления', 'char'),
'ENTRYPOINT_RECORD': ('https://amniss-ai.ru/api/v.1/records/%s', 'Адрес записи', 'char'),
'SCENARIO_ID': ('', 'ID сценария', 'char'),
'USERNAME': ('', 'Имя пользователя', 'char'), 'USERNAME': ('', 'Имя пользователя', 'char'),
'PASSWORD': ('', 'Пароль', 'char'), 'PASSWORD': ('', 'Пароль', 'char'),
'HOST': ('', 'Хост', 'char'),
'IS_ENABLED': (False, 'Активен', bool), 'IS_ENABLED': (False, 'Активен', bool),
'ACCESS_TOKEN': ('', 'Access token', 'char'),
'REFRESH_TOKEN': ('', 'Refresh token', 'char'),
'ACCESS_TOKEN_EXPIRED': (
datetime.datetime(2025, 1, 1, 0, 0),
'Access token expired',
datetime.datetime
),
'MEDICINE_TOKEN': ('', 'Токен', 'char'), 'MEDICINE_TOKEN': ('', 'Токен', 'char'),
'MEDICINE_HOST': ('http://medicine-app/', 'Хост', 'char'), 'MEDICINE_HOST': ('http://medicine-app/', 'Хост', 'char'),
} }
CONSTANCE_CONFIG_FIELDSETS = ( CONSTANCE_CONFIG_FIELDSETS = (
('МТС', ( ('API', (
'HOST', 'HOST',
'ENTRYPOINT_AUTH',
'ENTRYPOINT_ADD_RECORDS',
'ENTRYPOINT_DELETE',
'ENTRYPOINT_RECORD',
'SCENARIO_ID',
'USERNAME', 'USERNAME',
'PASSWORD', 'PASSWORD',
'IS_ENABLED', 'IS_ENABLED',
'ACCESS_TOKEN',
'ACCESS_TOKEN_EXPIRED',
'REFRESH_TOKEN'
)), )),
('МИС', ( ('МИС', (
'MEDICINE_HOST', 'MEDICINE_HOST',
@ -191,4 +208,4 @@ CALL_REQUEST_TIME_END = datetime.time(21, 0)
if DEBUG: if DEBUG:
AUTH_PASSWORD_VALIDATORS = [] AUTH_PASSWORD_VALIDATORS = []
SESSION_COOKIE_NAME = 'dev-medicine-mts' SESSION_COOKIE_NAME = 'dev-medicine-call'

View File

@ -5,23 +5,24 @@ from constance import config
from appa.celery import app from appa.celery import app
from appa.models import * from appa.models import *
from appa.mts_api import add_call_request from appa.call_api import add_call_request
@app.task(bind=True, acks_late=True) @app.task(bind=True, acks_late=True)
def send_call_request_task(self, ids=None): def send_call_request_task(self, ids=None):
tomorrow = datetime.date.today() + datetime.timedelta(days=1) call_requests = CallRequest.objects.filter(is_active=True)
call_requests = CallRequest.objects.filter(
date=tomorrow,
status__in=[
CallRequest.Status.PENDING,
CallRequest.Status.WITHOUT_ANSWER
],
is_active=True
)
if ids and len(ids) > 0: if ids and len(ids) > 0:
call_requests = call_requests.filter(id__in=ids) call_requests = call_requests.filter(id__in=ids)
else:
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
call_requests = CallRequest.objects.filter(
date=tomorrow,
status__in=[
CallRequest.Status.PENDING,
CallRequest.Status.WITHOUT_ANSWER
]
)
for call_request in call_requests: for call_request in call_requests:
add_call_request(call_request) add_call_request(call_request)

View File

@ -1,10 +1,10 @@
{% extends "admin/base_site.html" %} {% extends "admin/base_site.html" %}
{% load static %} {% load static %}
{% block title %}{{ title }} | МТС{% endblock %} {% block title %}{{ title }} | CALL{% endblock %}
{% block branding %} {% block branding %}
<h1 id="site-name"> <h1 id="site-name">
<a href="{% url 'admin:index' %}">МТС</a> <a href="{% url 'admin:index' %}">CALL</a>
</h1> </h1>
{% endblock %} {% endblock %}

View File

@ -1,14 +1,30 @@
import json
import random
from django.utils.crypto import get_random_string
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse from django.http import JsonResponse
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
@csrf_exempt
def auth_view(request):
return JsonResponse({
'accessToken': get_random_string(32),
'refreshToken': get_random_string(32),
})
@csrf_exempt @csrf_exempt
def add_success_view(request): def add_records_view(request):
data = json.loads(request.body)
results = []
for record in data['records']:
record['id'] = random.randint(1, 10000)
results.append(record)
return JsonResponse({ return JsonResponse({
'request_id': get_random_string(10), 'added_records': results
'success': '1'
}) })

View File

@ -10,17 +10,18 @@ from appa import test_views
admin.site.unregister(Group) admin.site.unregister(Group)
urlpatterns = [ urlpatterns = [
path('medicine-mts/admin/', admin.site.urls), path('medicine-call/admin/', admin.site.urls),
path('medicine-mts/api/', api.urls), path('medicine-call/api/', api.urls),
path('medicine-mts/', lambda request: redirect('/medicine-mts/admin/')), path('medicine-call/', lambda request: redirect('/medicine-call/admin/')),
path('admin/', lambda request: redirect('/medicine-mts/admin/')), path('admin/', lambda request: redirect('/medicine-call/admin/')),
path('', lambda request: redirect('/medicine-mts/admin/')), path('', lambda request: redirect('/medicine-call/admin/')),
] ]
if settings.DEBUG: if settings.DEBUG:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns, static from django.contrib.staticfiles.urls import staticfiles_urlpatterns, static
urlpatterns +=[ urlpatterns +=[
path('medicine-mts/tests/add_success_view/', test_views.add_success_view), path('medicine-mts/tests/auth/', test_views.auth_view),
path('medicine-mts/tests/add_records/', test_views.add_records_view),
path('medicine-mts/tests/add_error_view/', test_views.add_error_view), path('medicine-mts/tests/add_error_view/', test_views.add_error_view),
path('medicine-mts/tests/add_500_error_view/', test_views.add_500_error_view), path('medicine-mts/tests/add_500_error_view/', test_views.add_500_error_view),
path('medicine-mts/tests/history_view/', test_views.history_view), path('medicine-mts/tests/history_view/', test_views.history_view),

8
build-local.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
set -e
docker build \
--target python-nginx \
--file ./Dockerfile \
--tag medicine-call-local:latest .

5
local-celery.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
set -e
docker exec medicine-call-local-server celery -A appa worker -B --loglevel=INFO --concurrency=1

5
local-enter.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
set -e
docker exec -it medicine-call-local-server bash

26
local-server.sh Executable file
View File

@ -0,0 +1,26 @@
#!/bin/sh
docker stop medicine-call-local-server
docker rm medicine-call-local-server
open -n -a "Google Chrome" --args "http://0.0.0.0:9400/admin/"
docker run --rm \
--name medicine-call-local-server \
--network=local-network \
--volume .:/app \
--volume medicine-call-local:/app/public \
--publish 9400:80 \
--env-file .env \
medicine-call-local:latest \
uwsgi \
--http 0.0.0.0:80 \
--wsgi-file wsgi.py \
--workers 2 \
--threads 2 \
--master \
--py-autoreload 1 \
--disable-write-exception \
--buffer-size 32768 \
--http-timeout 30 \
--check-static /app/

View File

@ -11,6 +11,7 @@ click-didyoumean==0.3.1
click-plugins==1.1.1 click-plugins==1.1.1
click-repl==0.3.0 click-repl==0.3.0
Django==3.2 Django==3.2
django-admin-rangefilter==0.13.2
django-constance==3.1.0 django-constance==3.1.0
django-environ==0.11.2 django-environ==0.11.2
django-ninja==1.2.0 django-ninja==1.2.0
@ -31,6 +32,7 @@ sqlparse==0.5.1
typing_extensions==4.12.2 typing_extensions==4.12.2
tzdata==2024.1 tzdata==2024.1
urllib3==2.2.2 urllib3==2.2.2
uWSGI==2.0.26 uWSGI==2.0.28
vine==5.1.0 vine==5.1.0
wcwidth==0.2.13 wcwidth==0.2.13
wheel==0.43.0

View File

@ -17,7 +17,7 @@ command=uwsgi
--vacuum --vacuum
--need-app --need-app
--disable-write-exception --disable-write-exception
--static-map /medicine-mts/django_static=/app/django_static --static-map /medicine-call/django_static=/app/django_static
autostart=true autostart=true
autorestart=true autorestart=true
stderr_logfile=/dev/stderr stderr_logfile=/dev/stderr