/*
  Сервис реализует функционал управления выставленными счётами
*/
syntax = "proto3";

import "google/protobuf/timestamp.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "keyapis/invoice/v1/keyapis_invoice_paymethod_v1.proto";
import "google/protobuf/wrappers.proto";

package keyapis.invoice.v1;

option java_package = "ru.keyapis.invoice.v1";
option java_outer_classname = "KeyapisInvoiceV1Proto";
option java_multiple_files = false;
option java_string_check_utf8 = true;
option go_package = "/keyapis_invoice_v1";
option cc_enable_arenas = true;
option csharp_namespace = "Keyapis.Invoice.V1";
option objc_class_prefix = "KEYAPISINVOICEV1";
option php_namespace = "Keyapis\\Invoice\\V1";
option ruby_package = "Keyapis::Invoice::V1";
option optimize_for = LITE_RUNTIME;
// Сервис invoices
service InvoiceService{
  // Метод создания платежа.
  // Создание платежа в своей и внешней платежной системе.
  // Метод доступен для: service
  rpc CreateInvoice(CreateInvoiceRequest) returns(CreateInvoiceResponse) {
    option (google.api.http) = {
      post: "/invoice/api/v1/invoice",
      body: "*"
    };
  }

  // Метод получения платежа.
  // Для master доступно получение платежа только с user_id из токена.
  // Метод доступен для: admin, service, master
  rpc GetInvoice(GetInvoiceRequest) returns (GetInvoiceResponse)
  {
    option (google.api.http) = {
      get: "/invoice/api/v1/invoice/{invoice_id}"
    };
  }

  // Метод подтверждения платежа (вызывается со стороны внешней системы).
  // Не требует авторизации
  rpc PostInvoiceConfirm(PostInvoiceConfirmRequest) returns (PostInvoiceConfirmResponse)
  {
    option (google.api.http) = {
      post: "/invoice/internal/api/v1/invoice/confirm",
      body: "*"
    };
  }
  // Метод получения списка платежей.
  // Для master доступно получение только собственных платежей, если параметр filter.user_id передан и не совпадает с user_id из токена, возвращается ошибка доступа.
  // Метод доступен для: admin, service, master, ltp_first
  rpc GetInvoiceList(GetInvoiceListRequest) returns (GetInvoiceListResponse)
  {
    option (google.api.http) = {
      get: "/invoice/api/v1/invoice/list"
    };
  }

  // Метод получения количества платежей.
  // Для master в параметр filter.user_id подставляется user_id из токена.
  // Метод доступен для: admin, service, master, ltp_first
  rpc GetInvoiceCount(GetInvoiceCountRequest) returns (GetInvoiceCountResponse)
  {
    option (google.api.http) = {
      get: "/invoice/api/v1/invoice/count"
    };
  }
}

// Выставленный счёт
message Invoice {
  // Ошибки внешней системы
  message ExternalError {
    // Запрос к внешней системе вернул ошибку или прекращен по таймауту
    message ExternalSystemError {}
    // Причина
    oneof reason {
      // Запрос к внешней системе вернул ошибку или прекращен по таймауту
      ExternalSystemError external_system_error = 1;
    }
  }
  // Справочник типов статусов оплаты счёта
  enum InvoiceStatusType {
    // Значение не указано
    INVOICE_STATUS_TYPE_UNKNOWN = 0;
    // Создан, ожидает подтверждения
    PLANNED = 1;
    // Ожидает оплаты
    PENDING = 2;
    // Ошибка оплаты
    ERROR = 3;
    // Оплачен
    PAID = 4;
    // Отменен
    CANCELLED = 5;
  }
  // Справочник банковских карт
  enum CardType {
    // Значение не указано
    CARD_TYPE_UNKNOWN = 0;
    // Карта VISA
    VISA = 1;
    // Карта EuroCard/MasterCard
    EC_MC = 2;
    // Карта DinersClub
    DCL = 3;
    // Карта JCB
    JCB = 4;
    // Карта American Express
    AMEX = 5;
    // Платежная система "Мир"
    MIR = 6;
  }
  // Справочник методов платежа
  enum PayInterfaceType {
    // Значение не указано
    PAY_INTERFACE_TYPE_UNKNOWN = 0;
    // Оплата через интерфейс предпроцессинга
    GUI = 1;
    // Оплата с использованием ранее созданного способа платежа, настроенного по умолчанию
    M2M = 2;
  }
  // Справочник типов платежных средств
  enum PaywayType {
    // Значение не указано
    PAYWAY_TYPE_UNKNOWN = 0;
    // Банковская карта
    BANK_CARD = 1;
    // Сервис быстрых платежей
    SBP = 2;
    // Связка Сбербанка
    SBER_PAY = 3;
  }
  // Позиция счета
  message Position {
    // Идентификатор позиции.
    // # Тип: Guid
    string id = 1;
    // Идентификатор платежа.
    // # Тип: Guid
    string invoice_id = 2 [(google.api.field_behavior) = REQUIRED];
    // Название позиции
    string title = 3 [(google.api.field_behavior) = REQUIRED];
    // Категория позиции (='subscription')
    string category = 4 [(google.api.field_behavior) = REQUIRED];
    // Цена в рублях.
    // Число должно быть больше 0
    float amount = 5 [(google.api.field_behavior) = REQUIRED];
    // Дата создания позиции платежа.
    // # Тип: DateTime
    google.protobuf.Timestamp created_at = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
    // Дата обновления позиции платежа.
    // # Тип: DateTime
    google.protobuf.Timestamp updated_at = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
    // Идентификатор МРФ
    int32 mrf_id = 8 [(google.api.field_behavior) = REQUIRED];
    // Идентификатор РФ
    int32 rf_id = 9 [(google.api.field_behavior) = REQUIRED];
    // Идентификатор экземпляра оплачиваемой подписки.
    // # Тип: Guid
    string instance_id = 10 [(google.api.field_behavior) = REQUIRED];
    // Идентификатор предложения оплачиваемой подписки
    int32 offering_id = 11 [(google.api.field_behavior) = REQUIRED];
    // Срок окончания оплачиваемого периода
    google.protobuf.Timestamp due_date_at = 12;
    // Идентификатор получателя платежа
    string svc_type_id = 13;
    // Признак скидки
    bool is_discount = 14;
  }
  // Ошибка сохранения.
  // Эти проверки выполняются при работе с базой данных и сторонними сервисами
  message SavingError {
    // У пользователя уже есть платеж со статусом PENDING
    message InvoiceAlreadyExists {}
    // Причина ошибки
    oneof reason {
      // У пользователя уже есть платеж со статусом PENDING
      InvoiceAlreadyExists invoice_already_exists = 1;
    }
  }
  // Идентификатор платежа.
  // # Тип: Guid
  string id = 1 [(google.api.field_behavior) = REQUIRED];
  // Описание платежа
  string title = 2 [(google.api.field_behavior) = REQUIRED];
  // Идентификатор пользователя
  int32 user_id = 3 [(google.api.field_behavior) = REQUIRED];
  // Статус платежа
  InvoiceStatusType invoice_status_type = 4 [(google.api.field_behavior) = REQUIRED];
  // Дата создания платежа.
  // # Тип: DateTime
  google.protobuf.Timestamp created_at = 5 [(google.api.field_behavior) = REQUIRED];
  // Дата обновления платежа.
  // # Тип: DateTime
  google.protobuf.Timestamp updated_at = 6 [(google.api.field_behavior) = REQUIRED];
  // Позиция счета
  repeated Position positions = 7 [(google.api.field_behavior) = REQUIRED];
  // Метод платежа
  PayInterfaceType pay_interface_type = 8;
  // Способ оплаты
  PaywayType payway_type = 9;
  // Дата изменения статуса платежа.
  // # Тип: DateTime
  google.protobuf.Timestamp status_changed_at = 10;
  // Дата платежа.
  // # Тип: DateTime
  google.protobuf.Timestamp paid_at = 11;
  // Платежная ссылка
  string pay_url = 12;
  // Маскированный номер карты при платеже
  string paid_by_card_masked = 13;
  // Идентификатор платежного средства в внешней системы
  string paid_by_card_espp_id = 14;
  // Тип банковской карты
  CardType card_type = 15;
  // Код ошибки внешней системы
  int32 espp_req_status = 16;
  // Комментарий к статусу платежа из внешней системы
  string espp_req_user_msg = 17;
  // Уникальный номер транзакции в внешней системы
  string espp_invoice_id = 18;
  // Номер телефона
  string phone_number = 19;
  // Электронная почта
  string email = 20;
}

// Фильтр инвойсов
message InvoiceFilter {
  // Идентификатор пользователя
  int32 user_id = 1;
  // Статус платежа
  Invoice.InvoiceStatusType invoice_status_type = 2;
}

// Постраничный вывод
message InvoicePaging {
  // Справочник типов значений сортировки.
  // # Тип: byte
  enum OrderByType {
    // Значение не указано
    ORDER_BY_TYPE_UNKNOWN = 0;
    // По идентификатору
    ID = 1;
    // По дате оплаты
    PAID_AT = 2;
    // По дате создания
    CREATED_AT = 3;
  }
  // Тип значения сортировки.
  // Если значение не передано, то будет взято значение по умолчанию.
  // # По умолчанию: PAID_AT
  OrderByType order_by_type = 1;
  // Справочник типов направлений сортировки.
  // # Тип: byte
  enum DirectionType {
    // Значение не указано
    DIRECTION_TYPE_UNKNOWN = 0;
    // От большего к меньшему
    DESC = 1;
    // От меньшего к большему
    ASC = 2;
  }
  // Тип направления сортировки.
  // # По умолчанию: DESC
  DirectionType direction_type = 2;
  // Количество записей на страницу.
  // Если значение 0 (не передано), то будет взято значение по умолчанию.
  // # Диапазон: 0..100.
  // # По умолчанию: 20
  int32 limit = 3;
  // Сдвиг.
  // # Диапазон: 0..2147483647
  int32 offset = 4;
}



// Запрос на создание платежа
message CreateInvoiceRequest {
  // Идентификатор пользователя
  int32 user_id = 1 [(google.api.field_behavior) = REQUIRED];
  // Позиция счета
  repeated Invoice.Position positions = 2 [(google.api.field_behavior) = REQUIRED];
  // Метод платежа
  Invoice.PayInterfaceType pay_interface_type = 3 [(google.api.field_behavior) = REQUIRED];
  // Способ оплаты.
  // По умолчанию: BANK_CARD
  Invoice.PaywayType payway_type = 4;
  // Ссылка для перехода после оплаты.
  // Если не передан подставится значение по умолчанию
  string return_url = 5;
  // Номер телефона.
  // Должно быть означено поле phone_number, либо поле email
  string phone_number = 6;
  // Электронная почта.
  // Должно быть означено поле phone_number, либо поле email
  string email = 7;
  // Описание платежа.
  // По умолчанию подставляется "Счёт от {DD.MM.YYYY}г."
  string title = 8;
}

// Ответ на запрос создание платежа
message CreateInvoiceResponse {
  // Ошибка запроса
  message Error {
    // Должно быть означено поле phone_number, либо поле email
    message MissingUserContacts {}
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
      // Должно быть означено поле phone_number, либо поле email
      MissingUserContacts missing_user_contacts= 2;
      // Ошибки внешней системы
      Invoice.ExternalError external = 3;
      // Ошибка сохранения
      Invoice.SavingError saving = 4;
    }
  }
  // Тип ответа
  oneof type {
    // Ошибка валидации
    Error error = 1;
    // Платеж
    Invoice data = 2;
  }
}

// Запрос на получение статуса платежа
message GetInvoiceRequest {
  // Идентификатор платежа в Ключе.
  // # Тип: Guid
  string invoice_id = 1 [(google.api.field_behavior) = REQUIRED];
}


// Ответ на запрос получения платежа
message GetInvoiceResponse {
  // Ошибка запроса
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
    }
  }
  // Тип ответа
  oneof type {
    // Ошибка
    Error error = 1;
    // Платеж
    Invoice data = 2;
  }
}

// Запрос на подтверждение платежа
message PostInvoiceConfirmRequest {
  // Структура с информацией о карте плательщика
  message Card {
    // Идентификатор платежного средства во внешней системы.
    // Возвращается в случае успешной привязки БК к УЗ
    int32 espp_card_id = 1;
    // Номер платежного средства.
    // Маскированный номер карты. Например: 123456******7890
    string card_num = 2;
    // Тип банковской карты
    string card_kind = 3 [json_name = "cardType"];
    // Банк-эмитент.
    // Наименование банка-эмитента. Процессинг может вернуть значение "НЕ ЗАДАВАЛСЯ".
    // В этом случае рекомендуется не отображать эту информацию для пользователя
    string bank_name = 4;
  }
  // Идентификатор платежа в Ключе
  string src_pay_id = 1 [(google.api.field_behavior) = REQUIRED];
  // Идентификатор платежа во внешней системе
  string espp_pay_id = 2 [(google.api.field_behavior) = REQUIRED];
  // Статус платежа из внешней системы
  int32 pay_status = 3 [(google.api.field_behavior) = REQUIRED];
  // Тип запроса.
  // Должно иметь значение "confirmPayment"
  string req_type = 4 [(google.api.field_behavior) = REQUIRED];
  // Сумма платежа в минимальных единицах валюты
  float amount = 5;
  // Код валюты платежа
  string currency = 6;
  // Код способа оплаты
  string pay_method = 7;
  // Дата регистрации платежа.
  // # Тип: DateTime
  google.protobuf.Timestamp create_time_at = 8 [json_name = "createTime"];
  // Комментарий или сообщение об ошибке
  string req_note = 9;
  // Сообщение, отображаемое пользователю
  string req_user_msg = 10;
  // Время фактической оплаты. Время фактической оплаты на стороне Процессинга. Возвращается, если оплата состоялась
  google.protobuf.Timestamp pay_time_at = 11 [json_name = "payTime"];
  // Время фактической отмены оплаты.
  // Время фактической отмены оплаты на стороне Процессинга.
  // Возвращается, если отмена оплаты состоялась
  google.protobuf.Timestamp abandon_time_at = 12 [json_name = "abandonTime"];
  // Структура с информацией о карте плательщика.
  // Передаётся только при успешном платеже и если указаны способы оплаты payMethod = StoredBankCard либо BankCard
  Card card = 13;
}

// Ответ на запрос подтверждения платежа
message PostInvoiceConfirmResponse {
}

// Запрос на получение списка платежей
message GetInvoiceListRequest {
  // Фильтр
  InvoiceFilter filter = 1;
  // Вариант разбиения на страницы
  oneof pagination {
    // Пагинация
    InvoicePaging paging = 2;
  }
}

// Ответ на запрос получения списка платежей
message GetInvoiceListResponse {
  // Ошибка запроса на получение списка платежей
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      ValidationError validation = 1;
    }
  }
  // Платежи
  repeated Invoice data = 1;
  // Ошибка
  Error error = 2;
}

// Запрос на получение количества платежей
message GetInvoiceCountRequest {
  // Фильтр
  InvoiceFilter filter = 1[(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос получения количества платежей
message GetInvoiceCountResponse {
  // Тип результата
  oneof type {
    // Количество
    int32 data = 1;
  }
}

