Введение
В Odoo модели описывают структуру и хранение данных в базе. Любая бизнес‑сущность — от заказа до счета или контакта — представлена моделью, которая задаёт поля, связи и поведение.
Знание моделей критично как для разработчиков, так и для функциональных консультантов: именно они формируют архитектуру данных Odoo. Модель определяет типы полей, отношения между записями и встроенную бизнес‑логику.
Здесь мы подробно разбираем одну из ключевых моделей модуля «Продажи» — sale.order.line. Если вы разрабатываете модули, настраиваете прайс‑листы или интегрируете внешние системы, с ней придётся работать постоянно.
Что такое модель sale.order.line
Модель sale.order.line хранит отдельные позиции в коммерческом предложении или заказе клиента. Каждая запись обычно соответствует одному товару или услуге с количеством, ценой и налогами.
Эта модель принадлежит модулю sale и наследует аналитический миксин для привязки к проектной аналитике и учёту времени. Когда вы добавляете товар в предложение, создаётся запись sale.order.line.
Определение модели находится в модуле продаж, а другие модули расширяют её через наследование моделей Odoo. Например, sale_stock добавляет поля для доставки, а sale_margin — расчёт маржи — при этом ядро остаётся единым и не дублируется.
Ключевые поля модели
Ниже перечислены основные поля sale.order.line, знание которых помогает правильно работать с предложениями и заказами.
1. order_id
Тип: Many2one (sale.order). Обязательное поле. Ссылается на родительский заказ и связывает строку с заказом; при удалении заказа строки обычно удаляются каскадно.
2. sequence
Тип: Integer. Значение по умолчанию 10. Определяет порядок отображения строк в документе — полезно для сортировки секций, заметок и товарных позиций.
3. company_id
Тип: Many2one (res.company). Берётся из order_id. Используется для правил многокомпаний и контроля доступа.
4. currency_id
Тип: Many2one (res.currency). Берётся из заказа. Обеспечивает корректную валюту для всех денежных полей в строке.
5. order_partner_id
Тип: Many2one (res.partner). Клиент, указанный в заказе. Влияет на выбор прайс‑листа и налоговые правила.
6. salesman_id
Тип: Many2one (res.users). Привязка к менеджеру по продажам — важна для комиссии и отчётности.
7. state
Тип: Selection. Берётся из заказа. Статус заказа (черновик, отправлен, подтверждён, выполнен, отменён) определяет, какие поля доступны для редактирования.
8. display_type
Тип: Selection. Значения: line_section или line_note. Позволяет помечать строку как заголовок секции или заметку — такие строки не содержат товарных данных.
9. is_downpayment
Тип: Boolean. Флаг авансовой оплаты; такие строки выставляются отдельным счётом.
10. is_expense
Тип: Boolean. Источник строки — расход или счёт поставщика; используется для учёта затрат по проектам.
11. product_id
Тип: Many2one (product.product). Конкретный продаваемый товар. Для товарных позиций домен ограничивает выбор продажными товарами; обычно обязателен.
12. product_template_id
Тип: Many2one (product.template). Вычисляемое из product_id. Нужен для конфигурации вариантов товара и работы конфигуратора.
13. name
Тип: Text. Описание позиции; формируется из товара и дополнительных атрибутов, включает информацию о варианте при необходимости.
14. product_uom_qty
Тип: Float. Обязательное поле. Количество товара; по умолчанию 1.0; может зависеть от упаковки.
15. product_uom
Тип: Many2one (uom.uom). Единица измерения; по умолчанию берётся из карточки товара; влияет на расчёт цен и количества.
16. tax_id
Тип: Many2many (account.tax). Налоги, применяемые к строке; рассчитываются с учётом товара и фискальной позиции.
17. price_unit
Тип: Float. Обязательно. Цена за единицу в выбранной единице измерения; вычисляется из прайс‑листа или задана вручную.
18. discount
Тип: Float. Процент скидки, применяемый к цене до расчёта налогов.
19. price_subtotal
Тип: Monetary. Сумма по строке до налогов; вычисляется из количества, цены и скидки.
20. price_tax
Тип: Float. Сумма налогов по строке; вычисляется из price_subtotal и tax_id.
21. price_total
Тип: Monetary. Итоговая сумма с учётом налогов — ключевая величина для выставления счёта.
22. product_packaging_id
Тип: Many2one (product.packaging). Дополнительная упаковка (например, коробка на 12 шт.). При заданной упаковке количество может рассчитываться в упаковках.
23. customer_lead
Тип: Float. Время поставки в днях — от подтверждения заказа до отгрузки; используется для расчёта даты доставки.
24. qty_delivered
Тип: Float. Количество отгруженное; обновляется по движениям на складе или вручную; важно для частичного выставления счётов.
25. qty_invoiced
Тип: Float. Уже выставленное количество; вычисляется по строкам счёта.
26. qty_to_invoice
Тип: Float. Оставшееся к выставлению количество; рассчитывается по qty_delivered и qty_invoiced.
27. invoice_status
Тип: Selection. Значения: upselling, invoiced, to invoice, no — показывает текущее состояние по выставлению счётов для строки.
28. invoice_lines
Тип: Many2many (account.move.line). Связь со строками счётов, созданными из этой позиции — нужна для прозрачности и трассировки.
29. create_date
Тип: Datetime. Дата создания записи; управляется системой автоматически.
30. write_date
Тип: Datetime. Дата последнего изменения; полезна для аудита и синхронизаций.
Где эта модель применяется в бизнес-процессах
1. Коммерческое предложение и заказ
При создании предложения менеджер добавляет товары — каждая позиция превращается в sale.order.line и отображает количество, цену, скидку и сумму. Заказ подтверждается, когда клиент согласен с условиями.
2. Прайс‑листы и скидки
Прайс‑листы применяются на уровне строки: price_unit и discount часто вычисляются по правилам прайс‑листа. Там же обрабатываются скидки по объёму и индивидуальные условия для клиентов.
3. Доставка и выставление счетов
При отгрузке обновляется qty_delivered. Выставление счётов может происходить по факту отгрузки или по всему заказу целиком; поле invoice_status подсказывает, что ещё нужно выставить.
4. Проекты и услуги
Для сервисных продуктов строки связываются с задачами проекта и табелями; наследование analytic.mixin даёт возможность учитывать затраты по проекту.
5. Интернет‑магазин и портал
Когда клиент делает заказ на сайте, позиции корзины превращаются в sale.order.line. Конфигуратор товаров работает через product_template_id и набор пользовательских атрибутов.
Как разработчики расширяют модель
Разработчики расширяют sale.order.line разными способами, главным образом через механизмы наследования моделей Odoo.
Наследование модели
Пропишите _inherit = 'sale.order.line' в своём модуле, чтобы добавить поля, переопределить методы или задать ограничения. Такой подход сохраняет расширения вынесенными в отдельный модуль и упрощает будущие обновления.
Добавление полей
В дочерней модели объявляйте новые поля подходящего типа: Char, Many2one, Boolean, Integer, Text, Selection. Для многокомпанейных сценариев продумывайте company_dependent поля.
Расширения на Python
Переопределяйте вычисляемые методы, например _compute_price_unit или _compute_price_subtotal, либо подключайте логику в create/write. Всегда оборачивайте вызов базовой реализации через super() и внимательно следите за зависимостями вычислений.
Odoo Studio
Studio позволяет добавлять поля без кода — удобно для быстрых правок. Но для сложной логики и поддержки при обновлениях надёжнее писать полноценный модуль.
Рекомендации по использованию
- Используйте display_type для разделов и заметок — так отчёты не засоряются «пустыми» товарными строками.
- При интеграции через API создавайте строки в контексте заказа: используйте поле order_line_ids на sale.order с корректными командами Odoo для создания/обновления.
- Уважайте SQL‑ограничения: товарная строка должна иметь product_id и product_uom, а для секции/заметки обязательно указывать display_type.
- Для кастомной логики ценообразования сначала пробуйте прайс‑листы. Переопределяйте вычисления только если правила прайс‑листов не покрывают требуемый сценарий.
- Для пользовательских полей придерживайтесь префикса x_ или добавляйте префикс модуля, чтобы минимизировать риск конфликтов с будущими версиями Odoo.
Распространённые ошибки
- Создание строк без order_id. Это обязательное поле — всегда создавайте строки в контексте заказа, иначе валидаторы и бизнес‑логика сломаются.
- Путаница между product_id и product_template_id. Для реальной товарной позиции используйте product_id; product_template_id удобен в потоках конфигурации при выборе варианта.
- Изменение price_unit или discount после выставления счёта. Если qty_invoiced > 0, изменение цен может привести к несоответствиям между заказом и уже выставленными счетами.
- Переопределение ключевых методов без вызова super(). Это часто ломает сторонние модули и осложняет обновления.
- Забыть установить display_type для секции или заметки. Тогда строка будет валидироваться как товарная и приведёт к ошибке.
Вывод
Модель sale.order.line — ядро модуля продаж в Odoo: она хранит каждую позицию в предложениях и заказах. Понимание её полей и способов расширения облегчит настройку, кастомизацию и интеграцию системы.
Будь вы функциональным консультантом, формализующим процессы, или разработчиком, пишущим модули, глубокое понимание sale.order.line сэкономит время и уменьшит количество ошибок.
Нужна помощь с внедрением Odoo?
Компания Dasolo помогает внедрять, настраивать и оптимизировать Odoo. Мы специализируемся на интеграциях через API и разработке модулей, и имеем богатый опыт работы с архитектурой данных Odoo и моделями, такими как sale.order.line.
Если нужна помощь с внедрением Odoo, разработкой модулей или интеграциями — мы готовы помочь. Записаться на демо чтобы обсудить ваш проект.