Browse Source

Merge branch 'unstable' of blezz-tech/sharix-open-backend into unstable

Панюкова Александра Анатольевна 1 tháng trước cách đây
mục cha
commit
8c56771001
9 tập tin đã thay đổi với 296 bổ sung227 xóa
  1. 21 14
      models/client.py
  2. 39 33
      models/company.py
  3. 28 20
      models/documents.py
  4. 51 43
      models/orders.py
  5. 34 26
      models/permissions.py
  6. 33 23
      models/provider.py
  7. 28 21
      models/relationship.py
  8. 34 27
      models/service.py
  9. 28 20
      models/servicetype.py

+ 21 - 14
models/client.py

@@ -9,11 +9,14 @@ class Client(models.Model):
     Client - это таблица с клиентами. Клиент/пользователь/аккаунт 
     в системе, который по логике получает услугу.
     """
-    user = models.ForeignKey(
-        get_user_model(),
-        on_delete=models.DO_NOTHING,
-        help_text="пользователь, которому соответствует роль клиента"
+
+    # ID METASERVICE
+    id_metaservice = models.BigIntegerField(
+        null=True,
+        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false."
     )
+
+    # DATA
     requirements = models.CharField(
         max_length=150,
         help_text="требования для того, чтобы можно было получать услуги как клиент"
@@ -22,15 +25,8 @@ class Client(models.Model):
         max_length=150,
         help_text="активность на основе системы заявок"
     )
-    ticket_status = models.ForeignKey(
-        Ticket,
-        on_delete=models.DO_NOTHING,
-        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
-    )
-    id_metaservice = models.BigIntegerField(
-        null=True,
-        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false."
-    )
+
+    # OTHER
     is_global = models.BooleanField(
         default=False,
         help_text="доступно ли для хранения в глобальном сервисе/необходима синхронизация"
@@ -40,8 +36,19 @@ class Client(models.Model):
         help_text="доступно ли для планирования в цепочке с другими услугами в глобальном сервисе"
     )
 
+    # FK
+    ticket_status = models.ForeignKey(
+        Ticket,
+        on_delete=models.DO_NOTHING,
+        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
+    )
+    user = models.ForeignKey(
+        get_user_model(),
+        on_delete=models.DO_NOTHING,
+        help_text="пользователь, которому соответствует роль клиента"
+    )
 
     class Meta:
         db_table = "client"
         verbose_name = "Клиента"
-        verbose_name_plural = "Клиенты"
+        verbose_name_plural = "Клиенты"

+ 39 - 33
models/company.py

@@ -5,21 +5,17 @@ from tickets.models import Ticket
 
 
 class Company(models.Model):
-    legal_name = models.CharField(
-        "Название организации",
-        max_length=150,
-        help_text="Настоящее имя юридического лица"
-    )
 
-    # FIXME: Нет уверенности, что после удаления пользователя следует оставлять `models.DO_NOTHING`
-    repr_id =models.ForeignKey(
-        get_user_model(),
-        blank=True,
-        verbose_name="Представитель организации",
-        on_delete=models.DO_NOTHING,
-        help_text="Уникальный идентификатор представителя компании"
+
+
+    # ID METASERVICE
+    # FIXME: id_metaservice должно принимать текущий идентификатор метасервиса, на котором происходит создание записи
+    id_metaservice = models.PositiveBigIntegerField(
+        default=1,
+        help_text="Уникальный идентификатор метасервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких метасервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер."
     )
-    
+
+    # DATA
     requirements = models.CharField(
         "Ограничения",
         max_length=150,
@@ -32,17 +28,15 @@ class Company(models.Model):
         default="deactivated",
         help_text="Cтатус обработки заявки"
     )
-
-    # FIXME: Нет уверенности, что после удаления заявки следует оставлять `models.DO_NOTHING`
-    ticket_status = models.ForeignKey(
-        Ticket,
-        on_delete=models.SET_NULL,
-        blank=True,
-        null=True,
-        help_text="ID заявки, привязанной к текущей записи",
-        verbose_name="Связанный тикет"
+    legal_name = models.CharField(
+        "Название организации",
+        max_length=150,
+        help_text="Настоящее имя юридического лица"
+    )
+    address = models.CharField(
+        "Юридический адрес",
+        max_length=150
     )
-
     inn = models.CharField(
         "ИНН компании",
         max_length=12,
@@ -74,10 +68,9 @@ class Company(models.Model):
         max_length=50,
         help_text="Корреспондентский счет (счет, открываемый банковской организацией в подразделении самого банка)"
     )
-    address = models.CharField(
-        "Юридический адрес",
-        max_length=150
-    )
+    # FIXME: tax_method field not exist 
+
+    # OTHER
     is_global = models.CharField(
         max_length=1,
         default="f",
@@ -88,11 +81,24 @@ class Company(models.Model):
         default="f",
         help_text="Доступно ли для планирования в цепочке с другими услугами в глобальном сервисе"
     )
-    
-    # FIXME: id_metaservice должно принимать текущий идентификатор метасервиса, на котором происходит создание записи
-    id_metaservice = models.PositiveBigIntegerField(
-        default=1,
-        help_text="Уникальный идентификатор метасервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких метасервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер."
+
+    # FK
+    # FIXME: Нет уверенности, что после удаления пользователя следует оставлять `models.DO_NOTHING`
+    repr_id =models.ForeignKey(
+        get_user_model(),
+        blank=True,
+        verbose_name="Представитель организации",
+        on_delete=models.DO_NOTHING,
+        help_text="Уникальный идентификатор представителя компании"
+    )
+    # FIXME: Нет уверенности, что после удаления заявки следует оставлять `models.DO_NOTHING`
+    ticket_status = models.ForeignKey(
+        Ticket,
+        on_delete=models.SET_NULL,
+        blank=True,
+        null=True,
+        help_text="ID заявки, привязанной к текущей записи",
+        verbose_name="Связанный тикет"
     )
 
     def deactivate(self):
@@ -102,4 +108,4 @@ class Company(models.Model):
     class Meta:
         db_table = "company"
         verbose_name = "Компания"
-        verbose_name_plural = "Компании"
+        verbose_name_plural = "Компании"

+ 28 - 20
models/documents.py

@@ -31,12 +31,15 @@ class Documents(models.Model):
         ("99", "Иное"),
     ]
     DOC_TYPES_DICT = dict(DOC_TYPES)
-    
+
+    # ID METASERVICE
     # FIXME: id_metaservice должно принимать текущий идентификатор метасервиса, на котором происходит создание записи
     id_metaservice = models.BigIntegerField(
         default=1,
         help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false."
     )
+
+    # DATA
     check_date = models.DateTimeField(
         auto_now_add=True,
         help_text="timestamp проверки"
@@ -57,37 +60,42 @@ class Documents(models.Model):
         default="deactivated",
         help_text="активность на основе системы заявок"
     )
-    ticket_status = models.ForeignKey(
-        Ticket,
-        null=True,
-        blank=True,
-        on_delete=models.SET_NULL,
-        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
-    )
+    # FIXME: data_path field not exist
     doc_type = models.CharField(
         max_length=2,
         choices=DOC_TYPES,
         help_text="тип документа (паспорт/паспорт 1 страница и т д) в соответствии с классификатором типов документов (см описание в Requirements)"
     )
-    user_id = models.ForeignKey(
-        get_user_model(),
-        related_name="user_id_doc",
-        on_delete=models.DO_NOTHING,
-        help_text="уникальный идентификатор пользователя (конкретного клиентского аккаунта) являющегося владельцем данного документа"
+
+    # OTHER
+    is_global = models.BooleanField(
+        default=False,
+        help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация"
+    )
+    is_visible = models.BooleanField(
+        default=False,
+        help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе"
     )
+
+    # FK
     company_id = models.ForeignKey(
         Company,
         on_delete=models.DO_NOTHING,
         null=True,
         help_text="идентификатор компании, к которой относится документ, если таковая есть (может не быть)"
     )
-    is_global = models.BooleanField(
-        default=False,
-        help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация"
+    user_id = models.ForeignKey(
+        get_user_model(),
+        related_name="user_id_doc",
+        on_delete=models.DO_NOTHING,
+        help_text="уникальный идентификатор пользователя (конкретного клиентского аккаунта) являющегося владельцем данного документа"
     )
-    is_visible = models.BooleanField(
-        default=False,
-        help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе"
+    ticket_status = models.ForeignKey(
+        Ticket,
+        null=True,
+        blank=True,
+        on_delete=models.SET_NULL,
+        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
     )
     checked_by = models.ForeignKey(
         get_user_model(),
@@ -109,4 +117,4 @@ class DocumentFile(models.Model):
     file = models.FileField(upload_to=f'uploads/partners_docs/')
 
     def __str__(self):
-        return os.path.basename(self.file.name)
+        return os.path.basename(self.file.name)

+ 51 - 43
models/orders.py

@@ -12,26 +12,18 @@ class Orders(models.Model):
     """
     Orders - таблица с заказами
     """
-    service = models.ForeignKey(
-        Service,
-        null=True,
-        on_delete=models.DO_NOTHING,
-        help_text="спецификатор услуги провайдера, нужен для установления цены (id_service - уникальный идентификатор шаблона услуги, необходим для установления цены и исполнителей."
-    )
-    service_type = models.ForeignKey(
-        ServiceType,
+
+    # ID METASERVICE
+    id_metaservice = models.BigIntegerField(
         null=True,
-        on_delete=models.DO_NOTHING,
-        help_text="тип заказа по классификатору услу"
+        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false."
     )
+
+    # DATA
     status = models.CharField(
         max_length=150,
         help_text="текущий статус заказа из возможных на платформе"
     )
-    id_metaservice = models.BigIntegerField(
-        null=True,
-        help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Если при синхронизации возникает конфликт (несовместимость) с другим сервисом, предлагается или форсировать изменения везде (если возможно), либо is_global выставляется как false."
-    )
     title = models.CharField(
         max_length=150,
         help_text="заголовок заказа",
@@ -42,25 +34,6 @@ class Orders(models.Model):
         help_text="задание к заказу",
         default = 'Записи'
     )
-    provider = models.ForeignKey(
-        Provider,
-        null=True,
-        on_delete=models.DO_NOTHING,
-        help_text="уникальный идентификатор поставщика услуги/аккаунта, который оказывает услугу. Если несколько провайдеров собираются мета-сервисом в цепочку, где на уровне связи с клиентом нельзя установить одно ответственное лицо, то указывается вспомогательный мета-провайдер сервиса, и это означает, что мета-сервис несет ответственность перед пользователем за сборку услуги воедино."
-    ) 
-    receiver = models.ForeignKey(
-        get_user_model(),
-        null=True,
-        related_name="user_id",
-        on_delete=models.DO_NOTHING,
-        help_text="пользователь/аккаунт, который принимает оказываемые услуги"
-    )
-    client_id = models.ForeignKey(
-        Client,
-        null=True,
-        on_delete=models.DO_NOTHING,
-        help_text="клиент/аккаунт, который оплачивает все оказанные услуги"
-    )
     time_created = models.DateTimeField(
         auto_now_add=True,
         help_text="время создания заказа"
@@ -80,28 +53,25 @@ class Orders(models.Model):
         null=True,
         help_text=""
     )
-    time_finish_predicted = models.DateTimeField(
-        help_text="предварительное/расчетное время до окончания оказания услуги"
-    )
     time_finish_real = models.DateTimeField(
         null=True,
         help_text="фактическое время окончания (точное установленное время)"
     )
-    ticket = models.ForeignKey(
-        Ticket,
-        null=True,
-        on_delete=models.DO_NOTHING
-    )
-    predicted_price = models.FloatField(
-        help_text="расчетная цена с учетом тарифа поставщика услуг"
+    time_finish_predicted = models.DateTimeField(
+        help_text="предварительное/расчетное время до окончания оказания услуги"
     )
     real_price = models.FloatField(
         help_text="цена с учетом тарифа поставщика услуг по факту оказания услуги"
     )
+    predicted_price = models.FloatField(
+        help_text="расчетная цена с учетом тарифа поставщика услуг"
+    )
     asap = models.BooleanField(
         default=False,
         help_text="Срочный ли заказ."
     )
+
+    # OTHER
     is_global = models.BooleanField(
         default=False,
         help_text="доступна ли информация по заказу для хранения в глобальном сервисе/нужна синхронизация данных. Если is_global = false, то и is_visible для заказа и вглубь по цепочке для всех исполнителей и ресурсов - тоже false."
@@ -111,6 +81,44 @@ class Orders(models.Model):
         help_text="доступна ли информация по заказу (время, место) для планирования иных цепочек. Если нет, то все действующие исполнители и ресурсы считаются занятыми на неопределенное время, пока не завершится заказ. Если да - то ресурсы могут использоваться для построения цепочек после планируемого времени завершения, с учетом места."
     )
 
+    # FK
+    ticket = models.ForeignKey(
+        Ticket,
+        null=True,
+        on_delete=models.DO_NOTHING
+    )
+    service = models.ForeignKey(
+        Service,
+        null=True,
+        on_delete=models.DO_NOTHING,
+        help_text="спецификатор услуги провайдера, нужен для установления цены (id_service - уникальный идентификатор шаблона услуги, необходим для установления цены и исполнителей."
+    )
+    service_type = models.ForeignKey(
+        ServiceType,
+        null=True,
+        on_delete=models.DO_NOTHING,
+        help_text="тип заказа по классификатору услу"
+    )
+    client_id = models.ForeignKey(
+        Client,
+        null=True,
+        on_delete=models.DO_NOTHING,
+        help_text="клиент/аккаунт, который оплачивает все оказанные услуги"
+    )
+    provider = models.ForeignKey(
+        Provider,
+        null=True,
+        on_delete=models.DO_NOTHING,
+        help_text="уникальный идентификатор поставщика услуги/аккаунта, который оказывает услугу. Если несколько провайдеров собираются мета-сервисом в цепочку, где на уровне связи с клиентом нельзя установить одно ответственное лицо, то указывается вспомогательный мета-провайдер сервиса, и это означает, что мета-сервис несет ответственность перед пользователем за сборку услуги воедино."
+    )
+    receiver = models.ForeignKey(
+        get_user_model(),
+        null=True,
+        related_name="user_id",
+        on_delete=models.DO_NOTHING,
+        help_text="пользователь/аккаунт, который принимает оказываемые услуги"
+    )
+    # FIXME: company field not found
 
     class Meta:
         db_table = "orders"

+ 34 - 26
models/permissions.py

@@ -8,11 +8,13 @@ class Permissions(models.Model):
     По смыслу это что-то вроде “документа на право что-то делать” - на данном этапе это ограничено метасервисом/платформой, 
     при этом он может быть полностью цифровым (выданным платформой/сервисом).
     """
-    
-    check_date = models.DateTimeField(
-        null=True,
-        help_text="timestamp проверки"
+
+    # ID METASERVICE
+    id_metaservice = models.BigIntegerField(
+        help_text=" уникальный идентификатор мета-сервиса, необходимый для синхронизации данных."
     )
+
+    # DATA
     id_permissions = models.BigIntegerField(
         help_text="уникальный идентификатор определяющий наличие разрешения из множества в словаре - выданных пользователю/клиенту/аккаунту"
     )
@@ -20,33 +22,17 @@ class Permissions(models.Model):
         max_length=10,
         help_text="(check-level из классификатора платформы) - информация об уровне проверки. Проверка может быть проведена как платформой, так и мета-сервисом, так и партнером мета-сервиса, а может быть и никем (просто загружен). Указывается, так как достоверность проверки разная. Экзамен, проверенный только на низком уровне, не принимается во внимание как имеющийся до прохождения более высокоуровневой проверки."
     )
-    checked_by = models.ForeignKey(
-        get_user_model(),
-        related_name="checked_by_perm",
-        on_delete=models.DO_NOTHING,
-        null=True,
-        help_text="userid проверившего"
-    )
-    user_id = models.ForeignKey(
-        get_user_model(),
-        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(
-        Ticket,
-        on_delete=models.DO_NOTHING,
+    check_date = models.DateTimeField(
         null=True,
-        help_text="id заявки, по которой происходит проверка статуса relationship. State меняется только в результате изменений в заявке."
-    )
-    id_metaservice = models.BigIntegerField(
-        help_text=" уникальный идентификатор мета-сервиса, необходимый для синхронизации данных."
+        help_text="timestamp проверки"
     )
+    # FIXME: expire_date filed not exist
+
+    # OTHER
     is_global = models.BooleanField(
         default=False,
         help_text="доступна ли информация для хранения в глобальном сервисе/нужна синхронизация"
@@ -56,7 +42,29 @@ class Permissions(models.Model):
         help_text="доступна ли информация о наличии разрешения для планирования в цепочке с другими услугами в глобальном сервисе"
     )
 
+    # FK
+    ticket_status = models.ForeignKey(
+        Ticket,
+        on_delete=models.DO_NOTHING,
+        null=True,
+        help_text="id заявки, по которой происходит проверка статуса relationship. State меняется только в результате изменений в заявке."
+    )
+    user_id = models.ForeignKey(
+        get_user_model(),
+        related_name="user_id_perm",
+        on_delete=models.DO_NOTHING,
+        null=True,
+        help_text="уникальный идентификатор пользователя/клиента/аккаунта, которым была пройдена проверка и получено разрешение"
+    )
+    checked_by = models.ForeignKey(
+        get_user_model(),
+        related_name="checked_by_perm",
+        on_delete=models.DO_NOTHING,
+        null=True,
+        help_text="userid проверившего"
+    )
+
     class Meta:
         db_table = "permissions"
         verbose_name = "Разрешение"
-        verbose_name_plural = "Разрешения"
+        verbose_name_plural = "Разрешения"

+ 33 - 23
models/provider.py

@@ -11,29 +11,22 @@ class Provider(models.Model):
     По сути - это надстройка к клиентскому аккаунту, иллюстрирующая, что данный пользователь может выступать не только в роли потребителя. 
     То есть, по тому, какие “провайдеры” находятся по идентификатору пользователя - можно установить конкретный список услуг данного пользователя.
     """
+
     id = models.IntegerField(
         primary_key=True
     )
-    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(
-        get_user_model(),
-        on_delete=models.DO_NOTHING,
-        null=True,
-        help_text="уникальный идентификатор конкретного пользователя системы (meta-user), который будет оказывать услугу. Один пользователь может быть провайдером нескольких услуг. Статус провайдера означает, что с данным пользователем может быть установлена связь, как с исполнителем."
-    )
+
+    # ID METASERVICE
     id_metaservice = models.BigIntegerField(
         null=True,
         help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер."
     )
+
+    # DATA
+    type = models.CharField(
+        max_length=150,
+        help_text="тип поставщика (партнер/ответственное лицо/поставщик услуг). Смысл такой - провайдер это статус пользователя, который, в зависимости от применения, может нести разный смысл и подразумевает под собой какой-то тип действия. Обычные исполнители - это провайдеры услуг (код 3). Ответственные за какое-то имущество, которые сдают его в аренду - это тоже провайдеры (код 2). Ответственные за набор услуг перед метасервисом (фактически - назначенные админы) - это провайдеры-партнеры (код 1)"
+    )
     requirements = models.CharField(
         max_length=300,
         help_text="требования для того, чтобы можно было предоставлять услуги любые в этом метасервисе в целом (самые строгие)"
@@ -42,12 +35,6 @@ class Provider(models.Model):
         max_length=150,
         help_text="статус пользователя в системе относительно прохождения проверок (activity_status) (может быть active только в том случае, если ticket, влияющий на статус - закрыт."
     )
-    ticket_status = models.ForeignKey(
-        Ticket,
-        on_delete=models.DO_NOTHING,
-        null=True,
-        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
-    )
     location_type = models.CharField(
         max_length=300,
         help_text="статическая или динамическая локация оказания услуги. Если статическая, а исполнитель находится существенно за пределами локации - то тогда статус автоматом оффлайн для приема новых заявок."
@@ -56,6 +43,8 @@ class Provider(models.Model):
         max_length=300,
         help_text="локация по умолчанию для объекта."
     )
+
+    # OTHER
     is_global = models.BooleanField(
         default=False,
         help_text="(аккаунт поставщика услуг) – доступен для планирования в цепочке с другими услугами в глобальном сервисе"
@@ -65,7 +54,28 @@ class Provider(models.Model):
         help_text="(аккаунт поставщика услуг) – доступен для хранения в  глобальном сервисе/необходима синхронизация"
     )
 
+    # FK
+    user_id = models.ForeignKey(
+        get_user_model(),
+        on_delete=models.DO_NOTHING,
+        null=True,
+        help_text="уникальный идентификатор конкретного пользователя системы (meta-user), который будет оказывать услугу. Один пользователь может быть провайдером нескольких услуг. Статус провайдера означает, что с данным пользователем может быть установлена связь, как с исполнителем."
+    )
+    company_id = models.ForeignKey(
+        Company,
+        on_delete=models.DO_NOTHING,
+        null=True,
+        help_text="уникальный идентификатор компании, от лица которой выступает провайдер. Смысл такой - ответственны могут быть только одушевленные лица, компании - не одушевленные. Все услуги предоставляются через компании-партнеры, самозанятые или ИП являются единицами таких компаний."
+    )
+    ticket_status = models.ForeignKey(
+        Ticket,
+        on_delete=models.DO_NOTHING,
+        null=True,
+        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
+    )
+    # FIXME: service_id filed not exist
+
     class Meta:
         db_table = "provider"
         verbose_name = "Поставщик"
-        verbose_name_plural = "Поставщики"
+        verbose_name_plural = "Поставщики"

+ 28 - 21
models/relationship.py

@@ -10,25 +10,17 @@ class Relationship(models.Model):
     (желательных - как имеющиеся договорные отношения, 
     и нежелательных - как пожелание любой из сторон)
     """
-    user_id_who = models.ForeignKey(
-        get_user_model(),
-        related_name="user_id_who",
-        on_delete=models.DO_NOTHING,
-        help_text="уникальный идентификатор инициатора договорных отношений"
-    )
-    user_id_whom = models.ForeignKey(
-        get_user_model(),
-        related_name="user_id_whom",
-        on_delete=models.DO_NOTHING,
-        help_text=" уникальный идентификатор того с кем связываются"
-    )
-    neg_type = models.IntegerField(
-        help_text="тип договорных отношений по его уникальному идентификатору"
-    )
+
+    # ID METASERVICE
     id_metaservice = models.BigIntegerField(
         null=True,
         help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер."
     )
+
+    # DATA
+    neg_type = models.IntegerField(
+        help_text="тип договорных отношений по его уникальному идентификатору"
+    )
     requirements = models.CharField(
         max_length=150,
         help_text="код необходимого (самый строгий) для того, чтобы ресурс мог стать активным. Оно вставляется автоматом, в соответствии с профилем метасервиса. Далее, если кому-то из партнеров или пользователей надо строже - применяется более строгий вариант на данную связь."
@@ -37,11 +29,8 @@ class Relationship(models.Model):
         max_length=150,
         help_text="(статус обработки заявки в системе заявок)"
     )
-    ticket_status = models.ForeignKey(
-        Ticket,
-        on_delete=models.DO_NOTHING,
-        help_text="id заявки, по которой происходит проверка статуса relationship. State меняется только в результате изменений в заявке."
-    )
+
+    # OTHER
     is_global = models.BooleanField(
         default=False,
         help_text="установленный тип договорных отношений между клиентами/пользователями/аккаунтами доступен для хранения в глобальном сервисе/нужна синхронизация"
@@ -51,8 +40,26 @@ class Relationship(models.Model):
         help_text="установленный тип договорных отношений между клиентами/пользователями/аккаунтами, доступен для планирования в цепочке с другими услугами в глобальном сервисе"
     )
 
+    # FK
+    user_id_who = models.ForeignKey(
+        get_user_model(),
+        related_name="user_id_who",
+        on_delete=models.DO_NOTHING,
+        help_text="уникальный идентификатор инициатора договорных отношений"
+    )
+    user_id_whom = models.ForeignKey(
+        get_user_model(),
+        related_name="user_id_whom",
+        on_delete=models.DO_NOTHING,
+        help_text=" уникальный идентификатор того с кем связываются"
+    )
+    ticket_status = models.ForeignKey(
+        Ticket,
+        on_delete=models.DO_NOTHING,
+        help_text="id заявки, по которой происходит проверка статуса relationship. State меняется только в результате изменений в заявке."
+    )
 
     class Meta:
         db_table = "relationship"
         verbose_name = "Связь (Договорное отношение)"
-        verbose_name_plural = "Связи (Договорные отношения)"
+        verbose_name_plural = "Связи (Договорные отношения)"

+ 34 - 27
models/service.py

@@ -13,31 +13,13 @@ 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,
-        blank=True,
-        null=True,
-        help_text="ответственный за ресурс(не всегда). так как ресурсы сами услугу оказать не могут, а также один ресурс может быть представлен в виде разных услуг, то фактически с точки зрения смысла системы ресурс - это как неодушевленный пользователь. Без провайдера, который с его помощью оказывает услугу - никуда. Поле остается пустым, если сервис не предусматривает использование услуг. Стоит обратить внимание, что это не обязательно ответственный за ресурс. Например, за состояние автомобиля может быть ответственен пользователь (он и указывается в таблице со свойствами ресурса), а услугу доступа или перевозки может оказывать иное лицо."
-    )
-    requirements = models.CharField(
-        max_length=150,
-        help_text="код необходимого (самый строгий) для того, чтобы ресурс мог стать активным. Оно вставляется автоматом, в соответствии с профилем метасервиса. Далее, если кому-то из партнеров или пользователей надо строже - применяется более строгий вариант на данную связь."
-    )
+    # ID METASERVICE
     id_metaservice = models.BigIntegerField(
         null=True,
         help_text="уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер."
     )
+
+    # DATA
     price_alg = models.CharField(
         max_length=100,
         help_text="шаблон алгоритма расчета цены для оказываемой услуги (по этой переменной определяется, какую функцию для расчета цены вызывать)"
@@ -57,6 +39,10 @@ class Service(models.Model):
         decimal_places=2,
         help_text="значение параметра стоимости 1 услуги данного поставщика для данного шаблона услуги"
     )
+    requirements = models.CharField(
+        max_length=150,
+        help_text="код необходимого (самый строгий) для того, чтобы ресурс мог стать активным. Оно вставляется автоматом, в соответствии с профилем метасервиса. Далее, если кому-то из партнеров или пользователей надо строже - применяется более строгий вариант на данную связь."
+    )
     service_status = models.CharField(
         max_length=150,
         help_text="статус спецификации типа услуги, принимает значения Online, Offline, Preorder with Gap. Online/offline выставляются по проверке параметров и желанию пользователя (например, если пользователь переключает себя online, но по какой-то причине ему такую услугу оказывать запрещено - оно не переключится, то есть надо перед сменой значения этого поля всегда запускать проверку)"
@@ -65,11 +51,8 @@ class Service(models.Model):
         max_length=150,
         help_text="статус обработки заявки в системе заявок. активность на основе системы заяво"
     )
-    ticket_status = models.ForeignKey(
-        Ticket,
-        on_delete=models.DO_NOTHING,
-        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
-    )
+
+    # OTHER
     is_global = models.BooleanField(
         default=False,
         help_text="доступны ли документы для хранения в глобальном сервисе/нужна синхронизация"
@@ -78,8 +61,32 @@ class Service(models.Model):
         default=False,
         help_text="доступна ли информация о наличии документов для планирования в цепочке с другими услугами в глобальном сервисе"
     )
+
+    # FK
+    ticket_status = models.ForeignKey(
+        Ticket,
+        on_delete=models.DO_NOTHING,
+        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
+    )
+    resource_id = models.ForeignKey(
+        Resource,
+        on_delete=models.DO_NOTHING,
+        blank=True,
+        null=True,
+        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="уникальный идентификатор поставщика услуг (фактически определяет, какой пользователь будет оказывать услугу)"
+    )
     
     class Meta:
         db_table = "service"
         verbose_name = "Услуга"
-        verbose_name_plural = "Услуги"
+        verbose_name_plural = "Услуги"

+ 28 - 20
models/servicetype.py

@@ -8,43 +8,43 @@ class ServiceType(models.Model):
     Перечень типов услуг
     """
 
+    # ID METASERVICE
+    id_metaservice = models.BigIntegerField(
+        help_text=" уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер."
+    )
+
+    # DATA
     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(
-        Ticket,
-        on_delete=models.DO_NOTHING,
-        null=True,
-        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
+    caption = models.CharField(
+        max_length=255,
+        help_text="наименование услуги для отображения пользователю"
     )
-    id_metaservice = models.BigIntegerField(
-        help_text=" уникальный идентификатор мета-сервиса, необходимый для синхронизации данных. Один и тот же провайдер может быть для нескольких мета-сервисов, соответственно если происходят изменения в одном, то либо форсируется изменение во всех (если возможно), либо снимается is_global. Соответственно при изменении is_global в true должно происходить согласование с остальными копиями в других сервисах. Нужен в том числе для того, чтобы выяснять, в каких еще сервисах есть этот провайдер."
+    description = models.TextField(
+        blank=True,
+        help_text="текстовое описание услуги"
     )
     link_agreement = models.CharField(
         max_length=400,
         help_text="ссылка на договор в вики об оказании услуги данного типа (аренда, перевозка и тп)"
     )
+    price_type = models.CharField(
+        max_length=150,
+        help_text="ценообразование - код допустимых вариантов или код параметров, принимаемых во внимание и способ их учета (по сути хорошо закодировать формулу)"
+    )
+    # FIXME: service_comission field not exist
+
+    # OTHER
     is_global = models.BooleanField(
         default=False,
         help_text="доступно ли для планирования в цепочке с другими услугами в глобальном сервисе"
@@ -54,7 +54,15 @@ class ServiceType(models.Model):
         help_text="доступно ли для хранения в глобальном сервисе/нужна синхронизация данных"
     )
 
+    # FK
+    ticket_status = models.ForeignKey(
+        Ticket,
+        on_delete=models.DO_NOTHING,
+        null=True,
+        help_text="id последнего актуального тикета, касающийся статуса. Если он меняет статус на закрытый - вызывается проверка, которая смотрит, нет ли другого открытого по пользователю."
+    )
+
     class Meta:
         db_table = "servicetype"
         verbose_name = "Тип услуги"
-        verbose_name_plural = "Типы услуг"
+        verbose_name_plural = "Типы услуг"