Public release from ruodoo-project: 19.0 - 2026-11-01 22:52:25 UTC
This commit is contained in:
2
ruodoo_rsbu_mil/__init__.py
Normal file
2
ruodoo_rsbu_mil/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
55
ruodoo_rsbu_mil/__manifest__.py
Normal file
55
ruodoo_rsbu_mil/__manifest__.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'РСБУ — Воинский учёт (образец)',
|
||||
'version': '19.0.2026.10.01',
|
||||
'summary': 'Воинский учёт: приказы и отчёты (формы 6, 18, 19) с выгрузкой в DOCX',
|
||||
'description': """
|
||||
РСБУ — Воинский учёт (образец для настройки)
|
||||
|
||||
Демонстрационный блок воинского учёта (ВУ) поверх кадрового блока. Служит
|
||||
ОБРАЗЦОМ для дальнейшей настройки под конкретную организацию: состав форм,
|
||||
бланки и порядок уточняются у специалиста по ВУ.
|
||||
|
||||
Возможности:
|
||||
|
||||
* Данные воинского учёта на карточке сотрудника (hr.employee): отношение к
|
||||
воинской обязанности, состав (офицеры / прапорщики-солдаты), пребывание в
|
||||
запасе, бронирование и мобпредписание, категория должности для форм ВУ.
|
||||
* Реквизиты организации для ВУ на res.company (ответственный за ВУ, ведётся
|
||||
ли бронирование, коды ОКАТО/ОКОПФ/ОКФС/ОКПО).
|
||||
* Приказы по воинскому учёту (ruodoo.rsbu.mil.order) — об организации ВУ,
|
||||
о назначении ответственного и т.п. — с выгрузкой в DOCX.
|
||||
* Отчёты по воинскому учёту (ruodoo.rsbu.mil.report): форма 6 (отчёт о
|
||||
численности работающих и забронированных в запасе), форма 18 (карточка
|
||||
учёта организации), форма 19 (сведения об обеспеченности трудовыми
|
||||
ресурсами). Данные собираются из системы и выгружаются в DOCX через
|
||||
шаблонизатор docx_report.
|
||||
|
||||
Меню «Воинский учёт» размещается в приложении OCA Payroll.
|
||||
|
||||
> Выгрузка — в формате DOCX (шаблоны docx_report). Конвертация в PDF
|
||||
> возможна при наличии LibreOffice в окружении.
|
||||
""",
|
||||
'author': 'MK.Lab, RuOdoo',
|
||||
'website': 'https://ruodoo.ru',
|
||||
'category': 'Human Resources/Payroll',
|
||||
'depends': [
|
||||
'payroll',
|
||||
'rsbu_payroll',
|
||||
'rsbu_reporting_base',
|
||||
'docx_report',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/docx_templates.xml',
|
||||
'views/hr_employee_views.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'views/ruodoo_rsbu_mil_order_views.xml',
|
||||
'views/ruodoo_rsbu_mil_report_views.xml',
|
||||
'views/ruodoo_rsbu_mil_menus.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': False,
|
||||
'license': 'LGPL-3',
|
||||
'maintainers': ['mklab', 'ruodoo'],
|
||||
}
|
||||
56
ruodoo_rsbu_mil/data/docx_templates.xml
Normal file
56
ruodoo_rsbu_mil/data/docx_templates.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0">
|
||||
<!-- Форма 6 — отчёт о численности в запасе. -->
|
||||
<record id="docx_template_mil_form6" model="docx.template">
|
||||
<field name="name">Воинский учёт — Форма 6 (DOCX)</field>
|
||||
<field name="report_type">docx-docx</field>
|
||||
<field name="model">ruodoo.rsbu.mil.report</field>
|
||||
<field name="docx_output_type">docx</field>
|
||||
<field name="global_template" eval="True"/>
|
||||
<field name="filename_pattern">'Форма 6 ' + (object.report_date and object.report_date.strftime('%d.%m.%Y') or '')</field>
|
||||
<field name="report_docx_template" type="base64"
|
||||
file="ruodoo_rsbu_mil/static/src/docx/mil_form6.docx"/>
|
||||
<field name="report_docx_template_filename">mil_form6.docx</field>
|
||||
</record>
|
||||
|
||||
<!-- Форма 18 — карточка учёта организации. -->
|
||||
<record id="docx_template_mil_form18" model="docx.template">
|
||||
<field name="name">Воинский учёт — Форма 18 (DOCX)</field>
|
||||
<field name="report_type">docx-docx</field>
|
||||
<field name="model">ruodoo.rsbu.mil.report</field>
|
||||
<field name="docx_output_type">docx</field>
|
||||
<field name="global_template" eval="True"/>
|
||||
<field name="filename_pattern">'Форма 18 ' + (object.report_date and object.report_date.strftime('%d.%m.%Y') or '')</field>
|
||||
<field name="report_docx_template" type="base64"
|
||||
file="ruodoo_rsbu_mil/static/src/docx/mil_form18.docx"/>
|
||||
<field name="report_docx_template_filename">mil_form18.docx</field>
|
||||
</record>
|
||||
|
||||
<!-- Форма 19 — обеспеченность трудовыми ресурсами. -->
|
||||
<record id="docx_template_mil_form19" model="docx.template">
|
||||
<field name="name">Воинский учёт — Форма 19 (DOCX)</field>
|
||||
<field name="report_type">docx-docx</field>
|
||||
<field name="model">ruodoo.rsbu.mil.report</field>
|
||||
<field name="docx_output_type">docx</field>
|
||||
<field name="global_template" eval="True"/>
|
||||
<field name="filename_pattern">'Форма 19 ' + (object.report_date and object.report_date.strftime('%d.%m.%Y') or '')</field>
|
||||
<field name="report_docx_template" type="base64"
|
||||
file="ruodoo_rsbu_mil/static/src/docx/mil_form19.docx"/>
|
||||
<field name="report_docx_template_filename">mil_form19.docx</field>
|
||||
</record>
|
||||
|
||||
<!-- Приказ по воинскому учёту. -->
|
||||
<record id="docx_template_mil_order" model="docx.template">
|
||||
<field name="name">Воинский учёт — Приказ (DOCX)</field>
|
||||
<field name="report_type">docx-docx</field>
|
||||
<field name="model">ruodoo.rsbu.mil.order</field>
|
||||
<field name="docx_output_type">docx</field>
|
||||
<field name="global_template" eval="True"/>
|
||||
<field name="filename_pattern">'Приказ ВУ ' + (object.name or '')</field>
|
||||
<field name="report_docx_template" type="base64"
|
||||
file="ruodoo_rsbu_mil/static/src/docx/mil_order.docx"/>
|
||||
<field name="report_docx_template_filename">mil_order.docx</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
6
ruodoo_rsbu_mil/models/__init__.py
Normal file
6
ruodoo_rsbu_mil/models/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import res_company
|
||||
from . import res_config_settings
|
||||
from . import hr_employee
|
||||
from . import ruodoo_rsbu_mil_order
|
||||
from . import ruodoo_rsbu_mil_report
|
||||
80
ruodoo_rsbu_mil/models/hr_employee.py
Normal file
80
ruodoo_rsbu_mil/models/hr_employee.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Данные воинского учёта на карточке сотрудника.
|
||||
|
||||
Минимальный набор признаков, достаточный для агрегатов форм воинского
|
||||
учёта (6, 18, 19): отношение к воинской обязанности, состав (офицеры /
|
||||
прочие), пребывание в запасе, бронирование и мобпредписание, а также
|
||||
категория должности для группировки в формах.
|
||||
|
||||
Это ОБРАЗЕЦ: состав полей и справочники уточняются у специалиста по ВУ.
|
||||
"""
|
||||
from odoo import fields, models
|
||||
|
||||
# Категория должности для группировки в формах 6 и 19.
|
||||
MIL_JOB_CATEGORY = [
|
||||
('manager', 'Руководители'),
|
||||
('specialist', 'Специалисты'),
|
||||
('clerk', 'Служащие'),
|
||||
('worker', 'Рабочие'),
|
||||
]
|
||||
|
||||
# Состав граждан, пребывающих в запасе (деление в формах 6/18).
|
||||
MIL_RANK_GROUP = [
|
||||
('officer', 'Офицеры (и генералы)'),
|
||||
('soldier', 'Прапорщики, мичманы, сержанты, старшины, солдаты и матросы'),
|
||||
]
|
||||
|
||||
|
||||
class HrEmployee(models.Model):
|
||||
_inherit = 'hr.employee'
|
||||
|
||||
rsbu_mil_liable = fields.Boolean(
|
||||
string='Военнообязанный',
|
||||
help='Сотрудник подлежит воинскому учёту (военнообязанный или '
|
||||
'призывник).')
|
||||
rsbu_mil_in_reserve = fields.Boolean(
|
||||
string='Пребывает в запасе',
|
||||
help='Гражданин РФ, пребывающий в запасе (для форм 6/18/19).')
|
||||
rsbu_mil_rank_group = fields.Selection(
|
||||
selection=MIL_RANK_GROUP, string='Состав',
|
||||
help='Состав для деления в отчётах: офицеры либо '
|
||||
'прапорщики/сержанты/солдаты.')
|
||||
rsbu_mil_conscript = fields.Boolean(
|
||||
string='Подлежит призыву',
|
||||
help='Гражданин, подлежащий призыву на военную службу (не в запасе).')
|
||||
rsbu_mil_booked = fields.Boolean(
|
||||
string='Забронирован',
|
||||
help='Гражданин, пребывающий в запасе, забронированный за '
|
||||
'организацией на период мобилизации и военное время.')
|
||||
rsbu_mil_mobilization_order = fields.Boolean(
|
||||
string='Имеет мобпредписание',
|
||||
help='Наличие мобилизационного предписания в военном билете.')
|
||||
rsbu_mil_limited_fit = fields.Boolean(
|
||||
string='Ограниченно годен',
|
||||
help='Ограниченно годен к военной службе (категория годности «В»).')
|
||||
rsbu_mil_job_category = fields.Selection(
|
||||
selection=MIL_JOB_CATEGORY, string='Категория должности (ВУ)',
|
||||
help='Категория должности для группировки в формах 6 и 19 '
|
||||
'(руководители/специалисты/служащие/рабочие).')
|
||||
rsbu_mil_vus = fields.Char(
|
||||
string='ВУС',
|
||||
help='Военно-учётная специальность (код по военному билету).')
|
||||
rsbu_mil_rank = fields.Char(
|
||||
string='Воинское звание',
|
||||
help='Воинское звание по военному билету.')
|
||||
rsbu_mil_fitness = fields.Selection(
|
||||
selection=[
|
||||
('A', 'А — годен'),
|
||||
('B', 'Б — годен с незначительными ограничениями'),
|
||||
('V', 'В — ограниченно годен'),
|
||||
('G', 'Г — временно не годен'),
|
||||
('D', 'Д — не годен'),
|
||||
],
|
||||
string='Категория годности',
|
||||
help='Категория годности к военной службе.')
|
||||
rsbu_mil_commissariat = fields.Char(
|
||||
string='Военный комиссариат',
|
||||
help='Наименование военкомата, в котором состоит на учёте.')
|
||||
rsbu_mil_is_driver = fields.Boolean(
|
||||
string='Водитель (ВУ)',
|
||||
help='Отметка «из них водители» для формы 19.')
|
||||
46
ruodoo_rsbu_mil/models/res_company.py
Normal file
46
ruodoo_rsbu_mil/models/res_company.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Реквизиты организации для воинского учёта (формы 6/18/19).
|
||||
|
||||
Дополняют реквизиты, уже имеющиеся в rsbu_reporting_base (ОГРН, ОКВЭД)
|
||||
и в l10n_ru (ИНН/КПП). Это ОБРАЗЕЦ — состав уточняется у специалиста ВУ.
|
||||
"""
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
rsbu_mil_responsible = fields.Char(
|
||||
string='Ответственный за ВУ',
|
||||
help='Ф.И.О. работника, ответственного за воинский учёт и '
|
||||
'бронирование (форма 18).')
|
||||
rsbu_mil_responsible_phone = fields.Char(
|
||||
string='Телефон ответственного за ВУ')
|
||||
rsbu_mil_does_booking = fields.Boolean(
|
||||
string='Ведёт бронирование',
|
||||
help='Организация ведёт бронирование граждан, пребывающих в запасе '
|
||||
'(пункт 11 формы 18).')
|
||||
rsbu_mil_booking_list_section = fields.Char(
|
||||
string='Номер и раздел перечня бронирования',
|
||||
help='Номер и раздел перечня должностей и профессий, по которым '
|
||||
'бронируются граждане РФ (пункт 12 формы 18).')
|
||||
rsbu_mil_reg_number = fields.Char(
|
||||
string='Рег. номер (районная комиссия)',
|
||||
help='Регистрационный номер по учёту районной комиссии (форма 18).')
|
||||
rsbu_mil_parent_org = fields.Char(
|
||||
string='Вышестоящая организация',
|
||||
help='Вышестоящая организация (пункт 8 формы 18).')
|
||||
rsbu_mil_jurisdiction = fields.Char(
|
||||
string='В сфере ведения',
|
||||
help='В сфере ведения субъекта РФ или ФОИВ (пункт 13 формы 18).')
|
||||
# Коды организации для карточки (форма 18).
|
||||
rsbu_okato = fields.Char(
|
||||
string='ОКАТО',
|
||||
help='Код административно-территориального деления (ОКАТО).')
|
||||
# ОКПО переиспользуется из l10n_ru (поле res.company.okpo).
|
||||
rsbu_okopf = fields.Char(
|
||||
string='ОКОПФ',
|
||||
help='Организационно-правовая форма (ОКОПФ, текстовая расшифровка).')
|
||||
rsbu_okfs = fields.Char(
|
||||
string='ОКФС',
|
||||
help='Форма собственности (ОКФС, текстовая расшифровка).')
|
||||
35
ruodoo_rsbu_mil/models/res_config_settings.py
Normal file
35
ruodoo_rsbu_mil/models/res_config_settings.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Реквизиты воинского учёта организации в настройках."""
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
rsbu_mil_responsible = fields.Char(
|
||||
related='company_id.rsbu_mil_responsible', readonly=False,
|
||||
string='Ответственный за ВУ')
|
||||
rsbu_mil_responsible_phone = fields.Char(
|
||||
related='company_id.rsbu_mil_responsible_phone', readonly=False,
|
||||
string='Телефон ответственного за ВУ')
|
||||
rsbu_mil_does_booking = fields.Boolean(
|
||||
related='company_id.rsbu_mil_does_booking', readonly=False,
|
||||
string='Ведёт бронирование')
|
||||
rsbu_mil_booking_list_section = fields.Char(
|
||||
related='company_id.rsbu_mil_booking_list_section', readonly=False,
|
||||
string='Номер и раздел перечня бронирования')
|
||||
rsbu_mil_reg_number = fields.Char(
|
||||
related='company_id.rsbu_mil_reg_number', readonly=False,
|
||||
string='Рег. номер (районная комиссия)')
|
||||
rsbu_mil_parent_org = fields.Char(
|
||||
related='company_id.rsbu_mil_parent_org', readonly=False,
|
||||
string='Вышестоящая организация')
|
||||
rsbu_mil_jurisdiction = fields.Char(
|
||||
related='company_id.rsbu_mil_jurisdiction', readonly=False,
|
||||
string='В сфере ведения')
|
||||
rsbu_okato = fields.Char(
|
||||
related='company_id.rsbu_okato', readonly=False, string='ОКАТО')
|
||||
rsbu_okopf = fields.Char(
|
||||
related='company_id.rsbu_okopf', readonly=False, string='ОКОПФ')
|
||||
rsbu_okfs = fields.Char(
|
||||
related='company_id.rsbu_okfs', readonly=False, string='ОКФС')
|
||||
83
ruodoo_rsbu_mil/models/ruodoo_rsbu_mil_order.py
Normal file
83
ruodoo_rsbu_mil/models/ruodoo_rsbu_mil_order.py
Normal file
@@ -0,0 +1,83 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Приказы по воинскому учёту.
|
||||
|
||||
Организационные приказы ВУ (об организации воинского учёта, о назначении
|
||||
ответственного за ВУ и бронирование и т.п.). Документ-шаблон: заполняется
|
||||
реквизитами и выгружается в DOCX через docx_report.
|
||||
|
||||
Это ОБРАЗЕЦ: типовые формулировки приказов задаются по умолчанию и
|
||||
правятся пользователем.
|
||||
"""
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
# Виды приказов по ВУ.
|
||||
ORDER_KIND = [
|
||||
('organization', 'Об организации воинского учёта'),
|
||||
('responsible', 'О назначении ответственного за ВУ и бронирование'),
|
||||
('plan', 'Об утверждении плана работы по ВУ'),
|
||||
('other', 'Иной приказ по ВУ'),
|
||||
]
|
||||
|
||||
|
||||
class RuodooRsbuMilOrder(models.Model):
|
||||
_name = 'ruodoo.rsbu.mil.order'
|
||||
_description = 'Приказ по воинскому учёту'
|
||||
_order = 'order_date desc, id desc'
|
||||
|
||||
name = fields.Char(
|
||||
string='Номер приказа', required=True, copy=False, default='б/н')
|
||||
kind = fields.Selection(
|
||||
selection=ORDER_KIND, string='Вид приказа', required=True,
|
||||
default='organization')
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Организация', required=True, index=True,
|
||||
default=lambda self: self.env.company)
|
||||
order_date = fields.Date(
|
||||
string='Дата приказа', required=True,
|
||||
default=fields.Date.context_today)
|
||||
title = fields.Char(
|
||||
string='Заголовок', compute='_compute_title', store=True,
|
||||
readonly=False,
|
||||
help='Заголовок приказа. По умолчанию формируется по виду приказа.')
|
||||
body = fields.Html(
|
||||
string='Текст приказа',
|
||||
help='Основной текст (приказываю: ...). Можно править.')
|
||||
responsible_employee_id = fields.Many2one(
|
||||
'hr.employee', string='Назначаемый ответственный',
|
||||
help='Сотрудник, назначаемый ответственным за ВУ (для приказа о '
|
||||
'назначении).')
|
||||
signatory_name = fields.Char(
|
||||
string='Подписант', compute='_compute_signatory', store=True,
|
||||
readonly=False)
|
||||
signatory_title = fields.Char(
|
||||
string='Должность подписанта', compute='_compute_signatory',
|
||||
store=True, readonly=False)
|
||||
|
||||
@api.depends('kind')
|
||||
def _compute_title(self):
|
||||
labels = dict(ORDER_KIND)
|
||||
for rec in self:
|
||||
if not rec.title:
|
||||
rec.title = labels.get(rec.kind, 'Приказ по воинскому учёту')
|
||||
|
||||
@api.depends('company_id')
|
||||
def _compute_signatory(self):
|
||||
for rec in self:
|
||||
signatory = rec.company_id.rsbu_signatory_id
|
||||
if signatory and not rec.signatory_name:
|
||||
rec.signatory_name = signatory.partner_id.name
|
||||
if not rec.signatory_title:
|
||||
rec.signatory_title = (
|
||||
rec.company_id.rsbu_signatory_title or 'Руководитель')
|
||||
|
||||
def action_print_docx(self):
|
||||
"""Сформировать DOCX приказа по шаблону."""
|
||||
self.ensure_one()
|
||||
template = self.env.ref(
|
||||
'ruodoo_rsbu_mil.docx_template_mil_order',
|
||||
raise_if_not_found=False)
|
||||
if not template:
|
||||
raise UserError(
|
||||
'Не найден шаблон DOCX приказа по воинскому учёту.')
|
||||
return template.report_id.report_action(self)
|
||||
195
ruodoo_rsbu_mil/models/ruodoo_rsbu_mil_report.py
Normal file
195
ruodoo_rsbu_mil/models/ruodoo_rsbu_mil_report.py
Normal file
@@ -0,0 +1,195 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Отчёты по воинскому учёту: формы 6, 18, 19.
|
||||
|
||||
Собирают численности из карточек сотрудников (hr.employee, поля
|
||||
воинского учёта) и выгружаются в DOCX через docx_report.
|
||||
|
||||
* Форма 6 — отчёт о численности работающих и забронированных граждан,
|
||||
пребывающих в запасе (строки по категориям должности).
|
||||
* Форма 18 — карточка учёта организации (реквизиты + сводные числа).
|
||||
* Форма 19 — сведения об обеспеченности трудовыми ресурсами (строки по
|
||||
категориям должности с потребностью/некомплектом).
|
||||
|
||||
Это ОБРАЗЕЦ: методика подсчёта упрощена и уточняется у специалиста ВУ.
|
||||
"""
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
from .hr_employee import MIL_JOB_CATEGORY
|
||||
|
||||
REPORT_KIND = [
|
||||
('form6', 'Форма 6 — численность работающих и забронированных в запасе'),
|
||||
('form18', 'Форма 18 — карточка учёта организации'),
|
||||
('form19', 'Форма 19 — обеспеченность трудовыми ресурсами'),
|
||||
]
|
||||
|
||||
# Шаблоны docx_report (xmlid docx.template → по виду формы).
|
||||
_REPORT_XMLID = {
|
||||
'form6': 'ruodoo_rsbu_mil.docx_template_mil_form6',
|
||||
'form18': 'ruodoo_rsbu_mil.docx_template_mil_form18',
|
||||
'form19': 'ruodoo_rsbu_mil.docx_template_mil_form19',
|
||||
}
|
||||
|
||||
|
||||
class RuodooRsbuMilReport(models.Model):
|
||||
_name = 'ruodoo.rsbu.mil.report'
|
||||
_description = 'Отчёт по воинскому учёту'
|
||||
_order = 'report_date desc, id desc'
|
||||
|
||||
name = fields.Char(string='Наименование', compute='_compute_name',
|
||||
store=True)
|
||||
kind = fields.Selection(
|
||||
selection=REPORT_KIND, string='Форма', required=True, default='form6')
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Организация', required=True, index=True,
|
||||
default=lambda self: self.env.company)
|
||||
report_date = fields.Date(
|
||||
string='По состоянию на', required=True,
|
||||
default=fields.Date.context_today,
|
||||
help='Дата, по состоянию на которую формируется отчёт.')
|
||||
year = fields.Integer(
|
||||
string='Отчётный год', default=lambda self: fields.Date.today().year)
|
||||
state = fields.Selection(
|
||||
selection=[('draft', 'Черновик'), ('computed', 'Рассчитано')],
|
||||
default='draft', string='Состояние', copy=False)
|
||||
line_ids = fields.One2many(
|
||||
'ruodoo.rsbu.mil.report.line', 'report_id', string='Строки')
|
||||
|
||||
# --- Сводные числа (используются формой 18 и итогами). ---
|
||||
total_employees = fields.Integer(
|
||||
string='Всего работающих', compute='_compute_totals', store=True)
|
||||
total_reserve = fields.Integer(
|
||||
string='В запасе, всего', compute='_compute_totals', store=True)
|
||||
total_reserve_officer = fields.Integer(
|
||||
string='В запасе, офицеры', compute='_compute_totals', store=True)
|
||||
total_reserve_soldier = fields.Integer(
|
||||
string='В запасе, прочие', compute='_compute_totals', store=True)
|
||||
total_booked = fields.Integer(
|
||||
string='Забронировано, всего', compute='_compute_totals', store=True)
|
||||
total_booked_officer = fields.Integer(
|
||||
string='Забронировано, офицеры', compute='_compute_totals',
|
||||
store=True)
|
||||
total_booked_soldier = fields.Integer(
|
||||
string='Забронировано, прочие', compute='_compute_totals', store=True)
|
||||
total_conscript = fields.Integer(
|
||||
string='Подлежат призыву', compute='_compute_totals', store=True)
|
||||
total_limited_fit = fields.Integer(
|
||||
string='Ограниченно годных', compute='_compute_totals', store=True)
|
||||
total_no_order = fields.Integer(
|
||||
string='В запасе без мобпредписаний', compute='_compute_totals',
|
||||
store=True)
|
||||
total_with_order = fields.Integer(
|
||||
string='В запасе с мобпредписаниями', compute='_compute_totals',
|
||||
store=True)
|
||||
|
||||
@api.depends('kind', 'report_date', 'year')
|
||||
def _compute_name(self):
|
||||
labels = dict(REPORT_KIND)
|
||||
for rec in self:
|
||||
short = (labels.get(rec.kind, '?') or '').split('—')[0].strip()
|
||||
dt = rec.report_date and rec.report_date.strftime('%d.%m.%Y') or '?'
|
||||
rec.name = '%s на %s' % (short, dt)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
def _mil_employees(self):
|
||||
"""Военнообязанные сотрудники организации."""
|
||||
self.ensure_one()
|
||||
return self.env['hr.employee'].search([
|
||||
('company_id', '=', self.company_id.id),
|
||||
('rsbu_mil_liable', '=', True),
|
||||
])
|
||||
|
||||
@api.depends('company_id')
|
||||
def _compute_totals(self):
|
||||
for rec in self:
|
||||
emps = rec._mil_employees()
|
||||
reserve = emps.filtered('rsbu_mil_in_reserve')
|
||||
booked = reserve.filtered('rsbu_mil_booked')
|
||||
rec.total_employees = len(emps)
|
||||
rec.total_reserve = len(reserve)
|
||||
rec.total_reserve_officer = len(reserve.filtered(
|
||||
lambda e: e.rsbu_mil_rank_group == 'officer'))
|
||||
rec.total_reserve_soldier = len(reserve.filtered(
|
||||
lambda e: e.rsbu_mil_rank_group == 'soldier'))
|
||||
rec.total_booked = len(booked)
|
||||
rec.total_booked_officer = len(booked.filtered(
|
||||
lambda e: e.rsbu_mil_rank_group == 'officer'))
|
||||
rec.total_booked_soldier = len(booked.filtered(
|
||||
lambda e: e.rsbu_mil_rank_group == 'soldier'))
|
||||
rec.total_conscript = len(emps.filtered('rsbu_mil_conscript'))
|
||||
rec.total_limited_fit = len(reserve.filtered('rsbu_mil_limited_fit'))
|
||||
not_booked = reserve.filtered(lambda e: not e.rsbu_mil_booked)
|
||||
rec.total_no_order = len(not_booked.filtered(
|
||||
lambda e: not e.rsbu_mil_mobilization_order))
|
||||
rec.total_with_order = len(not_booked.filtered(
|
||||
'rsbu_mil_mobilization_order'))
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
def action_compute(self):
|
||||
"""Рассчитать строки отчёта по категориям должности."""
|
||||
Line = self.env['ruodoo.rsbu.mil.report.line']
|
||||
for rec in self:
|
||||
rec.line_ids.unlink()
|
||||
emps = rec._mil_employees()
|
||||
vals = []
|
||||
for code, label in MIL_JOB_CATEGORY:
|
||||
cat = emps.filtered(lambda e: e.rsbu_mil_job_category == code)
|
||||
reserve = cat.filtered('rsbu_mil_in_reserve')
|
||||
booked = reserve.filtered('rsbu_mil_booked')
|
||||
conscript = cat.filtered('rsbu_mil_conscript')
|
||||
vals.append({
|
||||
'report_id': rec.id,
|
||||
'category': code,
|
||||
'name': label,
|
||||
'total': len(cat),
|
||||
'reserve_total': len(reserve),
|
||||
'reserve_officer': len(reserve.filtered(
|
||||
lambda e: e.rsbu_mil_rank_group == 'officer')),
|
||||
'reserve_soldier': len(reserve.filtered(
|
||||
lambda e: e.rsbu_mil_rank_group == 'soldier')),
|
||||
'booked_total': len(booked),
|
||||
'booked_officer': len(booked.filtered(
|
||||
lambda e: e.rsbu_mil_rank_group == 'officer')),
|
||||
'booked_soldier': len(booked.filtered(
|
||||
lambda e: e.rsbu_mil_rank_group == 'soldier')),
|
||||
'conscript_total': len(conscript),
|
||||
})
|
||||
if vals:
|
||||
Line.create(vals)
|
||||
rec.state = 'computed'
|
||||
return True
|
||||
|
||||
def action_print_docx(self):
|
||||
"""Сформировать DOCX отчёта по шаблону, соответствующему форме."""
|
||||
self.ensure_one()
|
||||
if self.state == 'draft':
|
||||
self.action_compute()
|
||||
xmlid = _REPORT_XMLID.get(self.kind)
|
||||
template = self.env.ref(xmlid, raise_if_not_found=False) if xmlid else None
|
||||
if not template:
|
||||
raise UserError(
|
||||
'Не найден шаблон DOCX для выбранной формы воинского учёта.')
|
||||
return template.report_id.report_action(self)
|
||||
|
||||
|
||||
class RuodooRsbuMilReportLine(models.Model):
|
||||
_name = 'ruodoo.rsbu.mil.report.line'
|
||||
_description = 'Строка отчёта по воинскому учёту'
|
||||
_order = 'report_id, sequence, id'
|
||||
|
||||
report_id = fields.Many2one(
|
||||
'ruodoo.rsbu.mil.report', string='Отчёт', required=True,
|
||||
ondelete='cascade', index=True)
|
||||
sequence = fields.Integer(string='Порядок', default=10)
|
||||
category = fields.Selection(
|
||||
selection=MIL_JOB_CATEGORY, string='Категория должности')
|
||||
name = fields.Char(string='Наименование категории')
|
||||
total = fields.Integer(string='Всего работающих')
|
||||
reserve_total = fields.Integer(string='В запасе, всего')
|
||||
reserve_officer = fields.Integer(string='В запасе, офицеры')
|
||||
reserve_soldier = fields.Integer(string='В запасе, прочие')
|
||||
booked_total = fields.Integer(string='Забронировано, всего')
|
||||
booked_officer = fields.Integer(string='Забронировано, офицеры')
|
||||
booked_soldier = fields.Integer(string='Забронировано, прочие')
|
||||
conscript_total = fields.Integer(string='Подлежат призыву')
|
||||
note = fields.Char(string='Примечание')
|
||||
7
ruodoo_rsbu_mil/security/ir.model.access.csv
Normal file
7
ruodoo_rsbu_mil/security/ir.model.access.csv
Normal file
@@ -0,0 +1,7 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_ruodoo_rsbu_mil_order_user,ruodoo.rsbu.mil.order user,model_ruodoo_rsbu_mil_order,payroll.group_payroll_user,1,0,0,0
|
||||
access_ruodoo_rsbu_mil_order_mgr,ruodoo.rsbu.mil.order manager,model_ruodoo_rsbu_mil_order,payroll.group_payroll_manager,1,1,1,1
|
||||
access_ruodoo_rsbu_mil_report_user,ruodoo.rsbu.mil.report user,model_ruodoo_rsbu_mil_report,payroll.group_payroll_user,1,0,0,0
|
||||
access_ruodoo_rsbu_mil_report_mgr,ruodoo.rsbu.mil.report manager,model_ruodoo_rsbu_mil_report,payroll.group_payroll_manager,1,1,1,1
|
||||
access_ruodoo_rsbu_mil_report_line_user,ruodoo.rsbu.mil.report.line user,model_ruodoo_rsbu_mil_report_line,payroll.group_payroll_user,1,0,0,0
|
||||
access_ruodoo_rsbu_mil_report_line_mgr,ruodoo.rsbu.mil.report.line manager,model_ruodoo_rsbu_mil_report_line,payroll.group_payroll_manager,1,1,1,1
|
||||
|
BIN
ruodoo_rsbu_mil/static/description/icon.png
Normal file
BIN
ruodoo_rsbu_mil/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
ruodoo_rsbu_mil/static/src/docx/mil_form18.docx
Normal file
BIN
ruodoo_rsbu_mil/static/src/docx/mil_form18.docx
Normal file
Binary file not shown.
BIN
ruodoo_rsbu_mil/static/src/docx/mil_form19.docx
Normal file
BIN
ruodoo_rsbu_mil/static/src/docx/mil_form19.docx
Normal file
Binary file not shown.
BIN
ruodoo_rsbu_mil/static/src/docx/mil_form6.docx
Normal file
BIN
ruodoo_rsbu_mil/static/src/docx/mil_form6.docx
Normal file
Binary file not shown.
BIN
ruodoo_rsbu_mil/static/src/docx/mil_order.docx
Normal file
BIN
ruodoo_rsbu_mil/static/src/docx/mil_order.docx
Normal file
Binary file not shown.
45
ruodoo_rsbu_mil/views/hr_employee_views.xml
Normal file
45
ruodoo_rsbu_mil/views/hr_employee_views.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_employee_form_mil" model="ir.ui.view">
|
||||
<field name="name">hr.employee.form.mil</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="inherit_id" ref="hr.view_employee_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="Воинский учёт" name="rsbu_mil">
|
||||
<group>
|
||||
<group string="Статус">
|
||||
<field name="rsbu_mil_liable"/>
|
||||
<field name="rsbu_mil_in_reserve"
|
||||
invisible="not rsbu_mil_liable"/>
|
||||
<field name="rsbu_mil_conscript"
|
||||
invisible="not rsbu_mil_liable"/>
|
||||
<field name="rsbu_mil_rank_group"
|
||||
invisible="not rsbu_mil_in_reserve"/>
|
||||
<field name="rsbu_mil_job_category"
|
||||
invisible="not rsbu_mil_liable"/>
|
||||
</group>
|
||||
<group string="Бронирование">
|
||||
<field name="rsbu_mil_booked"
|
||||
invisible="not rsbu_mil_in_reserve"/>
|
||||
<field name="rsbu_mil_mobilization_order"
|
||||
invisible="not rsbu_mil_in_reserve"/>
|
||||
<field name="rsbu_mil_limited_fit"
|
||||
invisible="not rsbu_mil_in_reserve"/>
|
||||
<field name="rsbu_mil_is_driver"
|
||||
invisible="not rsbu_mil_liable"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Военный билет">
|
||||
<field name="rsbu_mil_rank"/>
|
||||
<field name="rsbu_mil_vus"/>
|
||||
<field name="rsbu_mil_fitness"/>
|
||||
<field name="rsbu_mil_commissariat"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
37
ruodoo_rsbu_mil/views/res_config_settings_views.xml
Normal file
37
ruodoo_rsbu_mil/views/res_config_settings_views.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="res_config_settings_view_form_mil" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.form.mil</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form" position="inside">
|
||||
<app string="Воинский учёт" name="ruodoo_rsbu_mil"
|
||||
logo="/base/static/img/icons/settings.png">
|
||||
<block title="Реквизиты организации для ВУ"
|
||||
name="rsbu_mil_block">
|
||||
<setting string="Ответственный за ВУ"
|
||||
help="Ф.И.О. и телефон ответственного за воинский учёт">
|
||||
<field name="rsbu_mil_responsible"/>
|
||||
<field name="rsbu_mil_responsible_phone"/>
|
||||
</setting>
|
||||
<setting string="Бронирование">
|
||||
<field name="rsbu_mil_does_booking"/>
|
||||
<field name="rsbu_mil_booking_list_section"/>
|
||||
</setting>
|
||||
<setting string="Прочие реквизиты">
|
||||
<field name="rsbu_mil_reg_number"/>
|
||||
<field name="rsbu_mil_parent_org"/>
|
||||
<field name="rsbu_mil_jurisdiction"/>
|
||||
</setting>
|
||||
<setting string="Коды организации">
|
||||
<field name="rsbu_okato"/>
|
||||
<field name="rsbu_okopf"/>
|
||||
<field name="rsbu_okfs"/>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
15
ruodoo_rsbu_mil/views/ruodoo_rsbu_mil_menus.xml
Normal file
15
ruodoo_rsbu_mil/views/ruodoo_rsbu_mil_menus.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Раздел «Воинский учёт» в приложении OCA Payroll. -->
|
||||
<menuitem id="menu_rsbu_mil_root" name="Воинский учёт"
|
||||
parent="payroll.payroll_menu_root" sequence="60"
|
||||
groups="payroll.group_payroll_user"/>
|
||||
|
||||
<menuitem id="menu_rsbu_mil_report" name="Отчёты (формы 6, 18, 19)"
|
||||
parent="menu_rsbu_mil_root" action="action_mil_report"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="menu_rsbu_mil_order" name="Приказы"
|
||||
parent="menu_rsbu_mil_root" action="action_mil_order"
|
||||
sequence="20"/>
|
||||
</odoo>
|
||||
54
ruodoo_rsbu_mil/views/ruodoo_rsbu_mil_order_views.xml
Normal file
54
ruodoo_rsbu_mil/views/ruodoo_rsbu_mil_order_views.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_mil_order_list" model="ir.ui.view">
|
||||
<field name="name">ruodoo.rsbu.mil.order.list</field>
|
||||
<field name="model">ruodoo.rsbu.mil.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Приказы по воинскому учёту">
|
||||
<field name="order_date"/>
|
||||
<field name="name"/>
|
||||
<field name="kind"/>
|
||||
<field name="title"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_mil_order_form" model="ir.ui.view">
|
||||
<field name="name">ruodoo.rsbu.mil.order.form</field>
|
||||
<field name="model">ruodoo.rsbu.mil.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Приказ по воинскому учёту">
|
||||
<header>
|
||||
<button name="action_print_docx" type="object"
|
||||
string="Сформировать DOCX" class="btn-primary"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="kind"/>
|
||||
<field name="name"/>
|
||||
<field name="order_date"/>
|
||||
<field name="company_id"
|
||||
groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="responsible_employee_id"
|
||||
invisible="kind != 'responsible'"/>
|
||||
<field name="signatory_name"/>
|
||||
<field name="signatory_title"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="title"/>
|
||||
<field name="body"/>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_mil_order" model="ir.actions.act_window">
|
||||
<field name="name">Приказы по ВУ</field>
|
||||
<field name="res_model">ruodoo.rsbu.mil.order</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
77
ruodoo_rsbu_mil/views/ruodoo_rsbu_mil_report_views.xml
Normal file
77
ruodoo_rsbu_mil/views/ruodoo_rsbu_mil_report_views.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_mil_report_list" model="ir.ui.view">
|
||||
<field name="name">ruodoo.rsbu.mil.report.list</field>
|
||||
<field name="model">ruodoo.rsbu.mil.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Отчёты по воинскому учёту">
|
||||
<field name="report_date"/>
|
||||
<field name="kind"/>
|
||||
<field name="total_employees"/>
|
||||
<field name="total_reserve"/>
|
||||
<field name="total_booked"/>
|
||||
<field name="state" widget="badge"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_mil_report_form" model="ir.ui.view">
|
||||
<field name="name">ruodoo.rsbu.mil.report.form</field>
|
||||
<field name="model">ruodoo.rsbu.mil.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Отчёт по воинскому учёту">
|
||||
<header>
|
||||
<button name="action_compute" type="object"
|
||||
string="Рассчитать" class="btn-primary"/>
|
||||
<button name="action_print_docx" type="object"
|
||||
string="Сформировать DOCX"/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1><field name="name" readonly="1"/></h1>
|
||||
</div>
|
||||
<div class="alert alert-info" role="alert">
|
||||
Образец блока воинского учёта. Данные собираются из
|
||||
карточек сотрудников (вкладка «Воинский учёт»).
|
||||
Состав форм и методику подсчёта уточните у специалиста.
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="kind"/>
|
||||
<field name="report_date"/>
|
||||
<field name="year"/>
|
||||
<field name="company_id"
|
||||
groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group string="Сводно">
|
||||
<field name="total_employees"/>
|
||||
<field name="total_reserve"/>
|
||||
<field name="total_booked"/>
|
||||
<field name="total_conscript"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="line_ids">
|
||||
<list editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="total"/>
|
||||
<field name="reserve_total"/>
|
||||
<field name="reserve_officer"/>
|
||||
<field name="reserve_soldier"/>
|
||||
<field name="booked_total"/>
|
||||
<field name="conscript_total"/>
|
||||
<field name="note"/>
|
||||
</list>
|
||||
</field>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_mil_report" model="ir.actions.act_window">
|
||||
<field name="name">Отчёты по ВУ</field>
|
||||
<field name="res_model">ruodoo.rsbu.mil.report</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user