Public release from ruodoo-project: 19.0 - 2026-05-31 21:19:12 UTC
This commit is contained in:
21
l10n_ru_attorney/README.md
Normal file
21
l10n_ru_attorney/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Российская локализация - Доверенность
|
||||
name: l10n_ru_attorney
|
||||
|
||||
## Описание
|
||||
Создание списка доверенностей на получение ТМЦ и их печать.
|
||||
|
||||
###Создание доверенности:
|
||||
1. Меню Покупки - Доверенности - кнопка "Создать";
|
||||
2. На форме указываем:
|
||||
|
||||
2.1. Контрагент - поставщик;
|
||||
|
||||
2.2. Заказ на закупку;
|
||||
|
||||
2.3. Даты действия доверенности ("дата выдачи" и "действительно по").
|
||||
|
||||
|
||||
###Для печати:
|
||||
1. Меню Настройки - Техническое - Отчеты;
|
||||
2. Находим в списке l10n_ru_attorney и добавляем в меню "Печать";
|
||||
3. Открываем созданную запись доверенности - Действие - "Доверенность".
|
||||
3
l10n_ru_attorney/__init__.py
Normal file
3
l10n_ru_attorney/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
45
l10n_ru_attorney/__manifest__.py
Normal file
45
l10n_ru_attorney/__manifest__.py
Normal file
@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': "Российская локализация - Доверенность",
|
||||
|
||||
'summary': """
|
||||
Печать доверенности на получение ТМЦ
|
||||
""",
|
||||
|
||||
'description': """
|
||||
Создание списка доверенностей на получение ТМЦ и их печать.
|
||||
|
||||
Создание доверенности:
|
||||
1. Меню Покупки - Доверенности - кнопка "Создать";
|
||||
2. На форме указываем:
|
||||
2.1. Контрагент - поставщик;
|
||||
2.2. Заказ на закупку;
|
||||
2.3. Даты действия доверенности ("дата выдачи" и "действительно по").
|
||||
|
||||
Для печати:
|
||||
1. Меню Настройки - Техническое - Отчеты;
|
||||
2. Находим в списке l10n_ru_attorney и добавляем в меню "Печать";
|
||||
3. Открываем созданную запись доверенности - Действие - "Доверенность".
|
||||
""",
|
||||
|
||||
'author': "MK.Lab",
|
||||
'website': "https://www.inf-centre.ru/",
|
||||
|
||||
'category': 'Uncategorized',
|
||||
'version': '0.1',
|
||||
|
||||
# any module necessary for this one to work correctly
|
||||
'depends': ['base', 'account', 'sale', 'purchase', 'hr', 'l10n_ru_base'],
|
||||
|
||||
# always loaded
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/base_consent_views.xml',
|
||||
'views/hr_employee_views.xml',
|
||||
'views/purchase_order_views.xml',
|
||||
'report/consent_report.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/demo.xml',
|
||||
],
|
||||
}
|
||||
36
l10n_ru_attorney/demo/demo.xml
Normal file
36
l10n_ru_attorney/demo/demo.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Демо партнёр-поставщик для доверенности -->
|
||||
<record id="demo_attorney_partner_supplier" model="res.partner">
|
||||
<field name="name">ООО "Снабжение Плюс"</field>
|
||||
<field name="is_company" eval="True"/>
|
||||
<field name="city">Москва</field>
|
||||
</record>
|
||||
|
||||
<!-- Демо сотрудник для доверенности -->
|
||||
<record id="demo_employee_ivanov" model="hr.employee">
|
||||
<field name="name">Иванов Иван Иванович</field>
|
||||
<field name="job_title">Менеджер по закупкам</field>
|
||||
</record>
|
||||
|
||||
<!-- Демо заказ на закупку -->
|
||||
<record id="demo_purchase_order_001" model="purchase.order">
|
||||
<field name="partner_id" ref="demo_attorney_partner_supplier"/>
|
||||
<field name="date_order">2026-01-15 10:00:00</field>
|
||||
</record>
|
||||
|
||||
<!-- Доверенность -->
|
||||
<record id="demo_consent_001" model="base.consent">
|
||||
<field name="name">ДОВ-2026-001</field>
|
||||
<field name="date_from">2026-01-15</field>
|
||||
<field name="date_to">2026-07-15</field>
|
||||
<field name="partner_id" ref="demo_attorney_partner_supplier"/>
|
||||
<field name="employee_id" ref="demo_employee_ivanov"/>
|
||||
<field name="purchaseorder_id" ref="demo_purchase_order_001"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
5
l10n_ru_attorney/models/__init__.py
Normal file
5
l10n_ru_attorney/models/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import base_consent
|
||||
from . import hr_employee
|
||||
from . import purchase_order
|
||||
48
l10n_ru_attorney/models/base_consent.py
Normal file
48
l10n_ru_attorney/models/base_consent.py
Normal file
@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
class BaseConsent(models.Model):
|
||||
_name = 'base.consent'
|
||||
_inherit = ['mail.thread', 'utm.mixin']
|
||||
_description = 'Consent'
|
||||
_order = 'date_from desc'
|
||||
|
||||
name = fields.Char(string=_('Номер'))
|
||||
date_from = fields.Date(string=_('Дата выдачи'), default=lambda self: fields.Datetime.now())
|
||||
date_to = fields.Date(string=_('Действительна по'), default=lambda self: datetime.today() + timedelta(days=180))
|
||||
partner_id = fields.Many2one('res.partner', string=_('Контрагент'), required=1)
|
||||
employee_id = fields.Many2one('hr.employee', string=_('Сотрудник'), required=1)
|
||||
purchaseorder_id = fields.Many2one('purchase.order', _('Заказ на закупку'), domain="[('partner_id','=',partner_id)]",
|
||||
required=1)
|
||||
company_id = fields.Many2one('res.company', string=_('Компания'),
|
||||
default=lambda self: self.env.company,
|
||||
required=1)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if not vals.get("name"):
|
||||
vals["name"] = self.env["ir.sequence"].next_by_code("base.consent")
|
||||
|
||||
records = super().create(vals_list)
|
||||
for record in records:
|
||||
if record.purchaseorder_id:
|
||||
record.purchaseorder_id.sudo().write({
|
||||
"consent_id": record.id
|
||||
})
|
||||
|
||||
return records
|
||||
|
||||
@api.onchange('purchaseorder_id')
|
||||
def set_partner(self):
|
||||
if self.purchaseorder_id:
|
||||
self.partner_id = self.purchaseorder_id.partner_id
|
||||
|
||||
@api.constrains('purchaseorder_id')
|
||||
def fill_order(self):
|
||||
p_orders = self.env['purchase.order'].sudo().browse(self.purchaseorder_id.id)
|
||||
for order in p_orders:
|
||||
order.consent_id = self.id
|
||||
11
l10n_ru_attorney/models/hr_employee.py
Normal file
11
l10n_ru_attorney/models/hr_employee.py
Normal file
@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import fields, models, _
|
||||
|
||||
|
||||
class HrEmployee(models.Model):
|
||||
_inherit = 'hr.employee'
|
||||
|
||||
inn = fields.Char(string=_("ИНН"))
|
||||
pass_kem = fields.Char(string=_("Кем выдан паспорт"))
|
||||
pass_date = fields.Date(string=_('Дата выдачи паспорта'))
|
||||
9
l10n_ru_attorney/models/purchase_order.py
Normal file
9
l10n_ru_attorney/models/purchase_order.py
Normal file
@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import fields, models, _
|
||||
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_inherit = 'purchase.order'
|
||||
|
||||
consent_id = fields.Many2one('base.consent', string=_('Доверенность'))
|
||||
305
l10n_ru_attorney/report/consent_report.xml
Normal file
305
l10n_ru_attorney/report/consent_report.xml
Normal file
@ -0,0 +1,305 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<report
|
||||
string="Доверенность"
|
||||
id="action_report_consent"
|
||||
model="base.consent"
|
||||
report_type="qweb-pdf"
|
||||
name="l10n_ru_attorney.report_consent"
|
||||
file="l10n_ru_attorney.report_consent"
|
||||
/>
|
||||
|
||||
<record model="ir.actions.report" id="l10n_ru_attorney.action_report_consent">
|
||||
<field name="name">Доверенность</field>
|
||||
<field name="model">base.consent</field>
|
||||
<field name="print_report_name">(u'Доверенность - %s.pdf' % (object.name))</field>
|
||||
<field name="binding_model_id" ref="model_base_consent"/>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">l10n_ru_attorney.report_consent</field>
|
||||
</record>
|
||||
|
||||
<record id="paperformat_a4new" model="report.paperformat">
|
||||
<field name="name">A4</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="format">A4</field>
|
||||
<field name="page_height">0</field>
|
||||
<field name="page_width">0</field>
|
||||
<field name="orientation">Portrait</field>
|
||||
<field name="margin_top">15</field>
|
||||
<field name="margin_bottom">15</field>
|
||||
<field name="margin_left">7</field>
|
||||
<field name="margin_right">7</field>
|
||||
<field name="header_line" eval="False"/>
|
||||
<field name="header_spacing">10</field>
|
||||
<field name="dpi">90</field>
|
||||
</record>
|
||||
|
||||
<template id="l10n_ru_attorney.report_consent">
|
||||
<t t-call="web.basic_layout">
|
||||
<t t-foreach="docs" t-as="o">
|
||||
<div class="page">
|
||||
<style type="text/css">
|
||||
/*----------------Invoice classes-------------------*/
|
||||
body { background: #ffffff; font-family: Arial; font-size: 8pt; font-style: normal; }
|
||||
p { font-family: Arial; font-size: 13px; }
|
||||
.tb-numbers { width: 600px; }
|
||||
.tb-numbers td { padding: 4px 10px; font-family: Arial; }
|
||||
.tb-numbers label {display: inline-block;padding: 4px 0px 0px;line-height: 20px;font-size:
|
||||
12px;font-family: Arial;}
|
||||
.tb-numbers input {width: 100px;}
|
||||
.company-info {width: 100%;margin: 20px auto;}
|
||||
.company-info td {padding: 5px 2px;font-size: 13px;font-family: Arial;}
|
||||
.approver-info {width: 100%;margin: 20px auto;text-align: center;}
|
||||
.approver-info .director {font-weight: bold;}
|
||||
.approver-info .title {font-weight: bold;font-size: 18px;padding-bottom: 20px;}
|
||||
.approver-info .signature {font-size: 11px;padding-top: 40px;}
|
||||
.actDate {float: right;}
|
||||
.actDescription {width: 100%;padding-top: 30px;}
|
||||
.act-info p {font-weight: bold;}
|
||||
.buyer-box {width: 50%;}
|
||||
.buyer-box table {width: 100%;}
|
||||
.buyer-box .tb-info {width: 310px;}
|
||||
.buyer-box .tb-info td {padding: 2px 5px;}
|
||||
.buyer-box .tb-info td.lbl {text-align: right;font-weight: bold;width: 40%;}
|
||||
.tb-invoice {width: 100%;border-collapse: collapse;}
|
||||
.tb-invoice td {padding: 2px 4px;border: 1px solid #ccc;font-size: 11px;text-align:
|
||||
center;font-family: Arial;}
|
||||
.tb-invoice td input {border: 0px;text-align: center;}
|
||||
.tb-invoice .head td {background: #f3f3f3;font-weight: bold;}
|
||||
.deleteRow {color: Red;font-size: 13px;font-weight: bold;cursor: pointer;}
|
||||
.tb-act {width: 100%;border-collapse: collapse;margin-bottom: 15px;clear: both;margin: 20px
|
||||
0px 10px 0px;}
|
||||
.tb-act td {padding: 2px 4px;border: 1px solid #ccc;font-size:
|
||||
13px;text-align:center;font-family: Arial;}
|
||||
.tb-act td input {border: 0px;text-align:center;}
|
||||
.tb-act .head td {background:#f3f3f3;}
|
||||
.tb-act td .deleteActRow {color: Red;font-size :13 px;font-weight:bold;cursor:pointer;}
|
||||
.description {font-size :12 px;text-align :justify;text-indent :1.5 em;white-space
|
||||
:pre-wrap;}
|
||||
.tb-total {width :405 px;margin: 30px 0px 20px auto;}
|
||||
.tb-total td {padding: 2px 5px;font-size :12 px;}
|
||||
.tb-total td.lbl {font-weight:bold;text-align:right;}
|
||||
.tb-total td.val {border :1 px solid #ccc ;min-width :50 px ;}
|
||||
.tb-total td input {padding :1 px ;font-size :11 px ;}
|
||||
.act-link-addrow-container {margin-bottom :30 px ;}
|
||||
.link-addrow, .act-link-addrow {text-decoration:none !important ;border-bottom :1 px dashed
|
||||
#777 ;font-size :13 px ;}
|
||||
.btn-box {margin: 10px 0px;}
|
||||
.signer-box {width: 400px;}
|
||||
.buyer-box .tb-info {width: 400px;}
|
||||
.btn-box a {font-size: 14px;margin-left: 10px;}
|
||||
.podpis-box {clear: both;display: inline-block;font-size: 11px;margin: 20px auto 30px;width:
|
||||
100%;}
|
||||
.tb-podpis {width: 100%;}
|
||||
.podpis-box .box1 {float: left;width: 48%;}
|
||||
|
||||
/*SIGNATURES PLACE BEGIN*/
|
||||
.signatures-box {clear: both;display: inline-block;font-size: 11px;margin: 20px auto
|
||||
30px;width: 100%;}
|
||||
.signatures-box .box1 {float: left;width: 35%;}
|
||||
.signatures-box .box2 {float: right;width: 35%;}
|
||||
.signatures-box .box1 table,
|
||||
.signatures-box .box2 table { width: 100%; }
|
||||
.signatures-box table td { padding: 3px; text-align: center; }
|
||||
|
||||
/*SIGNATURES PLACE END*/
|
||||
.podpis-box .box2 { float: right; width: 48%; }
|
||||
.podpis-box .box1 table,
|
||||
.podpis-box .box2 table { width: 100%; }
|
||||
.podpis-box table td { padding: 3px; text-align: center; }
|
||||
.special-line { border-bottom: 1px solid #000; display: block; line-height: 22px
|
||||
!important;text-align: center; }
|
||||
.w120 { width: 120px; }
|
||||
.w130 { width: 130px; }
|
||||
.note { font-size: 11px !important; }
|
||||
.l { text-align: left !important; }
|
||||
.r { text-align: right !important; }
|
||||
.c { text-align: center !important; }
|
||||
</style>
|
||||
|
||||
<div>
|
||||
<h4 style="text-align:center; margin:10px 5px 5px;">
|
||||
Доверенность №
|
||||
<span t-field="o.name"/>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<table style="width:55%">
|
||||
<tr>
|
||||
<td>Дата выдачи:</td>
|
||||
<td>
|
||||
<span t-field="o.date_from" t-options="{"widget": "date"}"/>
|
||||
г.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Доверенность действительна по:</td>
|
||||
<td>
|
||||
<span t-field="o.date_from" t-options="{"widget": "date"}"/>
|
||||
г.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="special-line" style="width:100%;margin-top:15px;text-align:center">
|
||||
<b>
|
||||
<span t-field="o.company_id.name"/>, адрес:<span t-field="o.company_id.street"/>, ИНН
|
||||
<span t-field="o.company_id.vat"/>,
|
||||
</b>
|
||||
</div>
|
||||
<div style="margin:0 auto;text-align:center;">наименование предприятия и его адрес</div>
|
||||
<table style="width:100%;margin-top:10px">
|
||||
<tr>
|
||||
<td style="width:30%">
|
||||
Доверенность выдана
|
||||
</td>
|
||||
<td style="width:100%;text-align:center;">
|
||||
<span style="border-bottom:1px solid;display:block;clear:both;text-align:center;">
|
||||
<span t-field="o.employee_id"/>,<span t-field="o.employee_id.job_id.name"/>, ИНН
|
||||
<span t-field="o.employee_id.inn"/>
|
||||
</span>
|
||||
<span style="">
|
||||
должность и Ф.И.О.
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<td>Паспорт серия и №
|
||||
|
||||
<span style="padding:0 5px 0 5px;margin-left:12px;margin-right:12px;display:inline-table;"
|
||||
class="special-line">
|
||||
<span t-field="o.employee_id.passport_id"/>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Кем выдан
|
||||
<span style="padding:0 5px 0 5px;margin-left:12px;margin-right:12px;display:inline-table;"
|
||||
class="special-line">
|
||||
<span t-field="o.employee_id.pass_kem"/>
|
||||
</span>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Дата выдачи
|
||||
<span style="padding:0 5px 0 5px;margin-left:12px;margin-right:12px;display:inline-table;"
|
||||
class="special-line">
|
||||
<span t-field="o.employee_id.pass_date"/>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<td style="width:25%">
|
||||
На получение от
|
||||
</td>
|
||||
<td style="width:75%;text-align:center;">
|
||||
<span style="border-bottom:1px solid;display:block;clear:both;">
|
||||
<span t-field="o.partner_id"/>
|
||||
</span>
|
||||
<span style="">
|
||||
наименование поставщика
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:25%">
|
||||
Материальных ценностей по
|
||||
</td>
|
||||
<td style="width:75%;text-align:center;">
|
||||
<span style="border-bottom:1px solid;display:block;clear:both;">
|
||||
Заказу на закупку №
|
||||
<span t-field="o.purchaseorder_id.name"/>
|
||||
от
|
||||
<span t-field="o.purchaseorder_id.date_order"
|
||||
t-options="{"widget": "date"}"/>
|
||||
г.
|
||||
</span>
|
||||
<span style="">
|
||||
наименование, номер и дата документа
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div>
|
||||
<h4 style="text-align:center; margin:15px 5px 15px;">
|
||||
Перечень материальных ценностей,
|
||||
<br/>
|
||||
подлежащих получению
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<table class="tb-invoice">
|
||||
<tr class="head">
|
||||
<td></td>
|
||||
<td style="min-width:200px;">Наименование товаров (работ, услуг)</td>
|
||||
<td>Ед. изм.</td>
|
||||
<td>Количество</td>
|
||||
</tr>
|
||||
<t t-set="num" t-value="1"/>
|
||||
<t t-foreach="o.purchaseorder_id.order_line" t-as="line">
|
||||
<tr class="data-row">
|
||||
<td>
|
||||
<t t-esc="num"/>
|
||||
</td>
|
||||
<td class="l" style="white-space: pre-wrap;">
|
||||
<span t-field="line.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="line.product_uom_id.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="line.product_qty"/>
|
||||
</td>
|
||||
</tr>
|
||||
<t t-set="num" t-value="num+1"/>
|
||||
</t>
|
||||
</table>
|
||||
|
||||
<div class="clear h100"></div>
|
||||
<div>
|
||||
<p></p>
|
||||
<p>Подпись лица, получившего доверенность ___________________ удостоверяем</p>
|
||||
</div>
|
||||
<div class="podpis-box">
|
||||
<table style="width:50%;">
|
||||
<tr>
|
||||
<td style="width: 13%;">Руководитель предприятия</td>
|
||||
<td style="width: 19%; vertical-align: bottom;">
|
||||
<span class="special-line"></span>
|
||||
<span class="note">(подпись)</span>
|
||||
</td>
|
||||
<td style="width: 16%; vertical-align: bottom;">
|
||||
<span class="special-line"></span>
|
||||
<span class="note">(Ф.И.О)</span>
|
||||
</td>
|
||||
<!-- <td style="width: 16%; vertical-align: bottom;"></td>-->
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 13%;">Гл. бухгалтер:</td>
|
||||
<td style="width: 19%; vertical-align: bottom;">
|
||||
<span class="special-line"></span>
|
||||
<span class="note">(подпись)</span>
|
||||
</td>
|
||||
<td style="width: 16%; vertical-align: bottom;">
|
||||
<span class="special-line"></span>
|
||||
<span class="note">(Ф.И.О)</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
</odoo>
|
||||
2
l10n_ru_attorney/security/ir.model.access.csv
Normal file
2
l10n_ru_attorney/security/ir.model.access.csv
Normal file
@ -0,0 +1,2 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_base_consent,base.consent,model_base_consent,base.group_user,1,1,1,1
|
||||
|
2
l10n_ru_attorney/tests/__init__.py
Normal file
2
l10n_ru_attorney/tests/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import test_base_consent
|
||||
136
l10n_ru_attorney/tests/test_base_consent.py
Normal file
136
l10n_ru_attorney/tests/test_base_consent.py
Normal file
@ -0,0 +1,136 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Tests for l10n_ru_attorney — attorney (base.consent) creation, autonumbering,
|
||||
and linkage to purchase orders.
|
||||
|
||||
Validates: Requirements 17.1, 17.2, 17.3
|
||||
"""
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _make_partner(env):
|
||||
"""Create a company partner (supplier)."""
|
||||
return env['res.partner'].create({
|
||||
'name': 'Test Supplier Attorney',
|
||||
'is_company': True,
|
||||
})
|
||||
|
||||
|
||||
def _make_employee(env):
|
||||
"""Create a minimal hr.employee."""
|
||||
return env['hr.employee'].create({
|
||||
'name': 'Test Employee Attorney',
|
||||
})
|
||||
|
||||
|
||||
def _make_purchase_order(env, partner):
|
||||
"""Create a minimal purchase.order."""
|
||||
return env['purchase.order'].create({
|
||||
'partner_id': partner.id,
|
||||
})
|
||||
|
||||
|
||||
def _make_consent(env, partner, employee, purchase_order, name=None):
|
||||
"""Create a base.consent record."""
|
||||
vals = {
|
||||
'partner_id': partner.id,
|
||||
'employee_id': employee.id,
|
||||
'purchaseorder_id': purchase_order.id,
|
||||
}
|
||||
if name:
|
||||
vals['name'] = name
|
||||
return env['base.consent'].create(vals)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TestBaseConsent
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestBaseConsent(TransactionCase):
|
||||
"""
|
||||
Tests for base.consent creation: autonumbering via ir.sequence,
|
||||
write-back of consent_id to purchase.order, and fill_order constraint.
|
||||
|
||||
Validates: Requirements 17.1, 17.2, 17.3
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.partner = _make_partner(self.env)
|
||||
self.employee = _make_employee(self.env)
|
||||
self.purchase_order = _make_purchase_order(self.env, self.partner)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Requirement 17.1 — autonumber via ir.sequence when name is absent
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_create_autonumber(self):
|
||||
"""
|
||||
Req 17.1 — creating base.consent without a name assigns a number
|
||||
via ir.sequence with code 'base.consent'.
|
||||
"""
|
||||
consent = _make_consent(
|
||||
self.env, self.partner, self.employee, self.purchase_order
|
||||
)
|
||||
self.assertTrue(
|
||||
consent.name,
|
||||
"consent.name should be set automatically via ir.sequence",
|
||||
)
|
||||
# A manually-supplied name must be preserved as-is
|
||||
consent2 = _make_consent(
|
||||
self.env, self.partner, self.employee, self.purchase_order,
|
||||
name='MANUAL-001',
|
||||
)
|
||||
self.assertEqual(
|
||||
consent2.name, 'MANUAL-001',
|
||||
"Explicitly supplied name should not be overwritten",
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Requirement 17.2 — purchase.order.consent_id set after create
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_create_writes_back_to_purchase_order(self):
|
||||
"""
|
||||
Req 17.2 — after creating base.consent linked to a purchase.order,
|
||||
purchase.order.consent_id equals the created consent.
|
||||
"""
|
||||
consent = _make_consent(
|
||||
self.env, self.partner, self.employee, self.purchase_order
|
||||
)
|
||||
self.purchase_order.invalidate_recordset()
|
||||
self.assertEqual(
|
||||
self.purchase_order.consent_id.id,
|
||||
consent.id,
|
||||
"purchase.order.consent_id should be set to the created consent",
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Requirement 17.3 — fill_order constraint writes consent_id to order
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_constrains_fill_order(self):
|
||||
"""
|
||||
Req 17.3 — the @api.constrains('purchaseorder_id') method fill_order
|
||||
writes consent_id into the linked purchase.order.
|
||||
"""
|
||||
# Create a second purchase order to reassign to
|
||||
second_order = _make_purchase_order(self.env, self.partner)
|
||||
|
||||
consent = _make_consent(
|
||||
self.env, self.partner, self.employee, self.purchase_order
|
||||
)
|
||||
|
||||
# Reassign to second_order — this triggers fill_order constraint
|
||||
consent.write({'purchaseorder_id': second_order.id})
|
||||
|
||||
second_order.invalidate_recordset()
|
||||
self.assertEqual(
|
||||
second_order.consent_id.id,
|
||||
consent.id,
|
||||
"fill_order should write consent_id into the newly assigned purchase.order",
|
||||
)
|
||||
62
l10n_ru_attorney/views/base_consent_views.xml
Normal file
62
l10n_ru_attorney/views/base_consent_views.xml
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="base_consent_tree" model="ir.ui.view">
|
||||
<field name="name">Consents</field>
|
||||
<field name="model">base.consent</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="base_consent_form" model="ir.ui.view">
|
||||
<field name="name">consent.form</field>
|
||||
<field name="model">base.consent</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header></header>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" placeholder="Для автонумерации оставьте пустым"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="employee_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date_from"/>
|
||||
<field name="date_to"/>
|
||||
<field name="purchaseorder_id"/>
|
||||
<field name="company_id"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="l10n_ru_attorney.action_consent" model="ir.actions.act_window">
|
||||
<field name="name">Доверенности</field>
|
||||
<field name="res_model">base.consent</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="l10n_ru_attorney.menu_1" name="Доверенности" parent="purchase.menu_purchase_root"
|
||||
action="l10n_ru_attorney.action_consent"/>
|
||||
|
||||
<record id="seq_consent" model="ir.sequence">
|
||||
<field name="name">Consents</field>
|
||||
<field name="code">base.consent</field>
|
||||
<field name="prefix">CON</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
19
l10n_ru_attorney/views/hr_employee_views.xml
Normal file
19
l10n_ru_attorney/views/hr_employee_views.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="view_employee_form" model="ir.ui.view">
|
||||
<field name="name">view_employee_form.inherit</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="inherit_id" ref="hr.view_employee_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='bank_account_ids']" position="after">
|
||||
<field name="inn"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='passport_id']" position="after">
|
||||
<field name="pass_kem"/>
|
||||
<field name="pass_date"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
16
l10n_ru_attorney/views/purchase_order_views.xml
Normal file
16
l10n_ru_attorney/views/purchase_order_views.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="purchase_order_form" model="ir.ui.view">
|
||||
<field name="name">purchase.order.form.inherit</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='currency_id']" position="after">
|
||||
<field name="consent_id" context="{'default_partner_id':partner_id,'default_purchaseorder_id':id}"
|
||||
domain="[('purchaseorder_id','=',id)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user