Перейти к содержанию

Types (Модели)

Сущности

ClientType

Список типов клиентов

Attributes:

Name Type Description
individual str

Для доходов от физических лиц из РФ

legal str

Для доходов от лиц или компаний из других стран

foreign str

Для доходов от ИП или компаний из РФ

Source code in npdtools/types/entity.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class ClientType(StrEnum):
    """
    Список типов клиентов

    Attributes:
        individual: Для доходов от физических лиц из РФ
        legal: Для доходов от лиц или компаний из других стран
        foreign: Для доходов от ИП или компаний из РФ
    """

    individual: str = "FROM_INDIVIDUAL"
    legal: str = "FROM_LEGAL_ENTITY"
    foreign: str = "FROM_FOREIGN_AGENCY"

PartnerInfo

Сведения о партнёре

Attributes:

Name Type Description
code str | None

Код партнёра, обычно uuid

logo str | None

base64 png-логотип

inn str | None

ИНН партнёра

name str | None

Краткое (красивое) название партнёра

Source code in npdtools/types/entity.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class PartnerInfo(BaseModel):
    """
    Сведения о партнёре

    Attributes:
        code: Код партнёра, обычно uuid
        logo: base64 png-логотип
        inn: ИНН партнёра
        name: Краткое (красивое) название партнёра
    """

    code: str | None = None
    logo: str | None = None
    inn: str | None = None
    name: str | None = None

ClientInfo

Сведения о клиенте

Attributes:

Name Type Description
inn str | None

ИНН клиента. Для физлиц и иностранных компаний по желанию. Для российских обязательно

name str | None

ФИО или название компании сокращённо (например, ИП вместо Индивидуальный предприниматель)

type ClientType

Тип клиента из ClientType

phone str | None

Контактный номер по желанию

email str | None

Контактный email по желанию. Туда может приходить чек. Но не всегда

Source code in npdtools/types/entity.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class ClientInfo(BaseModel):
    """
    Сведения о клиенте

    Attributes:
        inn: ИНН клиента. Для физлиц и иностранных компаний по желанию. Для российских обязательно
        name: ФИО или название компании сокращённо (например, ``ИП`` вместо ``Индивидуальный предприниматель``)
        type: Тип клиента из ClientType
        phone: Контактный номер по желанию
        email: Контактный email по желанию. Туда может приходить чек. Но не всегда
    """

    inn: str | None = None
    name: str | None = None
    type: ClientType = ClientType.individual
    phone: str | None = None
    email: str | None = None

    def fns_export(self) -> dict[str, Any]:
        """
        Экспортирует модель в json'подобный словарь

        Returns:
            Словарь в нужном ФНС формате
        """
        return {
            "incomeType": str(self.type.value),
            "inn": self.inn,
            "displayName": self.name,
            "contactPhone": self.phone,
        }

fns_export()

Экспортирует модель в json'подобный словарь

Returns:

Type Description
dict[str, Any]

Словарь в нужном ФНС формате

Source code in npdtools/types/entity.py
57
58
59
60
61
62
63
64
65
66
67
68
69
def fns_export(self) -> dict[str, Any]:
    """
    Экспортирует модель в json'подобный словарь

    Returns:
        Словарь в нужном ФНС формате
    """
    return {
        "incomeType": str(self.type.value),
        "inn": self.inn,
        "displayName": self.name,
        "contactPhone": self.phone,
    }

EmployeeInfo

Сведения о самозанятом

Редактор чека

Отображение всех полей, кроме inn, настраивается в редакторе чека.

Содержимое profession и description можно отредактировать. Содержимое email и phone изменяется только через их смену в профиле.

Применяется только к вновь создаваемым чекам.

Attributes:

Name Type Description
inn str

ИНН самозанятого

profession str | None

Строка, описывающая деятельность самозанятого

description list[dict[str, Any]] | None

Список дополнительного описания деятельности

email str | None

Адрес электронной почты

phone str | None

Номер телефона

Source code in npdtools/types/entity.py
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
class EmployeeInfo(BaseModel):
    """
    Сведения о самозанятом

    Notes: Редактор чека
        Отображение всех полей, кроме ``inn``, настраивается в [редакторе чека](https://lknpd.nalog.ru/settings/checks-editor).

        Содержимое ``profession`` и ``description`` можно отредактировать.
        Содержимое ``email`` и ``phone`` изменяется только через их смену в профиле.

        **Применяется только к вновь создаваемым чекам.**

    Attributes:
        inn: ИНН самозанятого
        profession: Строка, описывающая деятельность самозанятого
        description: Список дополнительного описания деятельности
        email: Адрес электронной почты
        phone: Номер телефона
    """

    inn: str
    profession: str | None = None
    description: list[dict[str, Any]] | None = None
    email: str | None = None
    phone: str | None = None

    @field_validator("profession", mode="before")
    @classmethod
    def profession_normalization(cls, value: str | None):
        if value is None or value == "":
            return None

        return value

Income (Доходы / Чеки)

PaymentTypes

Bases: enum.StrEnum

Attributes:

Name Type Description
cash str

Наличными

phone str

По номеру телефона

account str

По реквизитам счёта

Source code in npdtools/types/income.py
14
15
16
17
18
19
20
21
22
23
24
class PaymentTypes(enum.StrEnum):
    """
    Attributes:
        cash: Наличными
        phone: По номеру телефона
        account: По реквизитам счёта
    """

    cash: str = "CASH"
    phone: str = "PHONE"
    account: str = "ACCOUNT"

SortTypes

Bases: enum.StrEnum

Attributes:

Name Type Description
time str

Сортировка по времени

amount str

Сортировка по полной стоимости

Source code in npdtools/types/income.py
27
28
29
30
31
32
33
34
35
class SortTypes(enum.StrEnum):
    """
    Attributes:
        time: Сортировка по времени
        amount: Сортировка по полной стоимости
    """

    time: str = "operation_time"
    amount: str = "total_amount"

NewIncome

Bases: BaseModel

Attributes:

Name Type Description
receipt_id str

Номер чека

Source code in npdtools/types/income.py
38
39
40
41
42
43
44
class NewIncome(BaseModel):
    """
    Attributes:
        receipt_id: Номер чека
    """

    receipt_id: str = Field(..., alias="approvedReceiptUuid")

CancellationInfo

Bases: BaseModel

Сведения об аннулировании дохода

Attributes:

Name Type Description
canceled_at datetime

Время фактического возврата денег

registered_at datetime

Время регистрации аннулирования

comment str | None

Комментарий к аннулированию

tax_period int | None

Налоговый период в формате YYYYMM

raw dict[str, Any]

JSON'подобный словарь, содержащий необработанный ответ ФНС

Source code in npdtools/types/income.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class CancellationInfo(BaseModel):
    """
    Сведения об аннулировании дохода

    Attributes:
        canceled_at: Время фактического возврата денег
        registered_at: Время регистрации аннулирования
        comment: Комментарий к аннулированию
        tax_period: Налоговый период в формате ``YYYYMM``
        raw: JSON'подобный словарь, содержащий необработанный ответ ФНС
    """

    canceled_at: datetime = Field(..., alias="operationTime")
    registered_at: datetime = Field(..., alias="registerTime")
    comment: str | None = None
    tax_period: int | None = Field(None, alias="taxPeriodId")
    raw: dict[str, Any]

    @model_validator(mode="before")
    @classmethod
    def normalize(cls, values: dict[str, Any]) -> dict[str, Any]:
        values["raw"] = values.copy()

        return values

CanceledIncome

Bases: BaseModel

Сведения об аннулированном чеке

Attributes:

Name Type Description
receipt_id str

Номер чека

name str

Название чека

created_at datetime

Время фактической декларации дохода

received_at datetime

Время получения денег

payment_type PaymentTypes

Вид получения денег. Всегда CASH. Хз, когда не CASH

partner_code Any | None

Код партнёра, если это он регистрировал чек

total_amount Decimal

Общая сумма дохода, за все позиции

cancellation_info CancellationInfo

Сведения об аннулировании

device_id str | None

Идентификатор устройства, с которого был зарегистрирован чек

Source code in npdtools/types/income.py
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
class CanceledIncome(BaseModel):
    """
    Сведения об аннулированном чеке

    Attributes:
        receipt_id: Номер чека
        name: Название чека
        created_at: Время фактической декларации дохода
        received_at: Время получения денег
        payment_type: Вид получения денег. Всегда ``CASH``. Хз, когда не ``CASH``
        partner_code: Код партнёра, если это он регистрировал чек
        total_amount: Общая сумма дохода, за все позиции
        cancellation_info: Сведения об аннулировании
        device_id: Идентификатор устройства, с которого был зарегистрирован чек

    """

    receipt_id: str = Field(..., alias="approvedReceiptUuid")
    name: str
    created_at: datetime = Field(..., alias="requestTime")
    received_at: datetime = Field(..., alias="operationTime")
    payment_type: PaymentTypes = Field(..., alias="paymentType")
    partner_code: Any | None = Field(None, alias="partnerCode")
    total_amount: Decimal = Field(..., alias="totalAmount")
    cancellation_info: CancellationInfo = Field(..., alias="cancellationInfo")
    device_id: str | None = Field(None, alias="sourceDeviceId")

    @property
    def is_cancelled(self) -> bool:
        """
        Returns:
            bool: Является ли чек отменённым? Ну типа да, всегда, но не всегда
        """
        return self.cancellation_info is not None

    @field_validator("total_amount", mode="before")
    @classmethod
    def amount_normalizer(cls, value) -> Decimal:
        return amount_to_decimal(value)

is_cancelled: bool property

Returns:

Name Type Description
bool bool

Является ли чек отменённым? Ну типа да, всегда, но не всегда

IncomeInfo

Bases: BaseModel

Сведения о задекларированном доходе.

Attributes:

Name Type Description
receipt_id str

Номер чека

total_amount Decimal

Общая сумма дохода, за все позиции

services list[Service]

Список позиций в чеке

name str

Название чека

tax_period int | None

Налоговый период в формате YYYYMM

cancellation_info CancellationInfo | None

Сведения об аннулировании

payment_type PaymentTypes

Вид получения денег. Всегда CASH. Хз, когда не CASH

created_at datetime

Время фактической декларации дохода

received_at datetime

Время получения денег

device_id str | None

Идентификатор устройства, с которого был зарегистрирован чек

partner_info PartnerInfo | None

Сведения о партнёре

client_info ClientInfo

Сведения о клиенте

employee_info EmployeeInfo

Сведения о самозанятом

invoice_id int | None

Номер связанного с доходом счёта

raw dict[str, Any]

JSON'подобный словарь, содержащий необработанный ответ ФНС

Source code in npdtools/types/income.py
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
class IncomeInfo(BaseModel):
    """
    Сведения о задекларированном доходе.

    Attributes:
        receipt_id: Номер чека
        total_amount: Общая сумма дохода, за все позиции
        services: Список позиций в чеке
        name: Название чека
        tax_period: Налоговый период в формате ``YYYYMM``
        cancellation_info: Сведения об аннулировании
        payment_type: Вид получения денег. Всегда ``CASH``. Хз, когда не ``CASH``
        created_at: Время фактической декларации дохода
        received_at: Время получения денег
        device_id: Идентификатор устройства, с которого был зарегистрирован чек
        partner_info: Сведения о партнёре
        client_info: Сведения о клиенте
        employee_info: Сведения о самозанятом
        invoice_id: Номер связанного с доходом счёта
        raw: JSON'подобный словарь, содержащий необработанный ответ ФНС
    """

    receipt_id: str = Field(..., alias="approvedReceiptUuid")
    total_amount: Decimal = Field(..., alias="totalAmount")
    services: list[Service]

    name: str
    tax_period: int | None = Field(None, alias="taxPeriodId")
    cancellation_info: CancellationInfo | None = Field(None, alias="cancellationInfo")
    payment_type: PaymentTypes = Field(..., alias="paymentType")

    created_at: datetime = Field(..., alias="requestTime")
    registered_at: datetime = Field(..., alias="registerTime")
    received_at: datetime = Field(..., alias="operationTime")

    device_id: str | None = Field(None, alias="sourceDeviceId")

    partner_info: PartnerInfo | None = None
    client_info: ClientInfo
    employee_info: EmployeeInfo

    invoice_id: int | None = Field(None, alias="invoiceId")

    raw: dict[str, Any]

    @model_validator(mode="before")
    @classmethod
    def model_normalize(cls, values: dict[str, Any]) -> dict[str, Any]:
        values["raw"] = values.copy()

        partner_info: PartnerInfo = PartnerInfo(
            code=values.get("partnerCode", None),
            logo=values.get("partnerLogo", None),
            inn=values.get("partnerInn", None),
            name=values.get("partnerDisplayName", None),
        )

        if partner_info.inn is None:
            partner_info: None = None

        client_info: ClientInfo = ClientInfo(
            inn=values.get("clientInn", None),
            name=values.get("clientDisplayName", None),
            type=values.get("incomeType", ClientType.individual),
            phone=values.get("clientContactPhone", None),
        )
        employee_info: EmployeeInfo = EmployeeInfo(
            inn=values.get("inn", None),
            profession=values.get("profession", None),
            description=values.get("description", None),
            email=values.get("email", None),
            phone=values.get("phone", None),
        )

        values["employee_info"] = employee_info
        values["client_info"] = client_info
        values["partner_info"] = partner_info

        return values

    @property
    def receipt_url(self) -> str:
        """
        Returns:
            str: Ссылка на картинку чека
        """
        return (
            f"{LKNPD_API_V1}/receipt/{self.employee_info.inn}/{self.receipt_id}/print"
        )

    @property
    def receipt_url_json(self) -> str:
        """

        Returns:
            str: Ссылка на JSON со сведениями о чеке
        """
        return f"{LKNPD_API_V1}/receipt/{self.employee_info.inn}/{self.receipt_id}/json"

receipt_url: str property

Returns:

Name Type Description
str str

Ссылка на картинку чека

receipt_url_json: str property

Returns:

Name Type Description
str str

Ссылка на JSON со сведениями о чеке

IncomesList

Bases: BaseModel

Содержит сведения о чеках и пагинации

Attributes:

Name Type Description
incomes list[IncomeInfo]

Список чеков

has_more bool

Есть ли ещё счета для получения

offset int

Отступ от начала

limit int

Количество в выдаче

Source code in npdtools/types/income.py
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
class IncomesList(BaseModel):
    """
    Содержит сведения о чеках и пагинации

    Attributes:
        incomes: Список чеков
        has_more: Есть ли ещё счета для получения
        offset: Отступ от начала
        limit: Количество в выдаче
    """

    incomes: list[IncomeInfo] = Field(..., alias="content")
    has_more: bool = Field(..., alias="hasMore")
    offset: int = Field(..., alias="currentOffset")
    limit: int = Field(..., alias="currentLimit")

    def __iter__(self) -> Iterable[IncomeInfo]:
        return iter(self.incomes)

    def __getitem__(self, item) -> IncomeInfo:
        return self.incomes[item]

Invoice (Счета)

PaymentOption

Bases: BaseModel

Объект со способом приёма денег по счёту

Attributes:

Name Type Description
id int

Идентификатор способа оплаты

type Literal['ACCOUNT', 'PHONE']

Тип: по телефону или по номер счёта

bank BankAccount | BankPhone

Собственно, сами сведения о способе приёма

is_favorite bool

Является ли способ приоритетным. Может быть один на каждый PaymentOption.type

is_for_pa bool

Хз, зачем и что такое

raw dict[str, Any]

JSON'подобный словарь, содержащий необработанный ответ ФНС

Source code in npdtools/types/invoice.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class PaymentOption(BaseModel):
    """
    Объект со способом приёма денег по счёту

    Attributes:
        id: Идентификатор способа оплаты
        type: Тип: по телефону или по номер счёта
        bank: Собственно, сами сведения о способе приёма
        is_favorite: Является ли способ приоритетным. Может быть один на каждый ``PaymentOption.type``
        is_for_pa: Хз, зачем и что такое
        raw: JSON'подобный словарь, содержащий необработанный ответ ФНС
    """

    id: int
    type: Literal["ACCOUNT", "PHONE"]
    bank: BankAccount | BankPhone
    is_favorite: bool = Field(..., alias="favorite")
    is_for_pa: bool = Field(..., alias="availableForPa")  # Хз, зачем это
    raw: dict[str, Any]

    @model_validator(mode="before")
    @classmethod
    def normalize(cls, values: dict[str, Any]) -> dict[str, Any]:
        values["raw"] = values.copy()
        bank = {}

        if values.get("type") == "PHONE":
            bank = BankPhone(
                id=values.get("bankId"),
                name=values.get("bankName"),
                phone=values.get("phone"),
            )
        elif values.get("type") == "ACCOUNT":
            bank = BankAccount(
                name=values.get("bankName"),
                bik=values.get("bankBik"),
                account=values.get("currentAccount"),
                corr=values.get("corrAccount"),
            )

        values["bank"] = bank

        return values

PaymentOptions

Bases: BaseModel

Итерируемый список способов получения денег по счёту

Attributes:

Name Type Description
options list[PaymentOption]

Сам список хранится в этой переменной, но работать можно и с самим объектом сразу

Source code in npdtools/types/invoice.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class PaymentOptions(BaseModel):
    """
    Итерируемый список способов получения денег по счёту

    Attributes:
        options: Сам список хранится в этой переменной, но работать можно и с самим объектом сразу
    """

    options: list[PaymentOption] = Field(..., alias="items")

    def __iter__(self):
        return iter(self.options)

    def __getitem__(self, item) -> PaymentOption:
        return self.options[item]

    def __len__(self) -> int:
        return len(self.options)

ReceiptTemplate

Bases: BaseModel

Настройки чека

Редактор чека

Отображение всех полей настраивается в редакторе чека.

Содержимое profession и description можно отредактировать. Содержимое email и phone изменяется только через их смену в профиле.

Применяется только к вновь создаваемым счетам.

Attributes:

Name Type Description
profession str | None

Строка, описывающая деятельность самозанятого

description list[dict[str, Any]] | None

Список дополнительного описания деятельности

email str | None

Адрес электронной почты

phone str | None

Номер телефона

Source code in npdtools/types/invoice.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
class ReceiptTemplate(BaseModel):
    """
    Настройки чека

    Notes: Редактор чека
        Отображение всех полей настраивается в [редакторе чека](https://lknpd.nalog.ru/settings/checks-editor).

        Содержимое ``profession`` и ``description`` можно отредактировать.
        Содержимое ``email`` и ``phone`` изменяется только через их смену в профиле.

        **Применяется только к вновь создаваемым счетам.**

    Attributes:
        profession: Строка, описывающая деятельность самозанятого
        description: Список дополнительного описания деятельности
        email: Адрес электронной почты
        phone: Номер телефона

    """

    profession: str | None = None
    phone: str | None = None
    email: str | None = None
    description: list[dict[str, Any]] | None = Field(None)

Invoice

Bases: BaseModel

Attributes:

Name Type Description
invoice_id int

Номер счёта

receipt_id str | None

Номер чека, выданного к этому счёту, если, конечно, выдан

services list[Service]

Список позиций в чеке

url str

Ссылка на страницу со счётом. Можно отправить контрагенту

status Literal['CREATED', 'CANCELLED', 'PAID_WITHOUT_RECEIPT', 'PAID_WITH_RECEIPT'] | str

Статус счёта

payment_type PaymentTypes

Способ получения денег

total_amount Decimal

Общая сумма всех позиций в счёте

total_tax Decimal

Сумма налогов за этот счёт

commission Decimal | None

Комиссия за получение денег. Сейчас её нет или она равна нулю

created_at datetime

Время создания счёта

paid_at datetime | None

Время оплаты счёта

canceled_at datetime | None

Время отмены счёта

bank BankAccount | BankPhone

Сведения о способе получения денег по счёту

client_info ClientInfo

Сведения о клиенте

employee_info EmployeeInfo

Сведения о самозанятом

acquiring_info AcquiringInfo

Сведения об эквайринге, если для получения используется он (TODO: Возможно, надо перенести в bank_info)

receipt_template ReceiptTemplate | None

Сведения о самозанятом для отображения в счёте и чеке

type Literal['MANUAL']

Способ создания счёта, обычно MANUAL

auto_create_receipt bool | None

Был ли счёт создан автоматически

uuid str

Технический идентификатор счёта в ФНС

fid int

Ещё один рандомный идентификатор

Source code in npdtools/types/invoice.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
class Invoice(BaseModel):
    """
    Attributes:
        invoice_id: Номер счёта
        receipt_id: Номер чека, выданного к этому счёту, если, конечно, выдан
        services: Список позиций в чеке
        url: Ссылка на страницу со счётом. Можно отправить контрагенту
        status: Статус счёта
        payment_type: Способ получения денег
        total_amount: Общая сумма всех позиций в счёте
        total_tax: Сумма налогов за этот счёт
        commission: Комиссия за получение денег. Сейчас её нет или она равна нулю
        created_at: Время создания счёта
        paid_at: Время оплаты счёта
        canceled_at: Время отмены счёта
        bank: Сведения о способе получения денег по счёту
        client_info: Сведения о клиенте
        employee_info: Сведения о самозанятом
        acquiring_info: Сведения об эквайринге, если для получения используется он (TODO: Возможно, надо перенести в bank_info)
        receipt_template: Сведения о самозанятом для отображения в счёте и чеке
        type: Способ создания счёта, обычно ``MANUAL``
        auto_create_receipt: Был ли счёт создан автоматически

        uuid: Технический идентификатор счёта в ФНС
        fid: Ещё один рандомный идентификатор
    """

    invoice_id: int = Field(..., alias="invoiceId")
    uuid: str
    receipt_id: str | None = Field(..., alias="receiptId")
    fid: int

    services: list[Service]

    url: str = Field(..., alias="transitionPageURL")

    status: Literal[
        "CREATED", "CANCELLED", "PAID_WITHOUT_RECEIPT", "PAID_WITH_RECEIPT"
    ] | str

    payment_type: PaymentTypes = Field(..., alias="paymentType")

    total_amount: Decimal = Field(..., alias="totalAmount")
    total_tax: Decimal = Field(..., alias="totalTax")
    commission: Decimal | None = None

    created_at: datetime = Field(..., alias="createdAt")
    paid_at: datetime | None = Field(None, alias="paidAt")
    canceled_at: datetime | None = Field(None, alias="cancelledAt")

    bank: BankAccount | BankPhone
    client_info: ClientInfo
    employee_info: EmployeeInfo
    acquiring_info: AcquiringInfo

    receipt_template: ReceiptTemplate | None = Field(..., alias="receiptTemplate")
    type: Literal["MANUAL"]
    auto_create_receipt: bool | None = Field(None, alias="autoCreateReceipt")

    @property
    def is_paid(self) -> bool:
        """
        Returns:
            bool: Оплачен ли счёт
        """
        return self.paid_at is not None

    @property
    def is_canceled(self) -> bool:
        """
        Returns:
            bool: Отменён ли счёт
        """
        return self.canceled_at is not None

    @model_validator(mode="before")
    @classmethod
    def normalize(cls, values: dict[str, Any]) -> dict[str, Any]:
        values["raw"] = values.copy()

        client_info: ClientInfo = ClientInfo(
            inn=values.get("clientInn", None),
            name=values.get("clientDisplayName", None),
            type=values.get("clientType", ClientType.individual),
            phone=values.get("clientContactPhone", None),
            email=values.get("clientEmail", None),
        )
        employee_info: EmployeeInfo = EmployeeInfo(
            inn=values.get("inn", None),
            profession=values.get("profession", None),
            description=values.get("description", None),
            email=values.get("email", None),
            phone=values.get("phone", None),
        )

        acquiring_info: AcquiringInfo = AcquiringInfo(
            merchant_id=values.get("merchantId", None),
            acquirer_id=values.get("acquirerId", None),
            acquirer_name=values.get("acquirerName", None),
            payment_url=values.get("paymentUrl", None),
        )

        bank = {}

        if values.get("paymentType") == "PHONE":
            bank = BankPhone(
                id=values.get("bankId"),
                name=values.get("bankName"),
                phone=values.get("phone"),
            )
        elif values.get("paymentType") == "ACCOUNT":
            bank = BankAccount(
                name=values.get("bankName"),
                bik=values.get("bankBik"),
                account=values.get("currentAccount"),
                corr=values.get("corrAccount"),
            )

        values["bank"] = bank
        values["employee_info"] = employee_info
        values["client_info"] = client_info
        values["acquiring_info"] = acquiring_info

        return values

is_paid: bool property

Returns:

Name Type Description
bool bool

Оплачен ли счёт

is_canceled: bool property

Returns:

Name Type Description
bool bool

Отменён ли счёт

InvoicesList

Bases: BaseModel

Содержит сведения о счетах и пагинации

Attributes:

Name Type Description
invoices list[Invoice]

Список счетов

has_more bool

Есть ли ещё счета для получения

offset int

Отступ от начала

limit int

Количество в выдаче

Source code in npdtools/types/invoice.py
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
class InvoicesList(BaseModel):
    """
    Содержит сведения о счетах и пагинации

    Attributes:
        invoices: Список счетов
        has_more: Есть ли ещё счета для получения
        offset: Отступ от начала
        limit: Количество в выдаче
    """

    invoices: list[Invoice] = Field(..., alias="items")
    has_more: bool = Field(..., alias="hasMore")
    offset: int = Field(..., alias="currentOffset")
    limit: int = Field(..., alias="currentLimit")

    def __iter__(self) -> Iterable[Invoice]:
        return iter(self.invoices)

    def __getitem__(self, item) -> Invoice:
        return self.invoices[item]

Service (Позиция / Товар / Услуга)

Service

Bases: BaseModel

Объект позиции в чеке или счёте

Attributes:

Name Type Description
name str

Название позиции: товара, услуги или подобного

amount Decimal

Цена единицы позиции. За штуку, грамм или подобное

quantity int

Количество. Штук, грамм или подобного

number int | None

Порядковый номер позиции. Техническая штука.

Source code in npdtools/types/service.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Service(BaseModel):
    """
    Объект позиции в чеке или счёте

    Attributes:
        name: Название позиции: товара, услуги или подобного
        amount: Цена единицы позиции. За штуку, грамм или подобное
        quantity: Количество. Штук, грамм или подобного
        number: Порядковый номер позиции. Техническая штука.
    """

    name: str
    amount: Decimal
    quantity: int = 1
    number: int | None = Field(None, alias="serviceNumber", exclude=True)

    @field_validator("amount", mode="before")
    @classmethod
    def amount_normalize(cls, value: int | float | str | Decimal):
        return amount_to_decimal(value)

    @property
    def service_amount(self) -> Decimal:
        """
        Returns:
            Decimal: Стоимость всей позиции. Цена умножить на количество.
        """
        return self.amount * self.quantity

service_amount: Decimal property

Returns:

Name Type Description
Decimal Decimal

Стоимость всей позиции. Цена умножить на количество.