Преглед на файлове

Вывод исполнителей и тарифов по услугам, редактирование тарифов по услугам(промежуточный вариант)

Староверов Данила Андреевич преди 1 година
родител
ревизия
3faf522856

+ 3 - 0
.gitignore

@@ -2,8 +2,11 @@
 env/
 venv/
 #module
+tickets/
 staticfiles/
 core/config.py
+migrations/
+!__init__.py
 # VSCode
 .vscode
 

+ 9 - 0
SharixAdmin/admin.py

@@ -6,6 +6,7 @@ from SharixAdmin.models import *
 from django import forms
 from xmpp import cli
 from django.contrib.auth.admin import UserAdmin
+from django.contrib.auth.models import Permission
 import django.contrib.auth.admin as adm
 
 class MessageForm(forms.Form):
@@ -37,6 +38,14 @@ def send_phone(modeladmin, request, queryset):
     return render(request, "SharixAdmin/senderform.html", {"items":queryset, "form":form, 'title':'Отправка сообщений на номер телефона'})
 send_phone.short_description = u"Отправить сообщение на номер телефона"
 
+@admin.register(Permission)
+class PermissionsAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'name',
+        'content_type',
+        'codename',
+    )
     
 @admin.register(SharixUser)
 class SharixUserAdmin(adm.UserAdmin):

+ 16 - 1
SharixAdmin/forms.py

@@ -1,4 +1,6 @@
 from django.contrib.auth.forms import AuthenticationForm
+
+from metaservicesynced.models import Service
 from .models import SharixUser
 from django import forms
 
@@ -12,4 +14,17 @@ class LoginUserForm(AuthenticationForm):
 
     class Meta:
         model = SharixUser
-        fields = ['username', 'password']
+        fields = ['username', 'password']
+
+class ServiceTariffForm(forms.ModelForm):
+
+    class Meta:
+        model = Service
+        fields = ['status','ticket_status','servicetype_id','id_provider',
+                  'resource_id','requirements','price_alg','price_km','price_min','price_amount','service_status',
+                  'is_global','is_visible']
+        widgets = {
+            'status': forms.TextInput(attrs={'readonly': True}),
+            'ticket_status': forms.TextInput(attrs={'readonly': True}),
+        }
+        

+ 1 - 1
SharixAdmin/migrations/0001_initial.py

@@ -1,4 +1,4 @@
-# Generated by Django 4.1.3 on 2023-03-17 10:12
+# Generated by Django 4.1.3 on 2023-03-31 19:43
 
 import django.contrib.auth.models
 import django.contrib.auth.validators

+ 44 - 1
SharixAdmin/tables.py

@@ -1,4 +1,6 @@
 import django_tables2 as tables
+
+from metaservicesynced.models import *
 from .models import *
 from django.utils.html import format_html
 
@@ -25,4 +27,45 @@ class TransactionsWalletTable(tables.Table):
         return format_html("<a href='{}'>{}</a>", record.get_absolute_url(), value)
         
 
-    
+class ProviderTable(tables.Table):
+
+    id = tables.Column(verbose_name='ID', attrs={"td":{"width":"5%"}})
+    user_id = tables.Column(accessor='user_id.full_name', order_by=('user_id.first_name', 'user_id.last_name'), verbose_name='ФИО', attrs={"td":{"width":"15%"}})
+    status = tables.Column(verbose_name='Статус', attrs={'th':{'scope':'col'}, "td":{"width":"20%"}}) 
+    check = tables.BooleanColumn(verbose_name='', attrs={'th':{'scope':'col'}, "td":{"width":"20%"}})
+    paginate_by = 10
+    class Meta:
+        model = Provider
+        attrs = {"class": "table table-layout-fixed"}
+        exclude = ('type','company_id','id_metaservice', 'requirements', 
+                   'ticket_status', 'location_type', 'default_location', 
+                   'is_global', 'is_visible')
+
+    def render_check(self, value, record):
+        if record.status == 'active':
+            return format_html('<input class="form-check-input status-toggle" checked type="checkbox" id="flexCheckDefault" data-provider-id="{}">', record.id)
+        else:
+            return format_html('<input class="form-check-input status-toggle" type="checkbox" id="flexCheckDefault" data-provider-id="{}">', record.id)
+
+class ServiceTariffTable(tables.Table):
+
+    id = tables.Column(verbose_name='ID', attrs={"td":{"width":"5%"}})
+    servicetype_id = tables.LinkColumn('service_tariff/edit/', verbose_name='Название тарифа', text = lambda record: record.servicetype_id.caption,
+        args=[tables.A('pk')], attrs={'th':{'scope':'col'}, "td":{"width":"20%"}})
+    ticket_status = tables.Column(verbose_name='Название схемы услуги', attrs={'th':{'scope':'col'}, "td":{"width":"20%"}}) 
+    check = tables.BooleanColumn(verbose_name='Активность', orderable=False, attrs={'th':{'scope':'col'}, "td":{"width":"20%"}})
+
+
+    class Meta:
+        model = Service
+        attrs = {"class": "table table-layout-fixed"}
+        exclude = ('resource_id','id_provider','price_alg',
+                   'price_min','price_amount','id_metaservice', 
+                   'requirements', 'service_status', 'price_km',
+                   'is_global', 'is_visible','status')
+
+    def render_check(self, value, record):
+        if record.status == 'active':
+            return format_html('<input class="form-check-input status-toggle" disabled  checked type="checkbox"')
+        else:
+            return format_html('<input class="form-check-input status-toggle" disabled  type="checkbox"')

+ 36 - 0
SharixAdmin/templates/SharixAdmin/provider.html

@@ -0,0 +1,36 @@
+{% extends 'SharixAdmin/index.html' %}
+{% load render_table from django_tables2 %}
+
+{% block contenthome %}
+    <h1 >{{ title }}</h1>
+    <div class="container text-center mt-2">
+      {% render_table table %}
+    </div>
+    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
+    <script>
+      $('.status-toggle').change(function() {
+        var provider_id = $(this).data('provider-id');
+        var new_status = $(this).prop('checked') ? 'active' : 'deactivated';
+        $.ajax({
+          url: '{% url "provider/change_status" %}',
+          type: 'POST',
+          data: {
+            'provider_id': provider_id,
+            'new_status': new_status,
+            'csrfmiddlewaretoken': '{{ csrf_token }}'
+          },
+          success: function(response) {
+            var scrollTop = window.pageYOffset;
+            location.reload();
+            window.scrollTo(0, scrollTop);
+          },
+          error: function(xhr, status, error) {
+            console.log(xhr.responseText);
+          }
+        });
+      });
+    </script>
+    
+
+    
+{% endblock contenthome %}

+ 5 - 6
SharixAdmin/templates/SharixAdmin/senderform.html

@@ -1,11 +1,10 @@
-{% extends "admin/base_site.html" %}
+{% extends 'SharixAdmin/index.html' %}
 
-{% block content %}
-<form action="" method="post">{% csrf_token %}
+{% block contenthome %}
+<form action="" method="post">
+    {% csrf_token %}
     {{ form }}
     <p>Сообщение будет отправлена следующим пользователям:</p>
-    <ul>{{ items|unordered_list }}</ul>
-    <input type="hidden" name="action" value="send_phone" />
-    <input type="submit" name="apply" value="Отправить" />
+    <input type="submit" value="Отправить" />
 </form>
 {% endblock %}

+ 47 - 0
SharixAdmin/templates/SharixAdmin/service_tariff.html

@@ -0,0 +1,47 @@
+{% extends 'SharixAdmin/index.html' %}
+{% load render_table from django_tables2 %}
+
+{% block contenthome %}
+    <h1 >{{ title }}</h1>
+    <div class="container text-center mt-2">
+          {% render_table table %}
+
+          
+          {% if table.page %}
+            <nav aria-label="...">
+              <ul class="pagination">
+                {% if table.page.has_previous %}
+                <li class="page-item">
+                  <a class="page-link" href="?page={{ table.page.previous_page_number }}" tabindex="-1">Previous</a>
+                </li>
+                {% else %}
+                <li class="page-item disabled">
+                  <span class="page-link">Previous</span>
+                </li>
+                {% endif %}
+                {% for page in table.page_range %}
+                  {% if page == table.page.number %}
+                  <li class="page-item active">
+                    <span class="page-link">{{ page }} <span class="sr-only">(current)</span></span>
+                  </li>
+                  {% else %}
+                  <li class="page-item">
+                    <a class="page-link" href="?page={{page }}">{{ page }}</a>
+                  </li>
+                  {% endif %}
+                {% endfor %}
+                {% if table.page.has_next %}
+                <li class="page-item">
+                  <a class="page-link" href="?page={{ table.page.next_page_number }}">Next</a>
+                </li>
+                {% else %}
+                <li class="page-item disabled">
+                  <span class="page-link">Next</span>
+                </li>
+                {% endif %}
+              </ul>
+            </nav>
+          {% endif %}
+    </div>
+    
+{% endblock contenthome %}

+ 18 - 0
SharixAdmin/templates/SharixAdmin/service_tariff_form.html

@@ -0,0 +1,18 @@
+{% extends 'SharixAdmin/index.html' %}
+
+{% block contenthome %}
+<h1 class="mb-4">{{ title }}</h1>
+<form method="post" style="overflow: auto">
+    {% csrf_token %}
+    <div class="container m-2">
+        {% for field in form %}
+        {{field.errors}}
+        <div class="row">
+            {{field.label_tag}}
+            {{field}}
+        </div>
+        {% endfor %}
+    </div>
+    <input type="submit" name="apply" value="Отправить" />
+</form>
+{% endblock %}

+ 9 - 1
SharixAdmin/urls.py

@@ -5,6 +5,7 @@ from rest_framework import routers
 from django_spaghetti.views import Plate
 from schema_graph.views import Schema
 from django.contrib.auth.decorators import login_required
+
 router = routers.SimpleRouter()
 router.register(r'sharix-users', SharixUserMVS)
 router.register(r'group', GroupMVS)
@@ -18,7 +19,14 @@ urlpatterns = [
     path('logout/', logout_view, name='logoutweb'),
     path('balance/', balance, name='balance'),
     path('test/', testPage, name='test-page'),
+
     
+    path('provider/', ProviderListView.as_view(), name='provider'),
+    path('provider/change_status/', change_provider_status, name='provider/change_status'),
+
+    path('service_tariff/', ServiceTariffListView.as_view(), name='service_tariff'),
+    path('service_tariff/edit/<int:pk>', ServiceTariffUpdateView.as_view(), name='service_tariff/edit/'),
+
     #path('v1/auth/', include('djoser.urls')),
     path('auth/', include('djoser.urls.authtoken'), name='auth'),
     path('platform/api/', include(router.urls), name="sharix-api"),
@@ -27,6 +35,6 @@ urlpatterns = [
     path('schemav1/', login_required(Schema.as_view()), name='schemav1'),
     path('schemav2/', login_required(Plate.as_view()),  name='schemav2'),
     path('schemav3/', schema_v3, name='schema'),
-
+    
     re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
 ]

+ 67 - 2
SharixAdmin/views.py

@@ -1,16 +1,20 @@
 
 import json
 from django.shortcuts import render
-from django.http import HttpResponseRedirect, HttpResponse
+from django.http import HttpResponseRedirect, HttpResponse, JsonResponse
 from django.contrib.auth.views import LoginView
 from django.urls import reverse_lazy, resolve, reverse
 from django.contrib.auth.decorators import login_required
+from django_tables2 import SingleTableView
 from .forms import *
 from SharixAdmin.models import *
 from django.contrib.auth import logout
 from django.db.models import Q
 from .tables import *
 from django import template
+from django.views.generic.edit import UpdateView
+
+from metaservicesynced.models import *
 # Create your views here.
 
 
@@ -103,6 +107,8 @@ menu = [
     {'title':'Сотрудничество',          'link':'test-page', 'sel':'sotrud'},
     {'title':'Техподдержка',            'link':'test-page', 'sel':'gear'},
     {'title':'Мои заявки',              'link':'tickets', 'sel':'tikets'},
+    {'title':'Исполнители',             'link':'provider', 'sel':'people'},
+    {'title':'Тарифы услуг',            'link':'service_tariff', 'sel':'person'},
 ]
 
 def get_context(request, page_context) -> dict:
@@ -115,6 +121,64 @@ def get_context(request, page_context) -> dict:
     return context
 
 
+def change_provider_status(request):
+    if request.method == 'POST':
+        provider_id = request.POST.get('provider_id')
+        new_status = request.POST.get('new_status')
+        
+        provider = Provider.objects.get(pk=provider_id)
+        provider.status = new_status
+        provider.save()
+        return JsonResponse({'status': 'success'})
+    else:
+        return JsonResponse({'status': 'error'})
+
+class ServiceTariffUpdateView(UpdateView):
+    model = Service
+    form_class = ServiceTariffForm
+    template_name = "SharixAdmin/service_tariff_form.html"
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context.update(get_context(self.request, {
+            'title': 'Тарифы услуг',
+            'object': self.object,
+        }))
+        return context
+    
+    def get_success_url(self):
+        return reverse('service_tariff')
+
+class ProviderListView(SingleTableView):
+    table_class = ProviderTable
+    queryset = Provider.objects.all()
+    template_name = 'SharixAdmin/provider.html'
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context.update(get_context(self.request, {
+            'title': 'Исполнители',
+            'object_list': context['object_list'],
+        }))
+        return context
+
+class ServiceTariffListView(SingleTableView):
+    table_class = ServiceTariffTable
+    queryset = Service.objects.all()
+    template_name = 'SharixAdmin/service_tariff.html'
+    # paginate_by = 2
+
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context.update(get_context(self.request, {
+            'title': 'Тарифы услуг',
+            'object_list': context['object_list'],
+        }))
+        return context
+
+
+
 
 
 #Shema views
@@ -127,7 +191,8 @@ def schema_v3(request):
 
 
 
-    
+
+
 
 
 

+ 0 - 26
core/config_template.py

@@ -1,26 +0,0 @@
-#Create file config.py with this setting or rename this file to config.py
-
-#BASE
-DEBUG=True
-SECRET_KEY='secret-key(absolutely any character)'
-ALLOWED_HOSTS = ['127.0.0.1']
-CSRF_TRUSTED_ORIGINS = []
-
-#DATABSE
-DB_NAME=None
-DB_USER=None
-DB_PASSWORD=None
-DB_HOST=None
-
-#GUNICORN
-BIND = "127.0.0.1:8000"
-WORKERS = 2
-THREADS = 4
-
-#STATIC
-from pathlib import Path
-import os
-BASE_DIR = Path(__file__).resolve().parent.parent
-STATIC_URL = '/static/'
-STATICFILES_DIRS = [BASE_DIR / "SharixAdmin/static/", BASE_DIR / "tickets/static/"]
-STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")

+ 2 - 0
core/urls.py

@@ -11,6 +11,8 @@ urlpatterns = (
     path('admin/', admin.site.urls),
     path('', include('SharixAdmin.urls')),
     path('tickets/', include("tickets.urls"), name='tickets'),
+    #metaservice
+    path('metaservicesynced/', include("metaservicesynced.urls"), name="metaservicesynced"),
     
 
 ] 

+ 4 - 0
install_linux.sh

@@ -1,5 +1,9 @@
 #!/bin/sh
 
+git clone -b tickets_module http://git.sharix-app.org/ShariX_Open/sharix-open-tickets.git tickets
+
+git clone -b metasynced_module http://git.sharix-app.org/ShariX_Open/sharix-open-backend.git metaservicesynced
+
 python3 -m venv env
 
 source env/bin/activate

+ 2 - 0
install_win.bat

@@ -1,3 +1,5 @@
 @echo off
+git clone -b tickets_module http://git.sharix-app.org/ShariX_Open/sharix-open-tickets.git tickets
+git clone -b metasynced_module http://git.sharix-app.org/ShariX_Open/sharix-open-backend.git metaservicesynced
 python -m venv env
 .\env\Scripts\activate && pip install -r requirements.txt && python manage.py makemigrations && python manage.py migrate && python manage.py createsuperuser && python manage.py runserver

+ 220 - 1
metaservicesynced/admin.py

@@ -1,3 +1,222 @@
 from django.contrib import admin
+from .models import *
 
-# Register your models here.
+
+@admin.register(Company)
+class CompanyAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'legal_name',
+        'repr_id',
+        'inn',
+        'kpp',
+        'ogrn',
+        'bank_name',
+        'bik',
+        'ks',
+        'rs',
+        'address',
+        'requirements',
+        'status',
+        'ticket_status',
+        'id_metaservice',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = ('repr_id', 'ticket_status')
+
+
+@admin.register(Permissions)
+class PermissionsAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'check_date',
+        'id_permissions',
+        'check_level',
+        'checked_by',
+        'user_id',
+        'status',
+        'ticket_status',
+        'id_metaservice',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = ('check_date', 'checked_by', 'user_id', 'ticket_status')
+
+
+@admin.register(ServiceType)
+class ServiceTypeAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'codename',
+        'caption',
+        'description',
+        'requirements',
+        'price_type',
+        'status',
+        'ticket_status',
+        'id_metaservice',
+        'link_agreement',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = ('ticket_status',)
+
+
+@admin.register(Provider)
+class ProviderAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'type',
+        'company_id',
+        'user_id',
+        'id_metaservice',
+        'requirements',
+        'status',
+        'ticket_status',
+        'location_type',
+        'default_location',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = ('company_id', 'user_id', 'ticket_status')
+
+
+@admin.register(Resource)
+class ResourceAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'type_id',
+        'user_id',
+        'requirements',
+        'status',
+        'ticket_status',
+        'id_metaservice',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = ('user_id', 'ticket_status')
+
+
+@admin.register(Service)
+class ServiceAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'servicetype_id',
+        'id_provider',
+        'resource_id',
+        'requirements',
+        'id_metaservice',
+        'price_alg',
+        'price_km',
+        'price_min',
+        'price_amount',
+        'service_status',
+        'status',
+        'ticket_status',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = (
+        'servicetype_id',
+        'id_provider',
+        'resource_id',
+        'ticket_status',
+    )
+
+
+@admin.register(Documents)
+class DocumentsAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'check_date',
+        'check_level',
+        'expire_date',
+        'id_metaservice',
+        'requirements',
+        'status',
+        'ticket_status',
+        'datalink',
+        'doc_type',
+        'user_id',
+        'company_id',
+        'is_global',
+        'is_visible',
+        'checked_by',
+    )
+    list_filter = (
+        'check_date',
+        'expire_date',
+        'ticket_status',
+        'user_id',
+        'company_id',
+        'checked_by',
+    )
+
+
+@admin.register(Client)
+class ClientAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'user',
+        'requirements',
+        'status',
+        'ticket_status',
+        'id_metaservice',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = ('user', 'ticket_status')
+
+
+@admin.register(Orders)
+class OrdersAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'service',
+        'service_type',
+        'state',
+        'id_metaservice',
+        'provider',
+        'receiver',
+        'client_id',
+        'time_created',
+        'time_placed',
+        'time_start',
+        'time_finish_predicted',
+        'time_finish_real',
+        'ticket',
+        'predicted_price',
+        'real_price',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = (
+        'service',
+        'service_type',
+        'provider',
+        'receiver',
+        'client_id',
+        'time_created',
+        'time_placed',
+        'time_start',
+        'time_finish_predicted',
+        'time_finish_real',
+    )
+
+
+@admin.register(Relationship)
+class RelationshipAdmin(admin.ModelAdmin):
+    list_display = (
+        'id',
+        'user_id_who',
+        'user_id_whom',
+        'neg_type',
+        'id_metaservice',
+        'requirements',
+        'status',
+        'ticket_status',
+        'is_global',
+        'is_visible',
+    )
+    list_filter = ('user_id_who', 'user_id_whom', 'ticket_status')

+ 17 - 0
metaservicesynced/apiview.py

@@ -0,0 +1,17 @@
+from .serializer import *
+from rest_framework import viewsets, permissions, exceptions
+from rest_framework.authentication import TokenAuthentication
+from rest_framework.decorators import action
+from metaservicesynced.models import *
+from rest_framework.views import APIView
+from rest_framework.response import Response
+
+class DocumentsMVS(viewsets.ModelViewSet):
+    """
+    
+    """
+
+    queryset = Documents.objects.all()
+    serializer_class = DocumentsSerializer
+    #permission_classes = [IsOwnerOrReadOnly]
+    permission_classes = [permissions.IsAuthenticated]

+ 834 - 6
metaservicesynced/migrations/0001_initial.py

@@ -1,5 +1,6 @@
-# Generated by Django 4.1.3 on 2023-03-28 09:31
+# Generated by Django 4.1.3 on 2023-03-31 20:21
 
+from django.conf import settings
 from django.db import migrations, models
 import django.db.models.deletion
 
@@ -10,11 +11,545 @@ class Migration(migrations.Migration):
 
     dependencies = [
         ("tickets", "0001_initial"),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
     ]
 
     operations = [
         migrations.CreateModel(
-            name="Documents",
+            name="Client",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("requirements", models.CharField(max_length=150)),
+                (
+                    "status",
+                    models.CharField(
+                        help_text="активность на основе системы заявок", max_length=150
+                    ),
+                ),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.",
+                        null=True,
+                    ),
+                ),
+                ("is_global", models.CharField(max_length=1)),
+                ("is_visible", models.CharField(max_length=1)),
+                (
+                    "ticket_status",
+                    models.ForeignKey(
+                        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="tickets.task",
+                    ),
+                ),
+                (
+                    "user",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "client",
+            },
+        ),
+        migrations.CreateModel(
+            name="Company",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "legal_name",
+                    models.CharField(
+                        help_text="настоящее имя юридического лица", max_length=150
+                    ),
+                ),
+                (
+                    "inn",
+                    models.CharField(
+                        help_text="ИНН компании", max_length=10, unique=True
+                    ),
+                ),
+                ("kpp", models.CharField(help_text="КПП компании", max_length=9)),
+                ("ogrn", models.CharField(help_text="ОГРН компании", max_length=13)),
+                (
+                    "bank_name",
+                    models.CharField(
+                        help_text="Название банка с расчетным счетом", max_length=150
+                    ),
+                ),
+                ("bik", models.CharField(help_text="БИК компании", max_length=9)),
+                (
+                    "ks",
+                    models.CharField(
+                        help_text="Корреспондентский счёт (счёт, открываемый банковской организацией в подразделении самого банка)",
+                        max_length=50,
+                    ),
+                ),
+                ("rs", models.CharField(help_text="Расчетный счет", max_length=50)),
+                (
+                    "address",
+                    models.CharField(help_text="Юридический адрес", max_length=150),
+                ),
+                (
+                    "requirements",
+                    models.CharField(
+                        help_text="код необходимого для того, чтобы ресурс мог стать активным",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "status",
+                    models.CharField(
+                        help_text="статус обработки заявки в системе заявок",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.",
+                        null=True,
+                    ),
+                ),
+                (
+                    "is_global",
+                    models.CharField(
+                        help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "is_visible",
+                    models.CharField(
+                        help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "repr_id",
+                    models.ForeignKey(
+                        help_text="уникальный идентификатор представителя компании. Это обязательно пользователь-провайдер определенного типа. То есть нельзя назначить ответственного, который не может быть ответственным.",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+                (
+                    "ticket_status",
+                    models.ForeignKey(
+                        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="tickets.task",
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "company",
+            },
+        ),
+        migrations.CreateModel(
+            name="Provider",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "type",
+                    models.CharField(
+                        help_text="тип поставщика (партнер/ответственное лицо/поставщик услуг). Смысл такой - провайдер это статус пользователя, который, в зависимости от применения, может нести разный смысл и подразумевает под собой какой-то тип действия. Обычные исполнители - это провайдеры услуг (код 3). Ответственные за какое-то имущество, которые сдают его в аренду - это тоже провайдеры (код 2). Ответственные за набор услуг перед метасервисом (фактически - назначенные админы) - это провайдеры-партнеры (код 1)",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер.",
+                        null=True,
+                    ),
+                ),
+                (
+                    "requirements",
+                    models.CharField(
+                        help_text="требования для того, чтобы можно было предоставлять услуги любые в этом метасервисе в целом (самые строгие)",
+                        max_length=300,
+                    ),
+                ),
+                (
+                    "status",
+                    models.CharField(
+                        help_text="статус пользователя в системе относительно прохождения проверок (activity_status) (может быть active только в том случае, если ticket, влияющий на статус - закрыт.",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "location_type",
+                    models.CharField(
+                        help_text="статическая или динамическая локация оказания услуги. Если статическая, а исполнитель находится существенно за пределами локации - то тогда статус автоматом оффлайн для приема новых заявок.",
+                        max_length=300,
+                    ),
+                ),
+                (
+                    "default_location",
+                    models.CharField(
+                        help_text="локация по умолчанию для объекта.", max_length=300
+                    ),
+                ),
+                (
+                    "is_global",
+                    models.CharField(
+                        help_text="(аккаунт поставщика услуг) – доступен для планирования в цепочке с другими услугами в глобальном сервисе",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "is_visible",
+                    models.CharField(
+                        help_text="(аккаунт поставщика услуг) – доступен для хранения в  глобальном сервисе/необходима синхронизация",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "company_id",
+                    models.ForeignKey(
+                        help_text="уникальный идентификатор компании, от лица которой выступает провайдер. Смысл такой - ответственны могут быть только одушевленные лица, компании - не одушевленные. Все услуги предоставляются через компании-партнеры, самозанятые или ИП являются единицами таких компаний.",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.company",
+                    ),
+                ),
+                (
+                    "ticket_status",
+                    models.ForeignKey(
+                        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="tickets.task",
+                    ),
+                ),
+                (
+                    "user_id",
+                    models.ForeignKey(
+                        help_text="уникальный идентификатор конкретного пользователя системы (meta-user), который будет оказывать услугу. Один пользователь может быть провайдером нескольких услуг. Статус провайдера означает, что с данным пользователем может быть установлена связь, как с исполнителем.",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "provider",
+            },
+        ),
+        migrations.CreateModel(
+            name="Resource",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "type_id",
+                    models.CharField(help_text="идентификатор ресурса", max_length=10),
+                ),
+                (
+                    "requirements",
+                    models.CharField(
+                        help_text="код необходимого для того, чтобы ресурс мог стать активным",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "status",
+                    models.CharField(
+                        help_text="статус обработки заявки в системе заявок",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.",
+                        null=True,
+                    ),
+                ),
+                (
+                    "is_global",
+                    models.CharField(
+                        help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "is_visible",
+                    models.CharField(
+                        help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "ticket_status",
+                    models.ForeignKey(
+                        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="tickets.task",
+                    ),
+                ),
+                (
+                    "user_id",
+                    models.ForeignKey(
+                        help_text="уникальный идентификатор ответственного",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "resource",
+            },
+        ),
+        migrations.CreateModel(
+            name="ServiceType",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "codename",
+                    models.CharField(
+                        help_text="латинское наименование услуги в системе",
+                        max_length=255,
+                    ),
+                ),
+                (
+                    "caption",
+                    models.CharField(
+                        help_text="наименование услуги для отображения пользователю",
+                        max_length=255,
+                    ),
+                ),
+                (
+                    "description",
+                    models.TextField(blank=True, help_text="текстовое описание услуги"),
+                ),
+                (
+                    "requirements",
+                    models.CharField(
+                        help_text="код требований на основе вспомогательных таблиц-справочников",
+                        max_length=300,
+                    ),
+                ),
+                (
+                    "price_type",
+                    models.CharField(
+                        help_text="ценообразование - код допустимых вариантов или код параметров, принимаемых во внимание и способ их учета (по сути хорошо закодировать формулу)",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "status",
+                    models.CharField(
+                        help_text="активность на основе системы заявок", max_length=150
+                    ),
+                ),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text=" уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер."
+                    ),
+                ),
+                (
+                    "link_agreement",
+                    models.CharField(
+                        help_text="ссылка на договор в вики об оказании услуги данного типа (аренда, перевозка и тп)",
+                        max_length=400,
+                    ),
+                ),
+                (
+                    "is_global",
+                    models.CharField(
+                        help_text="доступно ли для планирования в цепочке с другими услугами в глобальном сервисе",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "is_visible",
+                    models.CharField(
+                        help_text="доступно ли для хранения в глобальном сервисе/нужна синхронизация данных",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "ticket_status",
+                    models.ForeignKey(
+                        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="tickets.task",
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "servicetype",
+            },
+        ),
+        migrations.CreateModel(
+            name="Service",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "requirements",
+                    models.CharField(
+                        help_text="код необходимого для того, чтобы ресурс мог стать активным",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.",
+                        null=True,
+                    ),
+                ),
+                (
+                    "price_alg",
+                    models.CharField(
+                        help_text="шаблон алгоритма расчета цены для оказываемой услуги",
+                        max_length=100,
+                    ),
+                ),
+                (
+                    "price_km",
+                    models.DecimalField(
+                        decimal_places=2,
+                        help_text="значение параметра стоимости 1км данного поставщика для данного шаблона услуги",
+                        max_digits=9,
+                    ),
+                ),
+                (
+                    "price_min",
+                    models.DecimalField(
+                        decimal_places=2,
+                        help_text="значение параметра стоимости 1мин данного поставщика для данного шаблона услуги",
+                        max_digits=9,
+                    ),
+                ),
+                (
+                    "price_amount",
+                    models.DecimalField(
+                        decimal_places=2,
+                        help_text="значение параметра стоимости 1 услуги данного поставщика для данного шаблона услуги",
+                        max_digits=9,
+                    ),
+                ),
+                (
+                    "service_status",
+                    models.CharField(
+                        help_text="статус спецификации типа услуги", max_length=150
+                    ),
+                ),
+                (
+                    "status",
+                    models.CharField(
+                        help_text="статус обработки заявки в системе заявок",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "is_global",
+                    models.CharField(
+                        help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "is_visible",
+                    models.CharField(
+                        help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "id_provider",
+                    models.ForeignKey(
+                        help_text="идентификатор поставщика услуг",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.provider",
+                    ),
+                ),
+                (
+                    "resource_id",
+                    models.ForeignKey(
+                        help_text="ответственный за ресурс(не всегда)",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.resource",
+                    ),
+                ),
+                (
+                    "servicetype_id",
+                    models.ForeignKey(
+                        help_text="тип оказываемой услуги по классификатору услуг сервиса",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.servicetype",
+                    ),
+                ),
+                (
+                    "ticket_status",
+                    models.ForeignKey(
+                        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="tickets.task",
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "service",
+            },
+        ),
+        migrations.CreateModel(
+            name="Relationship",
             fields=[
                 (
                     "id",
@@ -25,19 +560,312 @@ class Migration(migrations.Migration):
                         verbose_name="ID",
                     ),
                 ),
-                ("check_date", models.DateTimeField()),
-                ("check_level", models.IntegerField()),
-                ("expire_date", models.DateTimeField()),
-                ("id_metaservice", models.BigIntegerField()),
+                ("neg_type", models.IntegerField()),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.",
+                        null=True,
+                    ),
+                ),
                 ("requirements", models.CharField(max_length=150)),
                 ("status", models.CharField(max_length=150)),
+                ("is_global", models.CharField(max_length=1)),
+                ("is_visible", models.CharField(max_length=1)),
+                (
+                    "ticket_status",
+                    models.ForeignKey(
+                        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="tickets.task",
+                    ),
+                ),
+                (
+                    "user_id_who",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        related_name="user_id_who",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+                (
+                    "user_id_whom",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        related_name="user_id_whom",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "relationship",
+            },
+        ),
+        migrations.CreateModel(
+            name="Permissions",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "check_date",
+                    models.DateTimeField(help_text="timestamp проверки", null=True),
+                ),
+                (
+                    "id_permissions",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор определяющий наличие разрешения из множества в словаре - выданных пользователю/клиенту/аккаунту"
+                    ),
+                ),
+                (
+                    "check_level",
+                    models.CharField(
+                        help_text="тип проверки в соответствии с классификатором проверок.",
+                        max_length=10,
+                    ),
+                ),
+                (
+                    "status",
+                    models.CharField(
+                        help_text="статус обработки заявки в системе заявок",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text=" уникальный идентификатор мета-сервиса, необходимый для синхронизации данных."
+                    ),
+                ),
+                (
+                    "is_global",
+                    models.CharField(
+                        help_text="доступна ли информация для хранения в глобальном сервисе/нужна синхронизация",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "is_visible",
+                    models.CharField(
+                        help_text="доступна ли информация о наличии разрешения для планирования в цепочке с другими услугами в глобальном сервисе",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "checked_by",
+                    models.ForeignKey(
+                        help_text="(check-level из классификатора платформы) - информация об уровне проверки. Проверка может быть проведена как платформой, так и мета-сервисом, так и партнером мета-сервиса, а может быть и никем (просто загружен). Указывается, так как достоверность проверки разная. Экзамен, проверенный только на низком уровне, не принимается во внимание как имеющийся до прохождения более высокоуровневой проверки.",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        related_name="checked_by_perm",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+                (
+                    "ticket_status",
+                    models.ForeignKey(
+                        help_text="id заявки, по которой происходит проверка статуса relationship. State меняется только в результате изменений в заявке.",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="tickets.task",
+                    ),
+                ),
+                (
+                    "user_id",
+                    models.ForeignKey(
+                        help_text="уникальный идентификатор пользователя/клиента/аккаунта, которым была пройдена проверка и получено разрешение",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        related_name="user_id_perm",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "permissions",
+            },
+        ),
+        migrations.CreateModel(
+            name="Orders",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("state", models.CharField(max_length=150)),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.",
+                        null=True,
+                    ),
+                ),
+                ("time_created", models.DateTimeField(auto_now_add=True)),
+                ("time_placed", models.DateTimeField()),
+                ("time_start", models.DateTimeField()),
+                ("time_finish_predicted", models.DateTimeField()),
+                ("time_finish_real", models.DateTimeField(null=True)),
+                ("ticket", models.IntegerField()),
+                ("predicted_price", models.FloatField()),
+                ("real_price", models.FloatField()),
+                ("is_global", models.CharField(max_length=1)),
+                ("is_visible", models.CharField(max_length=1)),
+                (
+                    "client_id",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.client",
+                    ),
+                ),
+                (
+                    "provider",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.provider",
+                    ),
+                ),
+                (
+                    "receiver",
+                    models.ForeignKey(
+                        help_text="уникальный идентификатор пользователя (конкретного клиентского аккаунта) являющегося владельцем данного документа",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        related_name="user_id",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+                (
+                    "service",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.service",
+                    ),
+                ),
+                (
+                    "service_type",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.servicetype",
+                    ),
+                ),
+            ],
+            options={
+                "db_table": "orders",
+            },
+        ),
+        migrations.CreateModel(
+            name="Documents",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("check_date", models.DateTimeField(help_text="timestamp проверки")),
+                (
+                    "check_level",
+                    models.IntegerField(
+                        help_text="информация об уровне проверки. Документ может быть проверен как платформой, так и мета-сервисом, так и партнером мета-сервиса, а может быть и никем (просто загружен). Указывается, так как достоверность проверки разная. Документ, проверенный только на низком уровне, не принимается во внимание как имеющийся до прохождения более высокоуровневой проверки. Информацию об уровнях проверки можно посмотреть по словарю Requirements. В данной таблице хранится информация о наиболее высоком уровне проверки."
+                    ),
+                ),
+                (
+                    "expire_date",
+                    models.DateTimeField(
+                        help_text="срок окончания действия документа.", null=True
+                    ),
+                ),
+                (
+                    "id_metaservice",
+                    models.BigIntegerField(
+                        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.",
+                        null=True,
+                    ),
+                ),
+                ("requirements", models.CharField(max_length=150)),
+                (
+                    "status",
+                    models.CharField(
+                        help_text="активность на основе системы заявок", max_length=150
+                    ),
+                ),
+                (
+                    "datalink",
+                    models.TextField(
+                        blank=True,
+                        help_text="адрес фактического размещения на физическом носителе, если информация настолько велика, что не может храниться внутри БД.",
+                    ),
+                ),
+                (
+                    "doc_type",
+                    models.CharField(
+                        help_text="тип документа (паспорт/паспорт 1 страница и т д) в соответствии с классификатором типов документов (см описание в Requirements)",
+                        max_length=150,
+                    ),
+                ),
+                (
+                    "is_global",
+                    models.CharField(
+                        help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "is_visible",
+                    models.CharField(
+                        help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе",
+                        max_length=1,
+                    ),
+                ),
+                (
+                    "checked_by",
+                    models.ForeignKey(
+                        help_text="userid проверившего",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        related_name="checked_by_doc",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+                (
+                    "company_id",
+                    models.ForeignKey(
+                        help_text="идентификатор компании, к которой относится документ, если таковая есть (может не быть)",
+                        null=True,
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        to="metaservicesynced.company",
+                    ),
+                ),
                 (
                     "ticket_status",
                     models.ForeignKey(
+                        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.",
                         on_delete=django.db.models.deletion.DO_NOTHING,
                         to="tickets.task",
                     ),
                 ),
+                (
+                    "user_id",
+                    models.ForeignKey(
+                        help_text="уникальный идентификатор пользователя (конкретного клиентского аккаунта) являющегося владельцем данного документа",
+                        on_delete=django.db.models.deletion.DO_NOTHING,
+                        related_name="user_id_doc",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
             ],
             options={
                 "db_table": "documents",

+ 166 - 27
metaservicesynced/models.py

@@ -3,9 +3,6 @@ from tickets.models import Task
 from SharixAdmin.models import SharixUser
 # Create your models here.
 
-# Валя: Provider, ServiceType, Permissions
-# Виталий: Orders, Client, Relationship
-# Данила: Service, Company, Resource
 
 class Company(models.Model):
     legal_name = models.CharField(max_length=150, help_text="настоящее имя юридического лица")
@@ -18,31 +15,100 @@ class Company(models.Model):
     ks = models.CharField(max_length=50, help_text="Корреспондентский счёт (счёт, открываемый банковской организацией в подразделении самого банка)")
     rs = models.CharField(max_length=50, help_text="Расчетный счет")
     address = models.CharField(max_length=150, help_text="Юридический адрес")
-    requirements = models.CharField(max_length=150, help_text="код необходимого для того, чтобы ресурс мог стать активным")
+    requirements = models.CharField(max_length=150, help_text="код необходимого (самый строгий) для того, чтобы ресурс мог стать активным. Оно вставляется автоматом, в соответствии с профилем метасервиса. Далее, если кому-то из партнеров или пользователей надо строже - применяется более строгий вариант на данную связь.")
     status = models.CharField(max_length=150, help_text="статус обработки заявки в системе заявок")
-    ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.")
-    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.")
-    is_global = models.CharField(max_length=1, help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация")
-    is_visible = models.CharField(max_length=1, help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе")
+    ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, help_text="id заявки, по которой происходит проверка статуса relationship. State меняется только в результате изменений в заявке.")
+    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер.")
+    is_global = models.CharField(max_length=1, help_text="доступно ли для хранения в глобальном сервисе/нужна синхронизация данных")
+    is_visible = models.CharField(max_length=1, help_text="доступно ли для планирования в цепочке с другими услугами в глобальном сервисе")
+
     
     class Meta:
             db_table = "company"
 
+class Permissions(models.Model):
+    """
+    Разрешения - (проверки/экзамены). 
+    По смыслу это что-то вроде “документа на право что-то делать” - на данном этапе это ограничено метасервисом/платформой, 
+    при этом он может быть полностью цифровым (выданным платформой/сервисом).
+    """
+    
+    check_date = models.DateTimeField(null=True, help_text="timestamp проверки")
+    id_permissions = models.BigIntegerField(help_text="уникальный идентификатор определяющий наличие разрешения из множества в словаре - выданных пользователю/клиенту/аккаунту")
+    check_level = models.CharField(max_length=10, help_text="(check-level из классификатора платформы) - информация об уровне проверки. Проверка может быть проведена как платформой, так и мета-сервисом, так и партнером мета-сервиса, а может быть и никем (просто загружен). Указывается, так как достоверность проверки разная. Экзамен, проверенный только на низком уровне, не принимается во внимание как имеющийся до прохождения более высокоуровневой проверки.")
+    checked_by = models.ForeignKey(SharixUser, related_name="checked_by_perm", on_delete=models.DO_NOTHING, null=True, help_text="userid проверившего")
+    user_id = models.ForeignKey(SharixUser, related_name="user_id_perm", on_delete=models.DO_NOTHING, null=True, help_text="уникальный идентификатор пользователя/клиента/аккаунта, которым была пройдена проверка и получено разрешение")
+    status = models.CharField(max_length=150, help_text="статус обработки заявки в системе заявок")
+    ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, null=True, help_text="id заявки, по которой происходит проверка статуса relationship. State меняется только в результате изменений в заявке.")
+    id_metaservice = models.BigIntegerField(help_text=" уникальный идентификатор мета-сервиса, необходимый для синхронизации данных.")
+    is_global = models.CharField(max_length=1, help_text="доступна ли информация для хранения в глобальном сервисе/нужна синхронизация")
+    is_visible = models.CharField(max_length=1, help_text="доступна ли информация о наличии разрешения для планирования в цепочке с другими услугами в глобальном сервисе")
+
+    class Meta:
+        db_table = "permissions"
+
+class ServiceType(models.Model):
+    """
+    Перечень типов услуг
+    """
+
+    codename = models.CharField(max_length=255, help_text="латинское наименование услуги в системе")
+    caption = models.CharField(max_length=255, help_text="наименование услуги для отображения пользователю")
+    description = models.TextField(blank=True, help_text="текстовое описание услуги")
+    requirements = models.CharField(max_length=300, help_text="код требований на основе вспомогательных таблиц-справочников")
+    price_type = models.CharField(max_length=150, help_text="ценообразование - код допустимых вариантов или код параметров, принимаемых во внимание и способ их учета (по сути хорошо закодировать формулу)")
+    status = models.CharField(max_length=150, help_text="активность на основе системы заявок")
+    ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, null=True, help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.")
+    id_metaservice = models.BigIntegerField(help_text=" уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер.")
+    link_agreement = models.CharField(max_length=400, help_text="ссылка на договор в вики об оказании услуги данного типа (аренда, перевозка и тп)")
+    is_global = models.CharField(max_length=1, help_text="доступно ли для планирования в цепочке с другими услугами в глобальном сервисе")
+    is_visible = models.CharField(max_length=1, help_text="доступно ли для хранения в глобальном сервисе/нужна синхронизация данных")
+
+    class Meta:
+        db_table = "servicetype"
+
+class Provider(models.Model):
+    """
+    Provider – единица описания поставщика услуг/ответственного лица за определенный ресурс (например, машину). 
+    По сути - это надстройка к клиентскому аккаунту, иллюстрирующая, что данный пользователь может выступать не только в роли потребителя. 
+    То есть, по тому, какие “провайдеры” находятся по идентификатору пользователя - можно установить конкретный список услуг данного пользователя.
+    """
+
+    type = models.CharField(max_length=150, help_text="тип поставщика (партнер/ответственное лицо/поставщик услуг). Смысл такой - провайдер это статус пользователя, который, в зависимости от применения, может нести разный смысл и подразумевает под собой какой-то тип действия. Обычные исполнители - это провайдеры услуг (код 3). Ответственные за какое-то имущество, которые сдают его в аренду - это тоже провайдеры (код 2). Ответственные за набор услуг перед метасервисом (фактически - назначенные админы) - это провайдеры-партнеры (код 1)")
+    company_id = models.ForeignKey(Company, on_delete=models.DO_NOTHING, null=True, help_text="уникальный идентификатор компании, от лица которой выступает провайдер. Смысл такой - ответственны могут быть только одушевленные лица, компании - не одушевленные. Все услуги предоставляются через компании-партнеры, самозанятые или ИП являются единицами таких компаний.")
+    user_id = models.ForeignKey(SharixUser, on_delete=models.DO_NOTHING, null=True, help_text="уникальный идентификатор конкретного пользователя системы (meta-user), который будет оказывать услугу. Один пользователь может быть провайдером нескольких услуг. Статус провайдера означает, что с данным пользователем может быть установлена связь, как с исполнителем.")
+    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер.")
+    requirements = models.CharField(max_length=300, help_text="требования для того, чтобы можно было предоставлять услуги любые в этом метасервисе в целом (самые строгие)")
+    status = models.CharField(max_length=150, help_text="статус пользователя в системе относительно прохождения проверок (activity_status) (может быть active только в том случае, если ticket, влияющий на статус - закрыт.")
+    ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, null=True, help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.")
+    location_type = models.CharField(max_length=300, help_text="статическая или динамическая локация оказания услуги. Если статическая, а исполнитель находится существенно за пределами локации - то тогда статус автоматом оффлайн для приема новых заявок.")
+    default_location = models.CharField(max_length=300, help_text="локация по умолчанию для объекта.")
+    is_global = models.CharField(max_length=1, help_text="(аккаунт поставщика услуг) – доступен для планирования в цепочке с другими услугами в глобальном сервисе")
+    is_visible = models.CharField(max_length=1, help_text="(аккаунт поставщика услуг) – доступен для хранения в  глобальном сервисе/необходима синхронизация")
+
+    class Meta:
+        db_table = "provider"
+        
+
+
 class Resource(models.Model):
     """
     Resource/Список ресурсов – автомобили/дома/объекты сервиса
     """
-    type_id = models.CharField(max_length=10, help_text="идентификатор ресурса")
-    user_id = models.ForeignKey(SharixUser, on_delete=models.DO_NOTHING, help_text="уникальный идентификатор ответственного")
-    requirements = models.CharField(max_length=150, help_text="код необходимого для того, чтобы ресурс мог стать активным")
-    status = models.CharField(max_length=150, help_text="статус обработки заявки в системе заявок")
+
+    type_id = models.CharField(max_length=10, help_text="определение типа ресурса по его уникальному идентификатору в соответствии с классификатором")
+    user_id = models.ForeignKey(SharixUser, on_delete=models.DO_NOTHING, help_text="уникальный идентификатор ответственного (за состояние, доступность и так далее - то есть для договора) пользователя - идентификатор провайдера, по которому восстанавливается конкретный пользовательский аккаунт")
+    requirements = models.CharField(max_length=150, help_text="код необходимого (самый строгий) для того, чтобы ресурс мог стать активным")
+    status = models.CharField(max_length=150, help_text="статус ресурса в системе относительно прохождения проверок (activity_status) (может быть active только в том случае, если ticket, влияющий на статус - закрыт.")
     ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.")
-    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.")
-    is_global = models.CharField(max_length=1, help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация")
-    is_visible = models.CharField(max_length=1, help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе")
+    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер.")
+    is_global = models.CharField(max_length=1, help_text="доступны ли данные (по услугам или ресурсам?) для хранения в глобальном сервисе/необходима синхронизация")
+    is_visible = models.CharField(max_length=1, help_text="доступно ли для планирования в цепочке с другими услугами в глобальном сервисе")
+
     
     class Meta:
         db_table = "resource"
+
 class Service(models.Model):
     """
     service - спецификация услуги каждого конкретного поставщика 
@@ -50,17 +116,17 @@ class Service(models.Model):
     но конкретный шаблон с конкретным тарифом относится к отдельному перевозчику)
     """
 
-    servicetype_id = models.ForeignKey("ServiceType", on_delete=models.DO_NOTHING, help_text="тип оказываемой услуги по классификатору услуг сервиса")
-    id_provider = models.ForeignKey("Provider",on_delete=models.DO_NOTHING, help_text="идентификатор поставщика услуг")
-    resource_id = models.ForeignKey(Resource, on_delete=models.DO_NOTHING, null=True ,help_text="ответственный за ресурс(не всегда)")
-    requirements = models.CharField(max_length=150, help_text="код необходимого для того, чтобы ресурс мог стать активным")
-    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.")
-    price_alg = models.CharField(max_length=100, help_text="шаблон алгоритма расчета цены для оказываемой услуги")
+    servicetype_id = models.ForeignKey(ServiceType, on_delete=models.DO_NOTHING, help_text="тип оказываемой услуги по классификатору услуг сервиса")
+    id_provider = models.ForeignKey(Provider,on_delete=models.DO_NOTHING, help_text="уникальный идентификатор поставщика услуг (фактически определяет, какой пользователь будет оказывать услугу)")
+    resource_id = models.ForeignKey(Resource, on_delete=models.DO_NOTHING, null=True ,help_text="ответственный за ресурс(не всегда). так как ресурсы сами услугу оказать не могут, а также один ресурс может быть представлен в виде разных услуг, то фактически с точки зрения смысла системы ресурс - это как неодушевленный пользователь. Без провайдера, который с его помощью оказывает услугу - никуда. Поле остается пустым, если сервис не предусматривает использование услуг. Стоит обратить внимание, что это не обязательно ответственный за ресурс. Например, за состояние автомобиля может быть ответственен пользователь (он и указывается в таблице со свойствами ресурса), а услугу доступа или перевозки может оказывать иное лицо.")
+    requirements = models.CharField(max_length=150, help_text="код необходимого (самый строгий) для того, чтобы ресурс мог стать активным. Оно вставляется автоматом, в соответствии с профилем метасервиса. Далее, если кому-то из партнеров или пользователей надо строже - применяется более строгий вариант на данную связь.")
+    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер.")
+    price_alg = models.CharField(max_length=100, help_text="шаблон алгоритма расчета цены для оказываемой услуги (по этой переменной определяется, какую функцию для расчета цены вызывать)")
     price_km = models.DecimalField(max_digits=9, decimal_places=2, help_text="значение параметра стоимости 1км данного поставщика для данного шаблона услуги")
     price_min =  models.DecimalField(max_digits=9, decimal_places=2, help_text="значение параметра стоимости 1мин данного поставщика для данного шаблона услуги")
     price_amount =  models.DecimalField(max_digits=9, decimal_places=2, help_text="значение параметра стоимости 1 услуги данного поставщика для данного шаблона услуги")
-    service_status = models.CharField(max_length=150, help_text="статус спецификации типа услуги")
-    status = models.CharField(max_length=150, help_text="статус обработки заявки в системе заявок")
+    service_status = models.CharField(max_length=150, help_text="статус спецификации типа услуги, принимает значения Online, Offline, Preorder with Gap. Online/offline выставляются по проверке параметров и желанию пользователя (например, если пользователь переключает себя online, но по какой-то причине ему такую услугу оказывать запрещено - оно не переключится, то есть надо перед сменой значения этого поля всегда запускать проверку)")
+    status = models.CharField(max_length=150, help_text="статус обработки заявки в системе заявок. активность на основе системы заяво")
     ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.")
     is_global = models.CharField(max_length=1, help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация")
     is_visible = models.CharField(max_length=1, help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе")
@@ -68,6 +134,7 @@ class Service(models.Model):
     class Meta:
         db_table = "service"
 
+
 class Documents(models.Model):
     """
     Documents - это одна таблица со всеми документами.
@@ -84,13 +151,85 @@ class Documents(models.Model):
     status = models.CharField(max_length=150, help_text="активность на основе системы заявок")
     ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.")
     datalink = models.TextField(blank=True, help_text="адрес фактического размещения на физическом носителе, если информация настолько велика, что не может храниться внутри БД.")
-    doc_type = models.CharField(help_text="тип документа (паспорт/паспорт 1 страница и т д) в соответствии с классификатором типов документов (см описание в Requirements)")
-    user_id = models.ForeignKey(SharixUser, on_delete=models.DO_NOTHING, help_text="уникальный идентификатор пользователя (конкретного клиентского аккаунта) являющегося владельцем данного документа")
-    company_id = models.ForeignKey("Company", on_delete=models.DO_NOTHING, null=True, help_text="идентификатор компании, к которой относится документ, если таковая есть (может не быть)")
+    doc_type = models.CharField(max_length=150, help_text="тип документа (паспорт/паспорт 1 страница и т д) в соответствии с классификатором типов документов (см описание в Requirements)")
+    user_id = models.ForeignKey(SharixUser, related_name="user_id_doc", on_delete=models.DO_NOTHING, help_text="уникальный идентификатор пользователя (конкретного клиентского аккаунта) являющегося владельцем данного документа")
+    company_id = models.ForeignKey(Company, on_delete=models.DO_NOTHING, null=True, help_text="идентификатор компании, к которой относится документ, если таковая есть (может не быть)")
     is_global = models.CharField(max_length=1, help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация")
     is_visible = models.CharField(max_length=1, help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе")
-    checked_by = models.ForeignKey(SharixUser, on_delete=models.DO_NOTHING, null=True, help_text="userid проверившего")
+    checked_by = models.ForeignKey(SharixUser, related_name="checked_by_doc", on_delete=models.DO_NOTHING, null=True, help_text="userid проверившего")
+
 
     class Meta:
         db_table = "documents"
 
+
+class Client(models.Model):
+    """
+    Client - это таблица с клиентами. Клиент/пользователь/аккаунт 
+    в системе, который по логике получает услугу.
+    """
+    user = models.ForeignKey(SharixUser, on_delete=models.DO_NOTHING, help_text="пользователь, которому соответствует роль клиента")
+    requirements = models.CharField(max_length=150, help_text="требования для того, чтобы можно было получать услуги как клиент")
+    status = models.CharField(max_length=150, help_text="активность на основе системы заявок")
+    ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю.")
+    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.")
+    is_global = models.CharField(max_length=1, help_text="доступно ли для хранения в глобальном сервисе/необходима синхронизация")
+    is_visible = models.CharField(max_length=1, help_text="доступно ли для планирования в цепочке с другими услугами в глобальном сервисе")
+
+
+    class Meta:
+        db_table = "client"
+
+
+class Orders(models.Model):
+    """
+    Orders - таблица с заказами
+    """
+
+
+    service = models.ForeignKey(Service, on_delete=models.DO_NOTHING, help_text="спецификатор услуги провайдера, нужен для установления цены (id_service - уникальный идентификатор шаблона услуги, необходим для установления цены и исполнителей.")
+    service_type = models.ForeignKey(ServiceType, on_delete=models.DO_NOTHING, help_text="тип заказа по классификатору услу")
+    state = models.CharField(max_length=150, help_text="текущий статус заказа из возможных на платформе")
+    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false.")
+    provider = models.ForeignKey(Provider, on_delete=models.DO_NOTHING, help_text="уникальный идентификатор поставщика услуги/аккаунта, который оказывает услугу. Если несколько провайдеров собираются мета-сервисом в цепочку, где на уровне связи с клиентом нельзя установить одно ответственное лицо, то указывается вспомогательный мета-провайдер сервиса, и это означает, что мета-сервис несет ответственность перед пользователем за сборку услуги воедино.") 
+    receiver = models.ForeignKey(SharixUser, related_name="user_id", on_delete=models.DO_NOTHING, help_text="пользователь/аккаунт, который принимает оказываемые услуги")
+    client_id = models.ForeignKey(Client, on_delete=models.DO_NOTHING, help_text="клиент/аккаунт, который оплачивает все оказанные услуги") 
+    time_created = models.DateTimeField(auto_now_add=True, help_text="время создания заказа")
+    time_placed = models.DateTimeField(help_text="время размещения заказа")
+    time_start = models.DateTimeField(help_text="время начала оказания услуги")
+    time_finish_predicted = models.DateTimeField(help_text="предварительное/расчетное время до окончания оказания услуги")
+    time_finish_real = models.DateTimeField(null=True, help_text="фактическое время окончания (точное установленное время)")
+    ticket = models.IntegerField(help_text="")
+    predicted_price = models.FloatField(help_text="расчетная цена с учетом тарифа поставщика услуг")
+    real_price = models.FloatField(help_text="цена с учетом тарифа поставщика услуг по факту оказания услуги")
+    is_global = models.CharField(max_length=1, help_text="доступна ли информация по заказу для хранения в глобальном сервисе/нужна синхронизация данных. Если is_global = false, то и is_visible для заказа и вглубь по цепочке для всех исполнителей и ресурсов - тоже false.")
+    is_visible = models.CharField(max_length=1, help_text="доступна ли информация по заказу (время, место) для планирования иных цепочек. Если нет, то все действующие исполнители и ресурсы считаются занятыми на неопределенное время, пока не завершится заказ. Если да - то ресурсы могут использоваться для построения цепочек после планируемого времени завершения, с учетом места.")
+
+
+    class Meta:
+        db_table = "orders"
+
+
+
+
+#hi
+class Relationship(models.Model):
+    """
+    Relationship - описание связей 
+    (желательных - как имеющиеся договорные отношения, 
+    и нежелательных - как пожелание любой из сторон)
+    """
+    user_id_who = models.ForeignKey(SharixUser, related_name="user_id_who", on_delete=models.DO_NOTHING, help_text="уникальный идентификатор инициатора договорных отношений")
+    user_id_whom = models.ForeignKey(SharixUser,  related_name="user_id_whom", on_delete=models.DO_NOTHING, help_text=" уникальный идентификатор того с кем связываются")
+    neg_type = models.IntegerField(help_text="тип договорных отношений по его уникальному идентификатору")
+    id_metaservice = models.BigIntegerField(null=True, help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер.")
+    requirements = models.CharField(max_length=150, help_text="код необходимого (самый строгий) для того, чтобы ресурс мог стать активным. Оно вставляется автоматом, в соответствии с профилем метасервиса. Далее, если кому-то из партнеров или пользователей надо строже - применяется более строгий вариант на данную связь.")
+    status = models.CharField(max_length=150, help_text="(статус обработки заявки в системе заявок)")
+    ticket_status = models.ForeignKey(Task, on_delete=models.DO_NOTHING, help_text="id заявки, по которой происходит проверка статуса relationship. State меняется только в результате изменений в заявке.")
+    is_global = models.CharField(max_length=1, help_text="установленный тип договорных отношений между клиентами/пользователями/аккаунтами доступен для хранения в глобальном сервисе/нужна синхронизация")
+    is_visible = models.CharField(max_length=1, help_text="установленный тип договорных отношений между клиентами/пользователями/аккаунтами, доступен для планирования в цепочке с другими услугами в глобальном сервисе")
+
+
+    class Meta:
+        db_table = "relationship"
+

+ 8 - 0
metaservicesynced/serializer.py

@@ -0,0 +1,8 @@
+from rest_framework import serializers
+from .models import *
+from django.contrib.auth.models import *
+
+class DocumentsSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Documents
+        exclude = ["id"]

+ 12 - 0
metaservicesynced/urls.py

@@ -0,0 +1,12 @@
+from metaservicesynced.apiview import *
+from rest_framework import routers
+from django.urls import path, include
+
+from metaservicesynced.views import *
+
+router = routers.SimpleRouter()
+router.register(r'documents', DocumentsMVS)
+
+urlpatterns = [  
+    path('api/', include(router.urls), name="documents"),
+]

+ 2 - 0
metaservicesynced/views.py

@@ -1,3 +1,5 @@
 from django.shortcuts import render
+from metaservicesynced.models import *
 
 # Create your views here.
+

+ 2 - 1
tickets/.gitignore

@@ -1,4 +1,5 @@
 # Python
 __pycache__/
 *.py[cod]
-*$py.class
+*$py.class
+00*.py

+ 51 - 13
tickets/migrations/0001_initial.py

@@ -1,4 +1,4 @@
-# Generated by Django 4.1.3 on 2023-03-22 09:30
+# Generated by Django 4.1.3 on 2023-03-31 19:43
 
 import datetime
 from django.conf import settings
@@ -30,8 +30,16 @@ class Migration(migrations.Migration):
                         verbose_name="ID",
                     ),
                 ),
-                ("name", models.CharField(max_length=32, unique=True)),
-                ("life_cycle", models.CharField(max_length=192, unique=True)),
+                (
+                    "name",
+                    models.CharField(max_length=32, unique=True, verbose_name="Name"),
+                ),
+                (
+                    "life_cycle",
+                    models.CharField(
+                        max_length=192, unique=True, verbose_name="Life cycle"
+                    ),
+                ),
             ],
         ),
         migrations.CreateModel(
@@ -46,12 +54,14 @@ class Migration(migrations.Migration):
                         verbose_name="ID",
                     ),
                 ),
-                ("name", models.CharField(max_length=48)),
-                ("slug", models.SlugField(default="")),
+                ("name", models.CharField(max_length=48, verbose_name="Name")),
+                ("slug", models.SlugField(default="", verbose_name="Slug")),
                 (
                     "group",
                     models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE, to="auth.group"
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="auth.group",
+                        verbose_name="Group",
                     ),
                 ),
             ],
@@ -157,12 +167,18 @@ class Migration(migrations.Migration):
                         verbose_name="ID",
                     ),
                 ),
-                ("timestamp", models.DateTimeField(default=datetime.datetime.now)),
+                (
+                    "timestamp",
+                    models.DateTimeField(
+                        default=datetime.datetime.now, verbose_name="Timestamp"
+                    ),
+                ),
                 (
                     "file",
                     models.FileField(
                         max_length=255,
                         upload_to=tickets.models.get_attachment_upload_dir,
+                        verbose_name="File",
                     ),
                 ),
                 (
@@ -170,12 +186,15 @@ class Migration(migrations.Migration):
                     models.ForeignKey(
                         on_delete=django.db.models.deletion.CASCADE,
                         to=settings.AUTH_USER_MODEL,
+                        verbose_name="Added by",
                     ),
                 ),
                 (
                     "task",
                     models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE, to="tickets.task"
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="tickets.task",
+                        verbose_name="Task",
                     ),
                 ),
             ],
@@ -192,13 +211,28 @@ class Migration(migrations.Migration):
                         verbose_name="ID",
                     ),
                 ),
-                ("date", models.DateTimeField(default=django.utils.timezone.now)),
-                ("email_from", models.CharField(blank=True, max_length=320, null=True)),
+                (
+                    "date",
+                    models.DateTimeField(
+                        default=django.utils.timezone.now, verbose_name="Date"
+                    ),
+                ),
+                (
+                    "email_from",
+                    models.CharField(
+                        blank=True, max_length=320, null=True, verbose_name="Eamil from"
+                    ),
+                ),
                 (
                     "email_message_id",
-                    models.CharField(blank=True, max_length=255, null=True),
+                    models.CharField(
+                        blank=True,
+                        max_length=255,
+                        null=True,
+                        verbose_name="Eamil message id",
+                    ),
                 ),
-                ("body", models.TextField(blank=True)),
+                ("body", models.TextField(blank=True, verbose_name="Body")),
                 (
                     "author",
                     models.ForeignKey(
@@ -207,16 +241,20 @@ class Migration(migrations.Migration):
                         on_delete=django.db.models.deletion.CASCADE,
                         related_name="tickets_comments",
                         to=settings.AUTH_USER_MODEL,
+                        verbose_name="Author",
                     ),
                 ),
                 (
                     "task",
                     models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE, to="tickets.task"
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="tickets.task",
+                        verbose_name="Task",
                     ),
                 ),
             ],
             options={
+                "verbose_name": "Comment",
                 "unique_together": {("task", "email_message_id")},
             },
         ),

+ 0 - 136
tickets/migrations/0002_alter_comment_options_alter_attachment_added_by_and_more.py

@@ -1,136 +0,0 @@
-# Generated by Django 4.1.3 on 2023-03-28 09:31
-
-import datetime
-from django.conf import settings
-from django.db import migrations, models
-import django.db.models.deletion
-import django.utils.timezone
-import tickets.models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
-        ("auth", "0012_alter_user_first_name_max_length"),
-        ("tickets", "0001_initial"),
-    ]
-
-    operations = [
-        migrations.AlterModelOptions(
-            name="comment",
-            options={"verbose_name": "Comment"},
-        ),
-        migrations.AlterField(
-            model_name="attachment",
-            name="added_by",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                to=settings.AUTH_USER_MODEL,
-                verbose_name="Added by",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="attachment",
-            name="file",
-            field=models.FileField(
-                max_length=255,
-                upload_to=tickets.models.get_attachment_upload_dir,
-                verbose_name="File",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="attachment",
-            name="task",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                to="tickets.task",
-                verbose_name="Task",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="attachment",
-            name="timestamp",
-            field=models.DateTimeField(
-                default=datetime.datetime.now, verbose_name="Timestamp"
-            ),
-        ),
-        migrations.AlterField(
-            model_name="comment",
-            name="author",
-            field=models.ForeignKey(
-                blank=True,
-                null=True,
-                on_delete=django.db.models.deletion.CASCADE,
-                related_name="tickets_comments",
-                to=settings.AUTH_USER_MODEL,
-                verbose_name="Author",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="comment",
-            name="body",
-            field=models.TextField(blank=True, verbose_name="Body"),
-        ),
-        migrations.AlterField(
-            model_name="comment",
-            name="date",
-            field=models.DateTimeField(
-                default=django.utils.timezone.now, verbose_name="Date"
-            ),
-        ),
-        migrations.AlterField(
-            model_name="comment",
-            name="email_from",
-            field=models.CharField(
-                blank=True, max_length=320, null=True, verbose_name="Eamil from"
-            ),
-        ),
-        migrations.AlterField(
-            model_name="comment",
-            name="email_message_id",
-            field=models.CharField(
-                blank=True, max_length=255, null=True, verbose_name="Eamil message id"
-            ),
-        ),
-        migrations.AlterField(
-            model_name="comment",
-            name="task",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                to="tickets.task",
-                verbose_name="Task",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="tasklist",
-            name="group",
-            field=models.ForeignKey(
-                on_delete=django.db.models.deletion.CASCADE,
-                to="auth.group",
-                verbose_name="Group",
-            ),
-        ),
-        migrations.AlterField(
-            model_name="tasklist",
-            name="name",
-            field=models.CharField(max_length=48, verbose_name="Name"),
-        ),
-        migrations.AlterField(
-            model_name="tasklist",
-            name="slug",
-            field=models.SlugField(default="", verbose_name="Slug"),
-        ),
-        migrations.AlterField(
-            model_name="tickettype",
-            name="life_cycle",
-            field=models.CharField(
-                max_length=192, unique=True, verbose_name="Life cycle"
-            ),
-        ),
-        migrations.AlterField(
-            model_name="tickettype",
-            name="name",
-            field=models.CharField(max_length=32, unique=True, verbose_name="Name"),
-        ),
-    ]