From f0659575dd0fdc99455d6497ea9bac53c3da4b35 Mon Sep 17 00:00:00 2001 From: Sergey Korobkov Date: Fri, 17 Jan 2025 20:46:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=BE=D1=81=D1=81=D0=B8=D0=B9=D1=81?= =?UTF-8?q?=D0=BA=D0=B0=D1=8F=20=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20v17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- l10n_ru_act_rev/README.md | 14 + l10n_ru_act_rev/__init__.py | 4 + l10n_ru_act_rev/__manifest__.py | 45 + l10n_ru_act_rev/controllers/__init__.py | 3 + l10n_ru_act_rev/controllers/controllers.py | 89 ++ l10n_ru_act_rev/demo/demo.xml | 30 + l10n_ru_act_rev/models/__init__.py | 2 + l10n_ru_act_rev/models/account_account.py | 7 + l10n_ru_act_rev/models/ir_actions_report.py | 10 + l10n_ru_act_rev/report/__init__.py | 2 + l10n_ru_act_rev/report/general_ledger.py | 1045 +++++++++++++++ l10n_ru_act_rev/report/general_ledger.xml | 286 ++++ l10n_ru_act_rev/report/layouts.xml | 34 + l10n_ru_act_rev/security/ir.model.access.csv | 2 + .../views/account_account_views.xml | 14 + l10n_ru_act_rev/views/portal_templates.xml | 12 + .../views/report_general_ledger.xml | 9 + l10n_ru_act_rev/wizard/__init__.py | 2 + l10n_ru_act_rev/wizard/abstract_wizard.py | 38 + .../wizard/general_ledger_wizard.py | 898 +++++++++++++ .../wizard/general_ledger_wizard_view.xml | 167 +++ l10n_ru_attorney/README.md | 21 + l10n_ru_attorney/__init__.py | 3 + l10n_ru_attorney/__manifest__.py | 42 + l10n_ru_attorney/models/__init__.py | 5 + l10n_ru_attorney/models/base_consent.py | 46 + l10n_ru_attorney/models/hr_employee.py | 11 + l10n_ru_attorney/models/purchase_order.py | 9 + l10n_ru_attorney/report/consent_report.xml | 560 ++++++++ l10n_ru_attorney/security/ir.model.access.csv | 2 + l10n_ru_attorney/views/base_consent_views.xml | 65 + l10n_ru_attorney/views/hr_employee_views.xml | 19 + .../views/purchase_order_views.xml | 16 + l10n_ru_base/README.md | 16 + l10n_ru_base/__init__.py | 2 + l10n_ru_base/__manifest__.py | 28 + l10n_ru_base/i18n/ru_RU.po | 109 ++ l10n_ru_base/models/__init__.py | 4 + l10n_ru_base/models/res_config_settings.py | 41 + l10n_ru_base/static/description/icon.png | Bin 0 -> 4308 bytes .../views/res_config_settings_views.xml | 42 + l10n_ru_contract/__init__.py | 3 + l10n_ru_contract/__manifest__.py | 25 + l10n_ru_contract/data/data.xml | 21 + l10n_ru_contract/models/__init__.py | 2 + l10n_ru_contract/models/contract_customer.py | 334 +++++ .../models/crutch_fields_header.py | 33 + l10n_ru_contract/models/dop_field.py | 353 +++++ l10n_ru_contract/models/invoice_saleorder.py | 128 ++ l10n_ru_contract/report/__init__.py | 2 + l10n_ru_contract/report/report_contract.py | 14 + l10n_ru_contract/report/report_contract.xml | 398 ++++++ .../report/report_contract_invoce.py | 15 + .../report/report_contract_invoce.xml | 592 +++++++++ .../report/report_contract_order.py | 18 + .../report/report_contract_order.xml | 594 +++++++++ .../report/report_contract_order1.xml | 406 ++++++ l10n_ru_contract/security/ir.model.access.csv | 6 + .../views/contract_customer_view.xml | 358 +++++ l10n_ru_doc/__init__.py | 5 + l10n_ru_doc/__manifest__.py | 51 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 240 bytes .../__pycache__/report_helper.cpython-310.pyc | Bin 0 -> 3752 bytes l10n_ru_doc/demo/l10n_ru_doc_demo.xml | 63 + l10n_ru_doc/i18n/ru.po | 116 ++ l10n_ru_doc/models/__init__.py | 12 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 471 bytes .../account_invoice.cpython-310.pyc | Bin 0 -> 5013 bytes .../account_move_line.cpython-310.pyc | Bin 0 -> 1437 bytes .../__pycache__/product.cpython-310.pyc | Bin 0 -> 461 bytes .../__pycache__/res_bank.cpython-310.pyc | Bin 0 -> 980 bytes .../__pycache__/res_company.cpython-310.pyc | Bin 0 -> 1075 bytes .../__pycache__/res_partner.cpython-310.pyc | Bin 0 -> 767 bytes .../__pycache__/res_users.cpython-310.pyc | Bin 0 -> 507 bytes .../models/__pycache__/sale.cpython-310.pyc | Bin 0 -> 773 bytes .../models/__pycache__/tax.cpython-310.pyc | Bin 0 -> 462 bytes .../models/__pycache__/uom.cpython-310.pyc | Bin 0 -> 464 bytes l10n_ru_doc/models/account_invoice.py | 144 ++ l10n_ru_doc/models/account_move_line.py | 29 + l10n_ru_doc/models/product.py | 5 + l10n_ru_doc/models/res_bank.py | 19 + l10n_ru_doc/models/res_company.py | 18 + l10n_ru_doc/models/res_partner.py | 11 + l10n_ru_doc/models/res_users.py | 7 + l10n_ru_doc/models/sale.py | 8 + l10n_ru_doc/models/tax.py | 6 + l10n_ru_doc/models/uom.py | 4 + l10n_ru_doc/report/__init__.py | 5 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 325 bytes .../__pycache__/report_act.cpython-310.pyc | Bin 0 -> 758 bytes .../__pycache__/report_bill.cpython-310.pyc | Bin 0 -> 762 bytes .../report_invoice.cpython-310.pyc | Bin 0 -> 774 bytes .../__pycache__/report_order.cpython-310.pyc | Bin 0 -> 772 bytes .../__pycache__/report_upd.cpython-310.pyc | Bin 0 -> 1018 bytes l10n_ru_doc/report/l10n_ru_doc_report.xml | 107 ++ l10n_ru_doc/report/report_act.py | 16 + l10n_ru_doc/report/report_act.xml | 203 +++ l10n_ru_doc/report/report_bill.py | 14 + l10n_ru_doc/report/report_bill.xml | 758 +++++++++++ l10n_ru_doc/report/report_invoice.py | 13 + l10n_ru_doc/report/report_invoice.xml | 329 +++++ l10n_ru_doc/report/report_order.py | 13 + l10n_ru_doc/report/report_order.xml | 330 +++++ l10n_ru_doc/report/report_upd.py | 24 + l10n_ru_doc/report/report_upd.xml | 1108 ++++++++++++++++ l10n_ru_doc/report/report_updn.xml | 1177 +++++++++++++++++ l10n_ru_doc/report_helper.py | 112 ++ l10n_ru_doc/static/description/docs.png | Bin 0 -> 16383 bytes l10n_ru_doc/static/description/icon.png | Bin 0 -> 12456 bytes l10n_ru_doc/static/description/index.html | 45 + l10n_ru_doc/static/description/support.png | Bin 0 -> 20040 bytes l10n_ru_doc/static/description/waybill.png | Bin 0 -> 16671 bytes l10n_ru_doc/static/src/css/l10n_ru_doc.css | 7 + l10n_ru_doc/views/account_invoice_view.xml | 36 + l10n_ru_doc/views/l10n_ru_doc_data.xml | 14 + l10n_ru_doc/views/product.xml | 16 + l10n_ru_doc/views/res_bank_view.xml | 18 + l10n_ru_doc/views/res_company_view.xml | 42 + l10n_ru_doc/views/res_partner_view.xml | 36 + l10n_ru_doc/views/res_users_view.xml | 33 + l10n_ru_doc/views/tax.xml | 17 + l10n_ru_doc/views/uom.xml | 28 + l10n_ru_upd_xml/__init__.py | 5 + l10n_ru_upd_xml/__manifest__.py | 51 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 235 bytes l10n_ru_upd_xml/controllers/__init__.py | 3 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 188 bytes .../__pycache__/controllers.cpython-310.pyc | Bin 0 -> 3152 bytes l10n_ru_upd_xml/controllers/controllers.py | 91 ++ l10n_ru_upd_xml/demo/demo.xml | 30 + l10n_ru_upd_xml/models/__init__.py | 8 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 347 bytes .../ir_actions_report.cpython-310.pyc | Bin 0 -> 2058 bytes .../models/__pycache__/move.cpython-310.pyc | Bin 0 -> 8560 bytes .../__pycache__/res_company.cpython-310.pyc | Bin 0 -> 471 bytes .../__pycache__/res_partner.cpython-310.pyc | Bin 0 -> 1191 bytes .../__pycache__/res_users.cpython-310.pyc | Bin 0 -> 988 bytes .../__pycache__/uom_okei.cpython-310.pyc | Bin 0 -> 706 bytes l10n_ru_upd_xml/models/ir_actions_report.py | 65 + l10n_ru_upd_xml/models/move.py | 209 +++ l10n_ru_upd_xml/models/res_company.py | 6 + l10n_ru_upd_xml/models/res_partner.py | 33 + l10n_ru_upd_xml/models/res_users.py | 25 + l10n_ru_upd_xml/models/uom_okei.py | 12 + l10n_ru_upd_xml/reports/__init__.py | 3 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 209 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 199 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 186 bytes ...report_report_xml_abstract.cpython-310.pyc | Bin 0 -> 1747 bytes .../report_report_xml_abstract.cpython-36.pyc | Bin 0 -> 1719 bytes .../report_report_xml_abstract.cpython-37.pyc | Bin 0 -> 1696 bytes l10n_ru_upd_xml/reports/report.xml | 14 + .../reports/report_report_xml_abstract.py | 48 + l10n_ru_upd_xml/reports/upd_report.xml | 186 +++ l10n_ru_upd_xml/security/ir.model.access.csv | 2 + .../src/js/report/action_manager_report.js | 49 + .../views/ir_actions_report_view.xml | 24 + l10n_ru_upd_xml/views/res_company_view.xml | 19 + l10n_ru_upd_xml/views/res_partner_view.xml | 26 + l10n_ru_upd_xml/views/res_users_view.xml | 21 + l10n_ru_upd_xml/views/view_move.xml | 17 + l10n_ru_upd_xml/views/views_uom_okei.xml | 30 + 162 files changed, 13032 insertions(+) create mode 100644 l10n_ru_act_rev/README.md create mode 100644 l10n_ru_act_rev/__init__.py create mode 100644 l10n_ru_act_rev/__manifest__.py create mode 100644 l10n_ru_act_rev/controllers/__init__.py create mode 100644 l10n_ru_act_rev/controllers/controllers.py create mode 100644 l10n_ru_act_rev/demo/demo.xml create mode 100644 l10n_ru_act_rev/models/__init__.py create mode 100644 l10n_ru_act_rev/models/account_account.py create mode 100644 l10n_ru_act_rev/models/ir_actions_report.py create mode 100644 l10n_ru_act_rev/report/__init__.py create mode 100644 l10n_ru_act_rev/report/general_ledger.py create mode 100644 l10n_ru_act_rev/report/general_ledger.xml create mode 100644 l10n_ru_act_rev/report/layouts.xml create mode 100644 l10n_ru_act_rev/security/ir.model.access.csv create mode 100644 l10n_ru_act_rev/views/account_account_views.xml create mode 100644 l10n_ru_act_rev/views/portal_templates.xml create mode 100644 l10n_ru_act_rev/views/report_general_ledger.xml create mode 100644 l10n_ru_act_rev/wizard/__init__.py create mode 100644 l10n_ru_act_rev/wizard/abstract_wizard.py create mode 100644 l10n_ru_act_rev/wizard/general_ledger_wizard.py create mode 100644 l10n_ru_act_rev/wizard/general_ledger_wizard_view.xml create mode 100644 l10n_ru_attorney/README.md create mode 100644 l10n_ru_attorney/__init__.py create mode 100644 l10n_ru_attorney/__manifest__.py create mode 100644 l10n_ru_attorney/models/__init__.py create mode 100644 l10n_ru_attorney/models/base_consent.py create mode 100644 l10n_ru_attorney/models/hr_employee.py create mode 100644 l10n_ru_attorney/models/purchase_order.py create mode 100644 l10n_ru_attorney/report/consent_report.xml create mode 100644 l10n_ru_attorney/security/ir.model.access.csv create mode 100644 l10n_ru_attorney/views/base_consent_views.xml create mode 100644 l10n_ru_attorney/views/hr_employee_views.xml create mode 100644 l10n_ru_attorney/views/purchase_order_views.xml create mode 100644 l10n_ru_base/README.md create mode 100644 l10n_ru_base/__init__.py create mode 100644 l10n_ru_base/__manifest__.py create mode 100644 l10n_ru_base/i18n/ru_RU.po create mode 100644 l10n_ru_base/models/__init__.py create mode 100644 l10n_ru_base/models/res_config_settings.py create mode 100644 l10n_ru_base/static/description/icon.png create mode 100644 l10n_ru_base/views/res_config_settings_views.xml create mode 100644 l10n_ru_contract/__init__.py create mode 100644 l10n_ru_contract/__manifest__.py create mode 100644 l10n_ru_contract/data/data.xml create mode 100644 l10n_ru_contract/models/__init__.py create mode 100644 l10n_ru_contract/models/contract_customer.py create mode 100644 l10n_ru_contract/models/crutch_fields_header.py create mode 100644 l10n_ru_contract/models/dop_field.py create mode 100644 l10n_ru_contract/models/invoice_saleorder.py create mode 100644 l10n_ru_contract/report/__init__.py create mode 100644 l10n_ru_contract/report/report_contract.py create mode 100644 l10n_ru_contract/report/report_contract.xml create mode 100644 l10n_ru_contract/report/report_contract_invoce.py create mode 100644 l10n_ru_contract/report/report_contract_invoce.xml create mode 100644 l10n_ru_contract/report/report_contract_order.py create mode 100644 l10n_ru_contract/report/report_contract_order.xml create mode 100644 l10n_ru_contract/report/report_contract_order1.xml create mode 100644 l10n_ru_contract/security/ir.model.access.csv create mode 100644 l10n_ru_contract/views/contract_customer_view.xml create mode 100644 l10n_ru_doc/__init__.py create mode 100644 l10n_ru_doc/__manifest__.py create mode 100644 l10n_ru_doc/__pycache__/__init__.cpython-310.pyc create mode 100644 l10n_ru_doc/__pycache__/report_helper.cpython-310.pyc create mode 100644 l10n_ru_doc/demo/l10n_ru_doc_demo.xml create mode 100644 l10n_ru_doc/i18n/ru.po create mode 100644 l10n_ru_doc/models/__init__.py create mode 100644 l10n_ru_doc/models/__pycache__/__init__.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/account_invoice.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/account_move_line.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/product.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/res_bank.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/res_company.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/res_partner.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/res_users.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/sale.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/tax.cpython-310.pyc create mode 100644 l10n_ru_doc/models/__pycache__/uom.cpython-310.pyc create mode 100644 l10n_ru_doc/models/account_invoice.py create mode 100644 l10n_ru_doc/models/account_move_line.py create mode 100644 l10n_ru_doc/models/product.py create mode 100644 l10n_ru_doc/models/res_bank.py create mode 100644 l10n_ru_doc/models/res_company.py create mode 100644 l10n_ru_doc/models/res_partner.py create mode 100644 l10n_ru_doc/models/res_users.py create mode 100644 l10n_ru_doc/models/sale.py create mode 100644 l10n_ru_doc/models/tax.py create mode 100644 l10n_ru_doc/models/uom.py create mode 100644 l10n_ru_doc/report/__init__.py create mode 100644 l10n_ru_doc/report/__pycache__/__init__.cpython-310.pyc create mode 100644 l10n_ru_doc/report/__pycache__/report_act.cpython-310.pyc create mode 100644 l10n_ru_doc/report/__pycache__/report_bill.cpython-310.pyc create mode 100644 l10n_ru_doc/report/__pycache__/report_invoice.cpython-310.pyc create mode 100644 l10n_ru_doc/report/__pycache__/report_order.cpython-310.pyc create mode 100644 l10n_ru_doc/report/__pycache__/report_upd.cpython-310.pyc create mode 100644 l10n_ru_doc/report/l10n_ru_doc_report.xml create mode 100644 l10n_ru_doc/report/report_act.py create mode 100644 l10n_ru_doc/report/report_act.xml create mode 100644 l10n_ru_doc/report/report_bill.py create mode 100644 l10n_ru_doc/report/report_bill.xml create mode 100644 l10n_ru_doc/report/report_invoice.py create mode 100644 l10n_ru_doc/report/report_invoice.xml create mode 100644 l10n_ru_doc/report/report_order.py create mode 100644 l10n_ru_doc/report/report_order.xml create mode 100644 l10n_ru_doc/report/report_upd.py create mode 100644 l10n_ru_doc/report/report_upd.xml create mode 100644 l10n_ru_doc/report/report_updn.xml create mode 100644 l10n_ru_doc/report_helper.py create mode 100644 l10n_ru_doc/static/description/docs.png create mode 100644 l10n_ru_doc/static/description/icon.png create mode 100644 l10n_ru_doc/static/description/index.html create mode 100644 l10n_ru_doc/static/description/support.png create mode 100644 l10n_ru_doc/static/description/waybill.png create mode 100644 l10n_ru_doc/static/src/css/l10n_ru_doc.css create mode 100644 l10n_ru_doc/views/account_invoice_view.xml create mode 100644 l10n_ru_doc/views/l10n_ru_doc_data.xml create mode 100644 l10n_ru_doc/views/product.xml create mode 100644 l10n_ru_doc/views/res_bank_view.xml create mode 100644 l10n_ru_doc/views/res_company_view.xml create mode 100644 l10n_ru_doc/views/res_partner_view.xml create mode 100644 l10n_ru_doc/views/res_users_view.xml create mode 100644 l10n_ru_doc/views/tax.xml create mode 100644 l10n_ru_doc/views/uom.xml create mode 100644 l10n_ru_upd_xml/__init__.py create mode 100644 l10n_ru_upd_xml/__manifest__.py create mode 100644 l10n_ru_upd_xml/__pycache__/__init__.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/controllers/__init__.py create mode 100644 l10n_ru_upd_xml/controllers/__pycache__/__init__.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/controllers/__pycache__/controllers.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/controllers/controllers.py create mode 100644 l10n_ru_upd_xml/demo/demo.xml create mode 100644 l10n_ru_upd_xml/models/__init__.py create mode 100644 l10n_ru_upd_xml/models/__pycache__/__init__.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/models/__pycache__/ir_actions_report.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/models/__pycache__/move.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/models/__pycache__/res_company.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/models/__pycache__/res_partner.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/models/__pycache__/res_users.cpython-310.pyc create mode 100644 l10n_ru_upd_xml/models/__pycache__/uom_okei.cpython-310.pyc create mode 100755 l10n_ru_upd_xml/models/ir_actions_report.py create mode 100755 l10n_ru_upd_xml/models/move.py create mode 100755 l10n_ru_upd_xml/models/res_company.py create mode 100755 l10n_ru_upd_xml/models/res_partner.py create mode 100755 l10n_ru_upd_xml/models/res_users.py create mode 100755 l10n_ru_upd_xml/models/uom_okei.py create mode 100755 l10n_ru_upd_xml/reports/__init__.py create mode 100644 l10n_ru_upd_xml/reports/__pycache__/__init__.cpython-310.pyc create mode 100755 l10n_ru_upd_xml/reports/__pycache__/__init__.cpython-36.pyc create mode 100755 l10n_ru_upd_xml/reports/__pycache__/__init__.cpython-37.pyc create mode 100644 l10n_ru_upd_xml/reports/__pycache__/report_report_xml_abstract.cpython-310.pyc create mode 100755 l10n_ru_upd_xml/reports/__pycache__/report_report_xml_abstract.cpython-36.pyc create mode 100755 l10n_ru_upd_xml/reports/__pycache__/report_report_xml_abstract.cpython-37.pyc create mode 100755 l10n_ru_upd_xml/reports/report.xml create mode 100755 l10n_ru_upd_xml/reports/report_report_xml_abstract.py create mode 100755 l10n_ru_upd_xml/reports/upd_report.xml create mode 100644 l10n_ru_upd_xml/security/ir.model.access.csv create mode 100755 l10n_ru_upd_xml/static/src/js/report/action_manager_report.js create mode 100755 l10n_ru_upd_xml/views/ir_actions_report_view.xml create mode 100755 l10n_ru_upd_xml/views/res_company_view.xml create mode 100755 l10n_ru_upd_xml/views/res_partner_view.xml create mode 100755 l10n_ru_upd_xml/views/res_users_view.xml create mode 100755 l10n_ru_upd_xml/views/view_move.xml create mode 100755 l10n_ru_upd_xml/views/views_uom_okei.xml diff --git a/l10n_ru_act_rev/README.md b/l10n_ru_act_rev/README.md new file mode 100644 index 0000000..101fe21 --- /dev/null +++ b/l10n_ru_act_rev/README.md @@ -0,0 +1,14 @@ +# Российская локализация - Акт сверки +name: l10n_ru_act_rev + + +## Описание +Добавление печатной формы акт сверки из контактов, с помощью которой можно легко отслеживать дебеторские и кредиторские проводки с клиентами. + +### Для печати: +1. Выбираем меню Контакты - карточку конкретного партнера - Действия - "Печать акт сверки"; +2. В визарде выбираем: + 2.1. Компанию (для которой нужна сверка с выбранным контактом); + 2.2. Период сверки; + 2.3. Цель (один из режимом: все проведенные проводки или все проводки, включая черновики); +3. Кнопка "Печать" \ No newline at end of file diff --git a/l10n_ru_act_rev/__init__.py b/l10n_ru_act_rev/__init__.py new file mode 100644 index 0000000..778f647 --- /dev/null +++ b/l10n_ru_act_rev/__init__.py @@ -0,0 +1,4 @@ +from . import models +from . import report +from . import wizard +from . import controllers diff --git a/l10n_ru_act_rev/__manifest__.py b/l10n_ru_act_rev/__manifest__.py new file mode 100644 index 0000000..840b9e8 --- /dev/null +++ b/l10n_ru_act_rev/__manifest__.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Российская локализация - Акт сверки", + + 'summary': """ + Добавление отчета акт сверки""", + + 'description': """ + Добавление формы акт сверки, находящегося в контактах, с помощью которого можно легко отслеживать дебеторские и кредиторские проводки с клиентами. + + Для печати: + 1. Выбираем меню Контакты - конкретного партнера - Действия - "Печать акт сверки"; + 2. В визарде выбираем: + 2.1. Компанию (для которой нужна сверка с выбранным контактом); + 2.2. Период сверки; + 2.3. Цель (один из режимом: все проведенные проводки или все проводки, включая черновики); + 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": ["account", "portal", "website", 'contacts', "l10n_ru_doc", 'l10n_ru_contract', 'l10n_ru_base'], + "data": [ + "security/ir.model.access.csv", + "wizard/general_ledger_wizard_view.xml", + "report/layouts.xml", + "report/general_ledger.xml", + "views/account_account_views.xml", + "views/report_general_ledger.xml", + "views/portal_templates.xml", + ], + "installable": True, + "application": True, + "auto_install": False, + # only loaded in demonstration mode + 'demo': [ + 'demo/demo.xml', + ], +} diff --git a/l10n_ru_act_rev/controllers/__init__.py b/l10n_ru_act_rev/controllers/__init__.py new file mode 100644 index 0000000..457bae2 --- /dev/null +++ b/l10n_ru_act_rev/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers \ No newline at end of file diff --git a/l10n_ru_act_rev/controllers/controllers.py b/l10n_ru_act_rev/controllers/controllers.py new file mode 100644 index 0000000..86e717e --- /dev/null +++ b/l10n_ru_act_rev/controllers/controllers.py @@ -0,0 +1,89 @@ +from odoo import http +from odoo.http import request +from datetime import datetime, date + + +class ActRevise(http.Controller): + + @http.route(['/my/act_revise/'], type='http', auth="public", website=True) + def print_report(self): + partner = request.env.user.partner_id.parent_id.id + partner_name = request.env.user.partner_id.parent_id.name + if not partner: + partner = request.env.user.partner_id.id + partner_name = request.env.user.partner_id.name + company = request.env.user.company_id.id + company_name = request.env.user.company_id.name + today = date.today() + d1 = today.strftime("%d.%m.%y") + + wizard_data = { + "target_move": "posted", + "hide_account_at_0": True, + "foreign_currency": True, + "company_id": company, + "partner_ids": [partner], + "show_cost_center": True, + "centralize": True + } + wizard_record = request.env['general.ledger.act_revise.wizard'].sudo().create(wizard_data) + + action = request.env.ref('l10n_ru_act_rev.action_general_ledger_wizard').read()[0] + action['res_id'] = wizard_record.id + action['context'] = dict(request.env.context) + return request.redirect('/web#action=' + str(action['id']) + '&id=' + str(wizard_record.id) + '&view_type=form') + + # @http.route(['/my/act_revise/'], type='http', auth="public", website=True) + # def print_report(self): + # partner = request.env.user.partner_id.parent_id.id + # partner_name = request.env.user.partner_id.parent_id.name + # if not partner: + # partner = request.env.user.partner_id.id + # partner_name = request.env.user.partner_id.name + # company = request.env.user.company_id.id + # company_name = request.env.user.company_id.name + # today = date.today() + # d1 = today.strftime("%d.%m.%y") + # # new_url = str('Акт Сверки ' + d1 + ' ' + company_name + '_' + partner_name) + # # new_url=str('AC ' + company +' - ' + partner + ' ' + d1) + # # if request.httprequest.full_path == '/my/act_revise/a?': + # # return werkzeug.utils.redirect('/my/act_revise/%s' % new_url) + # wizard_data = {"target_move": "posted", + # "hide_account_at_0": True, + # "foreign_currency": True, + # #"show_analytic_tags": True, + # "company_id": company, + # "partner_ids": [partner], + # #"show_partner_details": True, + # "show_cost_center": True, + # "centralize": True} + # t = request.env['general.ledger.act_revise.wizard'].sudo().create(wizard_data) + # data = t._prepare_report_general_ledger() + # name = t.get_report_filename() + # report_name = name.encode('cp1251') + # pdf, _ = request.env['ir.actions.report']._render_qweb_pdf( + # 'act_revise.action_print_report_general_ledger_qweb', res_ids=t.id, data=data) + # pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf)), ] + # return request.make_response(pdf, headers=pdfhttpheaders) + + @http.route(['/my/act_revise_contact/'], type='http', auth="public", website=True) + def print_report_contact(self, date_to, date_from, target_move, company, partner): + partner_id = int(partner) or 'default_partner_value' + company_id = int(company) + wizard_data = {"date_to": date_to, + "date_from": date_from, + "target_move": target_move, + "hide_account_at_0": True, + "foreign_currency": True, + #"show_analytic_tags": True, + "company_id": company_id, + "partner_ids": [partner_id], + #"show_partner_details": True, + "show_cost_center": True, + "centralize": True} + t = request.env['general.ledger.act_revise.wizard'].sudo().create(wizard_data) + data = t._prepare_report_general_ledger() + pdf, _ = request.env['ir.actions.report']._render_qweb_pdf( + 'l10n_ru_act_rev.action_print_report_general_ledger_qweb', res_ids=t.id, data=data) + pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf)), ] + return request.make_response(pdf, headers=pdfhttpheaders) \ No newline at end of file diff --git a/l10n_ru_act_rev/demo/demo.xml b/l10n_ru_act_rev/demo/demo.xml new file mode 100644 index 0000000..340fdd0 --- /dev/null +++ b/l10n_ru_act_rev/demo/demo.xml @@ -0,0 +1,30 @@ + + + + + \ No newline at end of file diff --git a/l10n_ru_act_rev/models/__init__.py b/l10n_ru_act_rev/models/__init__.py new file mode 100644 index 0000000..f75a803 --- /dev/null +++ b/l10n_ru_act_rev/models/__init__.py @@ -0,0 +1,2 @@ +from . import account_account +from . import ir_actions_report \ No newline at end of file diff --git a/l10n_ru_act_rev/models/account_account.py b/l10n_ru_act_rev/models/account_account.py new file mode 100644 index 0000000..3e251fe --- /dev/null +++ b/l10n_ru_act_rev/models/account_account.py @@ -0,0 +1,7 @@ +from odoo import fields, models, _ + + +class AccountAccount(models.Model): + _inherit = "account.account" + + centralized = fields.Boolean(_("Централизованно")) diff --git a/l10n_ru_act_rev/models/ir_actions_report.py b/l10n_ru_act_rev/models/ir_actions_report.py new file mode 100644 index 0000000..b0f8377 --- /dev/null +++ b/l10n_ru_act_rev/models/ir_actions_report.py @@ -0,0 +1,10 @@ +from odoo import api, models + + +class IrActionsReport(models.Model): + _inherit = "ir.actions.report" + + @api.model + def _prepare_account_financial_report_context(self, data): + lang = data and data.get("account_financial_report_lang") or "" + return dict(self.env.context or {}, lang=lang) if lang else False diff --git a/l10n_ru_act_rev/report/__init__.py b/l10n_ru_act_rev/report/__init__.py new file mode 100644 index 0000000..f7ccab0 --- /dev/null +++ b/l10n_ru_act_rev/report/__init__.py @@ -0,0 +1,2 @@ +from . import general_ledger + diff --git a/l10n_ru_act_rev/report/general_ledger.py b/l10n_ru_act_rev/report/general_ledger.py new file mode 100644 index 0000000..d2c99d8 --- /dev/null +++ b/l10n_ru_act_rev/report/general_ledger.py @@ -0,0 +1,1045 @@ +import calendar +import datetime +import operator + +from odoo.exceptions import UserError +from odoo import _, api, models +from odoo.tools import float_is_zero + +class GeneralLedgerReport(models.AbstractModel): + _name = "report.act_revise.general_ledger" + _description = "General Ledger Report" + + COMMON_ML_FIELDS = [ + "account_id", + "partner_id", + "journal_id", + "move_type", + "date", + "ref", + "id", + "move_id", + "name", + ] + + @api.model + def _get_move_lines_domain_not_reconciled( + self, company_id, account_ids, partner_ids, only_posted_moves, date_from + ): + domain = [ + ("account_id", "in", account_ids), + ("company_id", "=", company_id), + ("reconciled", "=", False), + ] + if partner_ids: + domain += [("partner_id", "in", partner_ids)] + if only_posted_moves: + domain += [("move_id.state", "=", "posted")] + else: + domain += [("move_id.state", "in", ["posted", "draft"])] + if date_from: + domain += [("date", ">", date_from)] + return domain + + @api.model + def _get_new_move_lines_domain( + self, new_ml_ids, account_ids, company_id, partner_ids, only_posted_moves + ): + domain = [ + ("account_id", "in", account_ids), + ("company_id", "=", company_id), + ("id", "in", new_ml_ids), + ] + if partner_ids: + domain += [("partner_id", "in", partner_ids)] + if only_posted_moves: + domain += [("move_id.state", "=", "posted")] + else: + domain += [("move_id.state", "in", ["posted", "draft"])] + return domain + + def _recalculate_move_lines( + self, + move_lines, + move_type, + debit_ids, + credit_ids, + debit_amount, + credit_amount, + ml_ids, + account_ids, + company_id, + partner_ids, + only_posted_moves, + debit_amount_currency, + credit_amount_currency, + ): + debit_ids = set(debit_ids) + credit_ids = set(credit_ids) + in_credit_but_not_in_debit = credit_ids - debit_ids + reconciled_ids = list(debit_ids) + list(in_credit_but_not_in_debit) + reconciled_ids = set(reconciled_ids) + ml_ids = set(ml_ids) + new_ml_ids = reconciled_ids - ml_ids + new_ml_ids = list(new_ml_ids) + new_domain = self._get_new_move_lines_domain( + new_ml_ids, account_ids, company_id, partner_ids, only_posted_moves + ) + company_currency = self.env["res.company"].browse(company_id).currency_id + ml_fields = self._get_ml_fields() + new_move_lines = self.env["account.move.line"].search_read( + domain=new_domain, fields=ml_fields + ) + move_lines = move_lines + new_move_lines + for move_line in move_lines: + ml_id = move_line["id"] + if ml_id in debit_ids: + if move_line.get("amount_residual", False): + move_line["amount_residual"] += debit_amount[ml_id] + else: + move_line["amount_residual"] = debit_amount[ml_id] + if move_line.get("amount_residual_currency", False): + move_line["amount_residual_currency"] += debit_amount_currency[ + ml_id + ] + else: + move_line["amount_residual_currency"] = debit_amount_currency[ml_id] + if ml_id in credit_ids: + if move_line.get("amount_residual", False): + move_line["amount_residual"] -= credit_amount[ml_id] + else: + move_line["amount_residual"] = -credit_amount[ml_id] + if move_line.get("amount_residual_currency", False): + move_line["amount_residual_currency"] -= credit_amount_currency[ + ml_id + ] + else: + move_line["amount_residual_currency"] = -credit_amount_currency[ + ml_id + ] + # Set amount_currency=0 to keep the same behaviour as in v13 + # Conditions: if there is no curency_id defined or it is equal + # to the company's curency_id + if "amount_currency" in move_line and ( + "currency_id" not in move_line + or move_line["currency_id"] == company_currency.id + ): + move_line["amount_currency"] = 0 + return move_lines + + def _get_accounts_data(self, accounts_ids): + accounts = self.env["account.account"].browse(accounts_ids) + accounts_data = {} + for account in accounts: + accounts_data.update( + { + account.id: { + "id": account.id, + "code": account.code, + "name": account.name, + "hide_account": False, + "group_id": account.group_id.id, + "currency_id": account.currency_id.id, + "currency_name": account.currency_id.name, + "centralized": account.centralized, + } + } + ) + return accounts_data + + def _get_journals_data(self, journals_ids): + journals = self.env["account.journal"].browse(journals_ids) + journals_data = {} + for journal in journals: + journals_data.update({journal.id: {"id": journal.id, "code": journal.code}}) + return journals_data + + def _get_analytic_data(self, account_ids): + analytic_accounts = self.env["account.analytic.account"].browse(account_ids) + analytic_data = {} + for account in analytic_accounts: + analytic_data.update({account.id: {"name": account.name}}) + return analytic_data + + def _get_taxes_data(self, taxes_ids): + taxes = self.env["account.tax"].browse(taxes_ids) + taxes_data = {} + for tax in taxes: + taxes_data.update( + { + tax.id: { + "id": tax.id, + "amount": tax.amount, + "amount_type": tax.amount_type, + "display_name": tax.display_name, + } + } + ) + if tax.amount_type == "percent" or tax.amount_type == "division": + taxes_data[tax.id]["string"] = "%" + else: + taxes_data[tax.id]["string"] = "" + taxes_data[tax.id]["tax_name"] = ( + tax.display_name + + " (" + + str(tax.amount) + + taxes_data[tax.id]["string"] + + ")" + ) + return taxes_data + + def _get_account_type_domain(self, grouped_by): + """To avoid set all possible types, set in or not in as operator of the types + we are interested in. In v15 we used the internal_type field (type of + account.account.type).""" + at_op = "in" if grouped_by != "taxes" else "not in" + return [ + ("account_type", at_op, ["asset_receivable", "liability_payable"]), + ] + + def _get_acc_prt_accounts_ids(self, company_id, grouped_by): + accounts_domain = [ + ("company_id", "=", company_id), + ] + self._get_account_type_domain(grouped_by) + acc_prt_accounts = self.env["account.account"].search(accounts_domain) + return acc_prt_accounts.ids + + def _get_initial_balances_bs_ml_domain( + self, account_ids, company_id, date_from, base_domain, grouped_by, acc_prt=False + ): + accounts_domain = [ + ("company_id", "=", company_id), + ("include_initial_balance", "=", True), + ] + if account_ids: + accounts_domain += [("id", "in", account_ids)] + domain = [] + domain += base_domain + domain += [("date", "<", date_from)] + accounts = self.env["account.account"].search(accounts_domain) + domain += [("account_id", "in", accounts.ids)] + if acc_prt: + domain += self._get_account_type_domain(grouped_by) + return domain + + def _get_initial_balances_pl_ml_domain( + self, account_ids, company_id, date_from, fy_start_date, base_domain + ): + accounts_domain = [ + ("company_id", "=", company_id), + ("include_initial_balance", "=", False), + ] + if account_ids: + accounts_domain += [("id", "in", account_ids)] + domain = [] + domain += base_domain + domain += [("date", "<", date_from), ("date", ">=", fy_start_date)] + accounts = self.env["account.account"].search(accounts_domain) + domain += [("account_id", "in", accounts.ids)] + return domain + + def _get_accounts_initial_balance(self, initial_domain_bs, initial_domain_pl): + gl_initial_acc_bs = self.env["account.move.line"].read_group( + domain=initial_domain_bs, + fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"], + groupby=["account_id"], + ) + gl_initial_acc_pl = self.env["account.move.line"].read_group( + domain=initial_domain_pl, + fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"], + groupby=["account_id"], + ) + gl_initial_acc = gl_initial_acc_bs + gl_initial_acc_pl + return gl_initial_acc + + def _get_initial_balance_fy_pl_ml_domain( + self, account_ids, company_id, fy_start_date, base_domain + ): + accounts_domain = [ + ("company_id", "=", company_id), + ("include_initial_balance", "=", False), + ] + if account_ids: + accounts_domain += [("id", "in", account_ids)] + domain = [] + domain += base_domain + domain += [("date", "<", fy_start_date)] + accounts = self.env["account.account"].search(accounts_domain) + domain += [("account_id", "in", accounts.ids)] + return domain + + def _get_pl_initial_balance( + self, account_ids, company_id, fy_start_date, foreign_currency, base_domain + ): + domain = self._get_initial_balance_fy_pl_ml_domain( + account_ids, company_id, fy_start_date, base_domain + ) + initial_balances = self.env["account.move.line"].read_group( + domain=domain, + fields=["account_id", "debit", "credit", "balance", "amount_currency:sum"], + groupby=["account_id"], + ) + pl_initial_balance = { + "debit": 0.0, + "credit": 0.0, + "balance": 0.0, + "bal_curr": 0.0, + } + for initial_balance in initial_balances: + pl_initial_balance["debit"] += initial_balance["debit"] + pl_initial_balance["credit"] += initial_balance["credit"] + pl_initial_balance["balance"] += initial_balance["balance"] + pl_initial_balance["bal_curr"] += initial_balance["amount_currency"] + return pl_initial_balance + + def _get_gl_initial_acc( + self, account_ids, company_id, date_from, fy_start_date, base_domain, grouped_by + ): + initial_domain_bs = self._get_initial_balances_bs_ml_domain( + account_ids, company_id, date_from, base_domain, grouped_by + ) + initial_domain_pl = self._get_initial_balances_pl_ml_domain( + account_ids, company_id, date_from, fy_start_date, base_domain + ) + return self._get_accounts_initial_balance(initial_domain_bs, initial_domain_pl) + + def _prepare_gen_ld_data_item(self, gl): + res = {} + for key_bal in ["init_bal", "fin_bal"]: + res[key_bal] = {} + for key_field in ["credit", "debit", "balance", "bal_curr"]: + field_name = key_field if key_field != "bal_curr" else "amount_currency" + res[key_bal][key_field] = gl[field_name] + return res + + def _prepare_gen_ld_data(self, gl_initial_acc, domain, grouped_by): + data = {} + for gl in gl_initial_acc: + acc_id = gl["account_id"][0] + data[acc_id] = self._prepare_gen_ld_data_item(gl) + data[acc_id]["id"] = acc_id + if grouped_by: + data[acc_id][grouped_by] = False + method = "_prepare_gen_ld_data_group_%s" % grouped_by + if not hasattr(self, method): + return data + return getattr(self, method)(data, domain, grouped_by) + + def _prepare_gen_ld_data_group_partners(self, data, domain, grouped_by): + gl_initial_acc_prt = self.env["account.move.line"].read_group( + domain=domain, + fields=[ + "account_id", + "partner_id", + "debit", + "credit", + "balance", + "amount_currency:sum", + ], + groupby=["account_id", "partner_id"], + lazy=False, + ) + if gl_initial_acc_prt: + for gl in gl_initial_acc_prt: + if not gl["partner_id"]: + prt_id = 0 + prt_name = _("Missing Partner") + else: + prt_id = gl["partner_id"][0] + prt_name = gl["partner_id"][1] + prt_name = prt_name._value + acc_id = gl["account_id"][0] + data[acc_id][prt_id] = self._prepare_gen_ld_data_item(gl) + data[acc_id][prt_id]["id"] = prt_id + data[acc_id][prt_id]["name"] = prt_name + data[acc_id][grouped_by] = True + return data + + def _prepare_gen_ld_data_group_taxes(self, data, domain, grouped_by): + gl_initial_acc_prt = self.env["account.move.line"].read_group( + domain=domain, + fields=[ + "account_id", + "debit", + "credit", + "balance", + "amount_currency:sum", + "tax_line_id", + ], + groupby=["account_id"], + lazy=False, + ) + if gl_initial_acc_prt: + for gl in gl_initial_acc_prt: + if "tax_line_id" in gl and gl["tax_line_id"]: + tax_id = gl["tax_line_id"][0] + tax_name = gl["tax_line_id"][1] + tax_name = tax_name._value + else: + tax_id = 0 + tax_name = "Missing Tax" + acc_id = gl["account_id"][0] + data[acc_id][tax_id] = self._prepare_gen_ld_data_item(gl) + data[acc_id][tax_id]["id"] = tax_id + data[acc_id][tax_id]["name"] = tax_name + data[acc_id][grouped_by] = True + return data + + def _get_initial_balance_data( + self, + account_ids, + partner_ids, + company_id, + date_from, + foreign_currency, + only_posted_moves, + unaffected_earnings_account, + fy_start_date, + cost_center_ids, + extra_domain, + grouped_by, + ): + # If explicit list of accounts is provided, + # don't include unaffected earnings account + if account_ids: + unaffected_earnings_account = False + base_domain = [] + if company_id: + base_domain += [("company_id", "=", company_id)] + if partner_ids: + base_domain += [("partner_id", "in", partner_ids)] + if only_posted_moves: + base_domain += [("move_id.state", "=", "posted")] + else: + base_domain += [("move_id.state", "in", ["posted", "draft"])] + if cost_center_ids: + base_domain += [("analytic_account_ids", "in", cost_center_ids)] + if extra_domain: + base_domain += extra_domain + gl_initial_acc = self._get_gl_initial_acc( + account_ids, company_id, date_from, fy_start_date, base_domain, grouped_by + ) + domain = self._get_initial_balances_bs_ml_domain( + account_ids, company_id, date_from, base_domain, grouped_by, acc_prt=True + ) + data = self._prepare_gen_ld_data(gl_initial_acc, domain, grouped_by) + accounts_ids = list(data.keys()) + unaffected_id = unaffected_earnings_account + if unaffected_id: + if unaffected_id not in accounts_ids: + accounts_ids.append(unaffected_id) + data[unaffected_id] = self._initialize_data(foreign_currency) + data[unaffected_id]["id"] = unaffected_id + data[unaffected_id]["mame"] = "" + data[unaffected_id][grouped_by] = False + pl_initial_balance = self._get_pl_initial_balance( + account_ids, company_id, fy_start_date, foreign_currency, base_domain + ) + for key_bal in ["init_bal", "fin_bal"]: + fields_balance = ["credit", "debit", "balance"] + if foreign_currency: + fields_balance.append("bal_curr") + for field_name in fields_balance: + data[unaffected_id][key_bal][field_name] += pl_initial_balance[ + field_name + ] + return data + + @api.model + def _get_move_line_data(self, move_line): + move_type = move_line.get("move_type", "") + inscription = "" + account = self.env['account.account'].browse(move_line['account_id'][0]) + accounttype = account.account_type + if move_type == "entry": + if accounttype == "liability_payable": + inscription = "Платеж поставщику" + elif accounttype == "asset_receivable": + inscription = "Оплата покупателя" + # elif accounttype == "asset_current": + # inscription = "Оплата покупателя" + # else: + # inscription = "" + elif move_type == "out_invoice": + inscription = "Продажа товаров и услуг" + # elif move_type == "out_refund": + # inscription = "Сторно клиента " + elif move_type == "in_invoice": + inscription = "Покупка товаров и услуг " + # elif move_type == "in_refund": + # inscription = "Кредитное обязательство поставщика " + # elif move_type == "out_receipt": + # inscription = "Квитанция продаж" + # elif move_type == "in_receipt": + # inscription = "Квитанция покупки" + + transformed_move_name = f"{inscription} No. {move_line['move_name']}" + move_line_data = { + "id": move_line["id"], + "date": move_line["date"], + "entry": transformed_move_name, + # "entry": move_line["move_name"], + "entry_id": move_line["move_id"][0], + "journal_id": move_line["journal_id"][0], + "account_id": move_line["account_id"][0], + "partner_id": move_line["partner_id"][0] + if move_line["partner_id"] + else False, + "partner_name": move_line["partner_id"][1] + if move_line["partner_id"] + else "", + "ref": "" if not move_line["ref"] else move_line["ref"], + "name": "" if not move_line["name"] else move_line["name"], + "tax_ids": move_line["tax_ids"], + "tax_line_id": move_line["tax_line_id"], + "debit": move_line["debit"], + "credit": move_line["credit"], + "balance": move_line["balance"], + "bal_curr": move_line["amount_currency"], + "rec_id": move_line["full_reconcile_id"][0] + if move_line["full_reconcile_id"] + else False, + "rec_name": move_line["full_reconcile_id"][1] + if move_line["full_reconcile_id"] + else "", + "currency_id": move_line["currency_id"], + "analytic_distribution": move_line["analytic_distribution"] or {}, + } + if ( + move_line_data["ref"] == move_line_data["name"] + or move_line_data["ref"] == "" + ): + ref_label = move_line_data["name"] + elif move_line_data["name"] == "": + ref_label = move_line_data["ref"] + else: + ref_label = move_line_data["ref"] + str(" - ") + move_line_data["name"] + move_line_data.update({"ref_label": ref_label}) + return move_line_data + + @api.model + def _get_period_domain( + self, + account_ids, + partner_ids, + company_id, + only_posted_moves, + date_to, + date_from, + cost_center_ids, + ): + domain = [ + ("display_type", "not in", ["line_note", "line_section"]), + ("date", ">=", date_from), + ("date", "<=", date_to), + ] + if account_ids: + domain += [("account_id", "in", account_ids)] + if company_id: + domain += [("company_id", "=", company_id)] + if partner_ids: + domain += [("partner_id", "in", partner_ids)] + if only_posted_moves: + domain += [("move_id.state", "=", "posted")] + else: + domain += [("move_id.state", "in", ["posted", "draft"])] + + if cost_center_ids: + domain += [("analytic_account_ids", "in", cost_center_ids)] + return domain + + def _initialize_data(self, foreign_currency): + res = {} + for key_bal in ["init_bal", "fin_bal"]: + res[key_bal] = {} + for key_field in ["balance", "credit", "debit"]: + res[key_bal][key_field] = 0.0 + if foreign_currency: + res[key_bal]["bal_curr"] = 0.0 + return res + + def _get_reconciled_after_date_to_ids(self, full_reconcile_ids, date_to): + full_reconcile_ids = list(full_reconcile_ids) + domain = [ + ("max_date", ">", date_to), + ("full_reconcile_id", "in", full_reconcile_ids), + ] + fields = ["full_reconcile_id"] + reconciled_after_date_to = self.env["account.partial.reconcile"].search_read( + domain=domain, fields=fields + ) + rec_after_date_to_ids = list( + map(operator.itemgetter("full_reconcile_id"), reconciled_after_date_to) + ) + rec_after_date_to_ids = [i[0] for i in rec_after_date_to_ids] + return rec_after_date_to_ids + + def _prepare_ml_items(self, move_line, grouped_by): + res = [] + if grouped_by == "partners": + item_id = move_line["partner_id"][0] if move_line["partner_id"] else 0 + item_name = ( + move_line["partner_id"][1] + if move_line["partner_id"] + else _("Missing Partner") + ) + res.append({"id": item_id, "name": item_name}) + elif grouped_by == "taxes": + if move_line["tax_line_id"]: + item_id = move_line["tax_line_id"][0] + item_name = move_line["tax_line_id"][1] + res.append({"id": item_id, "name": item_name}) + elif move_line["tax_ids"]: + for tax_id in move_line["tax_ids"]: + tax_item = self.env["account.tax"].browse(tax_id) + res.append({"id": tax_item.id, "name": tax_item.name}) + else: + res.append({"id": 0, "name": "Missing Tax"}) + else: + res.append({"id": 0, "name": ""}) + return res + + def _get_period_ml_data( + self, + account_ids, + partner_ids, + company_id, + foreign_currency, + only_posted_moves, + date_from, + date_to, + gen_ld_data, + cost_center_ids, + extra_domain, + grouped_by, + ): + domain = self._get_period_domain( + account_ids, + partner_ids, + company_id, + only_posted_moves, + date_to, + date_from, + cost_center_ids, + ) + if extra_domain: + domain += extra_domain + ml_fields = self._get_ml_fields() + move_lines = self.env["account.move.line"].search_read( + domain=domain, fields=ml_fields, order="date,move_name" + ) + journal_ids = set() + full_reconcile_ids = set() + taxes_ids = set() + analytic_ids = set() + full_reconcile_data = {} + acc_prt_account_ids = self._get_acc_prt_accounts_ids(company_id, grouped_by) + for move_line in move_lines: + journal_ids.add(move_line["journal_id"][0]) + for tax_id in move_line["tax_ids"]: + taxes_ids.add(tax_id) + for analytic_account in move_line["analytic_distribution"] or {}: + analytic_ids.add(int(analytic_account)) + if move_line["full_reconcile_id"]: + rec_id = move_line["full_reconcile_id"][0] + if rec_id not in full_reconcile_ids: + full_reconcile_data.update( + { + rec_id: { + "id": rec_id, + "name": move_line["full_reconcile_id"][1], + } + } + ) + full_reconcile_ids.add(rec_id) + acc_id = move_line["account_id"][0] + ml_id = move_line["id"] + if acc_id not in gen_ld_data.keys(): + gen_ld_data[acc_id] = self._initialize_data(foreign_currency) + gen_ld_data[acc_id]["id"] = acc_id + gen_ld_data[acc_id]["mame"] = move_line["account_id"][1] + if grouped_by: + gen_ld_data[acc_id][grouped_by] = False + if acc_id in acc_prt_account_ids: + item_ids = self._prepare_ml_items(move_line, grouped_by) + for item in item_ids: + item_id = item["id"] + if item_id not in gen_ld_data[acc_id]: + if grouped_by: + gen_ld_data[acc_id][grouped_by] = True + gen_ld_data[acc_id][item_id] = self._initialize_data( + foreign_currency + ) + gen_ld_data[acc_id][item_id]["id"] = item_id + gen_ld_data[acc_id][item_id]["name"] = item["name"] + gen_ld_data[acc_id][item_id][ml_id] = self._get_move_line_data( + move_line + ) + gen_ld_data[acc_id][item_id]["fin_bal"]["credit"] += move_line[ + "credit" + ] + gen_ld_data[acc_id][item_id]["fin_bal"]["debit"] += move_line[ + "debit" + ] + gen_ld_data[acc_id][item_id]["fin_bal"]["balance"] += move_line[ + "balance" + ] + if foreign_currency: + gen_ld_data[acc_id][item_id]["fin_bal"][ + "bal_curr" + ] += move_line["amount_currency"] + else: + gen_ld_data[acc_id][ml_id] = self._get_move_line_data(move_line) + gen_ld_data[acc_id]["fin_bal"]["credit"] += move_line["credit"] + gen_ld_data[acc_id]["fin_bal"]["debit"] += move_line["debit"] + gen_ld_data[acc_id]["fin_bal"]["balance"] += move_line["balance"] + if foreign_currency: + gen_ld_data[acc_id]["fin_bal"]["bal_curr"] += move_line[ + "amount_currency" + ] + journals_data = self._get_journals_data(list(journal_ids)) + accounts_data = self._get_accounts_data(gen_ld_data.keys()) + taxes_data = self._get_taxes_data(list(taxes_ids)) + analytic_data = self._get_analytic_data(list(analytic_ids)) + rec_after_date_to_ids = self._get_reconciled_after_date_to_ids( + full_reconcile_data.keys(), date_to + ) + return ( + gen_ld_data, + accounts_data, + journals_data, + full_reconcile_data, + taxes_data, + analytic_data, + rec_after_date_to_ids, + ) + + @api.model + def _recalculate_cumul_balance( + self, move_lines, last_cumul_balance, rec_after_date_to_ids + ): + for move_line in move_lines: + move_line["balance"] += last_cumul_balance + last_cumul_balance = move_line["balance"] + if move_line["rec_id"] in rec_after_date_to_ids: + move_line["rec_name"] = "(" + _("future") + ") " + move_line["rec_name"] + return move_lines + + def _create_account(self, account, acc_id, gen_led_data, rec_after_date_to_ids): + move_lines = [] + for ml_id in gen_led_data[acc_id].keys(): + if not isinstance(ml_id, int): + account.update({ml_id: gen_led_data[acc_id][ml_id]}) + else: + move_lines += [gen_led_data[acc_id][ml_id]] + move_lines = sorted(move_lines, key=lambda k: (k["date"])) + move_lines = self._recalculate_cumul_balance( + move_lines, + gen_led_data[acc_id]["init_bal"]["balance"], + rec_after_date_to_ids, + ) + account.update({"move_lines": move_lines}) + return account + + def _create_account_not_show_item( + self, account, acc_id, gen_led_data, rec_after_date_to_ids, grouped_by + ): + move_lines = [] + for prt_id in gen_led_data[acc_id].keys(): + if not isinstance(prt_id, int): + account.update({prt_id: gen_led_data[acc_id][prt_id]}) + elif isinstance(gen_led_data[acc_id][prt_id], dict): + for ml_id in gen_led_data[acc_id][prt_id].keys(): + if isinstance(ml_id, int): + move_lines += [gen_led_data[acc_id][prt_id][ml_id]] + move_lines = sorted(move_lines, key=lambda k: (k["date"])) + move_lines = self._recalculate_cumul_balance( + move_lines, + gen_led_data[acc_id]["init_bal"]["balance"], + rec_after_date_to_ids, + ) + account.update({"move_lines": move_lines, grouped_by: False}) + return account + + def _get_list_grouped_item( + self, data, account, rec_after_date_to_ids, hide_account_at_0, rounding + ): + list_grouped = [] + for data_id in data.keys(): + group_item = {} + move_lines = [] + if not isinstance(data_id, int): + account.update({data_id: data[data_id]}) + else: + for ml_id in data[data_id].keys(): + if not isinstance(ml_id, int): + group_item.update({ml_id: data[data_id][ml_id]}) + else: + move_lines += [data[data_id][ml_id]] + move_lines = sorted(move_lines, key=lambda k: (k["date"])) + move_lines = self._recalculate_cumul_balance( + move_lines, + data[data_id]["init_bal"]["balance"], + rec_after_date_to_ids, + ) + group_item.update({"move_lines": move_lines}) + if ( + hide_account_at_0 + and float_is_zero( + data[data_id]["init_bal"]["balance"], + precision_rounding=rounding, + ) + and group_item["move_lines"] == [] + ): + continue + list_grouped += [group_item] + return account, list_grouped + + def _create_general_ledger( + self, + gen_led_data, + accounts_data, + grouped_by, + rec_after_date_to_ids, + hide_account_at_0, + ): + general_ledger = [] + rounding = self.env.company.currency_id.rounding + for acc_id in gen_led_data.keys(): + account = {} + account.update( + { + "code": accounts_data[acc_id]["code"], + "name": accounts_data[acc_id]["name"], + "type": "account", + "currency_id": accounts_data[acc_id]["currency_id"], + "centralized": accounts_data[acc_id]["centralized"], + "grouped_by": grouped_by, + } + ) + if grouped_by and not gen_led_data[acc_id][grouped_by]: + account = self._create_account( + account, acc_id, gen_led_data, rec_after_date_to_ids + ) + if ( + hide_account_at_0 + and float_is_zero( + gen_led_data[acc_id]["init_bal"]["balance"], + precision_rounding=rounding, + ) + and account["move_lines"] == [] + ): + continue + else: + if grouped_by: + account, list_grouped = self._get_list_grouped_item( + gen_led_data[acc_id], + account, + rec_after_date_to_ids, + hide_account_at_0, + rounding, + ) + account.update({"list_grouped": list_grouped}) + if ( + hide_account_at_0 + and float_is_zero( + gen_led_data[acc_id]["init_bal"]["balance"], + precision_rounding=rounding, + ) + and account["list_grouped"] == [] + ): + continue + else: + account = self._create_account_not_show_item( + account, acc_id, gen_led_data, rec_after_date_to_ids, grouped_by + ) + if ( + hide_account_at_0 + and float_is_zero( + gen_led_data[acc_id]["init_bal"]["balance"], + precision_rounding=rounding, + ) + and account["move_lines"] == [] + ): + continue + general_ledger += [account] + return general_ledger + + @api.model + def _calculate_centralization(self, centralized_ml, move_line, date_to): + jnl_id = move_line["journal_id"] + month = move_line["date"].month + if jnl_id not in centralized_ml.keys(): + centralized_ml[jnl_id] = {} + if month not in centralized_ml[jnl_id].keys(): + centralized_ml[jnl_id][month] = {} + last_day_month = calendar.monthrange(move_line["date"].year, month) + date = datetime.date(move_line["date"].year, month, last_day_month[1]) + if date > date_to: + date = date_to + centralized_ml[jnl_id][month].update( + { + "journal_id": jnl_id, + "ref_label": "Centralized entries", + "date": date, + "debit": 0.0, + "credit": 0.0, + "balance": 0.0, + "bal_curr": 0.0, + "partner_id": False, + "rec_id": 0, + "entry_id": False, + "tax_ids": [], + "tax_line_id": False, + "full_reconcile_id": False, + "id": False, + "currency_id": False, + "analytic_distribution": {}, + } + ) + centralized_ml[jnl_id][month]["debit"] += move_line["debit"] + centralized_ml[jnl_id][month]["credit"] += move_line["credit"] + centralized_ml[jnl_id][month]["balance"] += ( + move_line["debit"] - move_line["credit"] + ) + centralized_ml[jnl_id][month]["bal_curr"] += move_line["bal_curr"] + return centralized_ml + + @api.model + def _get_centralized_ml(self, account, date_to, grouped_by): + centralized_ml = {} + if isinstance(date_to, str): + date_to = datetime.datetime.strptime(date_to, "%Y-%m-%d").date() + if grouped_by and account[grouped_by]: + for item in account["list_grouped"]: + for move_line in item["move_lines"]: + centralized_ml = self._calculate_centralization( + centralized_ml, + move_line, + date_to, + ) + else: + for move_line in account["move_lines"]: + centralized_ml = self._calculate_centralization( + centralized_ml, + move_line, + date_to, + ) + list_centralized_ml = [] + for jnl_id in centralized_ml.keys(): + list_centralized_ml += list(centralized_ml[jnl_id].values()) + return list_centralized_ml + + def _get_report_values(self, docids, data): + wizard_id = data["wizard_id"] + company = self.env["res.company"].browse(data["company_id"]) + company_id = data["company_id"] + date_to = data["date_to"] + date_from = data["date_from"] + partner_ids = data["partner_ids"] + account_ids = data["account_ids"] + cost_center_ids = data["cost_center_ids"] + grouped_by = data["grouped_by"] + hide_account_at_0 = data["hide_account_at_0"] + foreign_currency = data["foreign_currency"] + only_posted_moves = data["only_posted_moves"] + unaffected_earnings_account = data["unaffected_earnings_account"] + fy_start_date = data["fy_start_date"] + extra_domain = data["domain"] + gen_ld_data = self._get_initial_balance_data( + account_ids, + partner_ids, + company_id, + date_from, + foreign_currency, + only_posted_moves, + unaffected_earnings_account, + fy_start_date, + cost_center_ids, + extra_domain, + grouped_by, + ) + centralize = data["centralize"] + ( + gen_ld_data, + accounts_data, + journals_data, + full_reconcile_data, + taxes_data, + analytic_data, + rec_after_date_to_ids, + ) = self._get_period_ml_data( + account_ids, + partner_ids, + company_id, + foreign_currency, + only_posted_moves, + date_from, + date_to, + gen_ld_data, + cost_center_ids, + extra_domain, + grouped_by, + ) + general_ledger = self._create_general_ledger( + gen_ld_data, + accounts_data, + grouped_by, + rec_after_date_to_ids, + hide_account_at_0, + ) + if centralize: + for account in general_ledger: + if account["centralized"]: + centralized_ml = self._get_centralized_ml( + account, date_to, grouped_by + ) + account["move_lines"] = centralized_ml + account["move_lines"] = self._recalculate_cumul_balance( + account["move_lines"], + gen_ld_data[account["id"]]["init_bal"]["balance"], + rec_after_date_to_ids, + ) + if grouped_by and account[grouped_by]: + account[grouped_by] = False + del account["list_grouped"] + general_ledger = sorted(general_ledger, key=lambda k: k["code"]) + if not general_ledger: + raise UserError(f'Проводок для формирования акта по введенным условиям не найдено.') + return { + "doc_ids": [wizard_id], + "doc_model": "general.ledger.act_revise.wizard", + "docs": self.env["general.ledger.act_revise.wizard"].browse(wizard_id), + "foreign_currency": data["foreign_currency"], + "company_name": company.display_name, + "company_currency": company.currency_id, + "currency_name": company.currency_id.name, + "date_from": data["date_from"], + "date_to": data["date_to"], + "only_posted_moves": data["only_posted_moves"], + "hide_account_at_0": data["hide_account_at_0"], + "show_cost_center": data["show_cost_center"], + "general_ledger": general_ledger, + "accounts_data": accounts_data, + "journals_data": journals_data, + "full_reconcile_data": full_reconcile_data, + "taxes_data": taxes_data, + "centralize": centralize, + "analytic_data": analytic_data, + "filter_partner_ids": True if partner_ids else False, + "currency_model": self.env["res.currency"], + } + + def _get_ml_fields(self): + return self.COMMON_ML_FIELDS + [ + "analytic_distribution", + "full_reconcile_id", + "tax_line_id", + "currency_id", + "credit", + "debit", + "amount_currency", + "balance", + "tax_ids", + "move_name", + ] diff --git a/l10n_ru_act_rev/report/general_ledger.xml b/l10n_ru_act_rev/report/general_ledger.xml new file mode 100644 index 0000000..b7add8b --- /dev/null +++ b/l10n_ru_act_rev/report/general_ledger.xml @@ -0,0 +1,286 @@ + + + + + + + + + + + + + + + + + Акт сверки + general.ledger.act_revise.wizard + qweb-pdf + l10n_ru_act_rev.general_ledger + l10n_ru_act_rev.general_ledger + 'Акт сверки - %s' % (object.get_report_filename() or '') + + + + + Account financial report qweb paperformat + + custom + 297 + 210 + Landscape + 12 + 8 + 5 + 5 + + 10 + 110 + + + + + \ No newline at end of file diff --git a/l10n_ru_act_rev/report/layouts.xml b/l10n_ru_act_rev/report/layouts.xml new file mode 100644 index 0000000..e77d9c7 --- /dev/null +++ b/l10n_ru_act_rev/report/layouts.xml @@ -0,0 +1,34 @@ + + + + + diff --git a/l10n_ru_act_rev/security/ir.model.access.csv b/l10n_ru_act_rev/security/ir.model.access.csv new file mode 100644 index 0000000..96c0232 --- /dev/null +++ b/l10n_ru_act_rev/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_general_ledger_act_revise_wizard,general.ledger.act_revise.wizard,model_general_ledger_act_revise_wizard,base.group_user,1,1,1,1 diff --git a/l10n_ru_act_rev/views/account_account_views.xml b/l10n_ru_act_rev/views/account_account_views.xml new file mode 100644 index 0000000..38dce94 --- /dev/null +++ b/l10n_ru_act_rev/views/account_account_views.xml @@ -0,0 +1,14 @@ + + + + account.account.form.inherit + + account.account + form + + + + + + + diff --git a/l10n_ru_act_rev/views/portal_templates.xml b/l10n_ru_act_rev/views/portal_templates.xml new file mode 100644 index 0000000..b7a1ff2 --- /dev/null +++ b/l10n_ru_act_rev/views/portal_templates.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/l10n_ru_act_rev/views/report_general_ledger.xml b/l10n_ru_act_rev/views/report_general_ledger.xml new file mode 100644 index 0000000..9e6945e --- /dev/null +++ b/l10n_ru_act_rev/views/report_general_ledger.xml @@ -0,0 +1,9 @@ + + + + diff --git a/l10n_ru_act_rev/wizard/__init__.py b/l10n_ru_act_rev/wizard/__init__.py new file mode 100644 index 0000000..c0d813c --- /dev/null +++ b/l10n_ru_act_rev/wizard/__init__.py @@ -0,0 +1,2 @@ +from . import abstract_wizard +from . import general_ledger_wizard diff --git a/l10n_ru_act_rev/wizard/abstract_wizard.py b/l10n_ru_act_rev/wizard/abstract_wizard.py new file mode 100644 index 0000000..216bae7 --- /dev/null +++ b/l10n_ru_act_rev/wizard/abstract_wizard.py @@ -0,0 +1,38 @@ +from odoo import models, fields + + +class AbstractWizard(models.AbstractModel): + _name = "act_revise.abstract_wizard" + _description = "Abstract Wizard" + + def _get_partner_ids_domain(self): + return [ + "&", + "|", + ("company_id", "=", self.company_id.id), + ("company_id", "=", False), + "|", + ("parent_id", "=", False), + ("is_company", "=", True), + ] + + def _default_partners(self): + context = self.env.context + if context.get("active_ids") and context.get("active_model") == "res.partner": + partners = self.env["res.partner"].browse(context["active_ids"]) + corp_partners = partners.filtered("parent_id") + partners -= corp_partners + partners |= corp_partners.mapped("commercial_partner_id") + return partners.ids + + company_id = fields.Many2one( + comodel_name="res.company", + default=lambda self: self.env.company.id, + required=False, + string="Компания", + ) + + def button_export_pdf(self): + self.ensure_one() + report_type = "qweb-pdf" + return self._export(report_type) \ No newline at end of file diff --git a/l10n_ru_act_rev/wizard/general_ledger_wizard.py b/l10n_ru_act_rev/wizard/general_ledger_wizard.py new file mode 100644 index 0000000..d0d08e0 --- /dev/null +++ b/l10n_ru_act_rev/wizard/general_ledger_wizard.py @@ -0,0 +1,898 @@ +import logging +import time +from ast import literal_eval +from odoo import _, api, fields, models +from odoo.tools import date_utils,pycompat +from pytils import dt,numeral +from datetime import datetime, date +import re +import urllib +from odoo.exceptions import UserError + +class GeneralLedgerReportWizard(models.TransientModel): + """General ledger report wizard.""" + + _name = "general.ledger.act_revise.wizard" + _description = "General Ledger Report Wizard" + _inherit = "act_revise.abstract_wizard" + + # date_range_id = fields.Many2one(comodel_name="date.range", string="Date range") + date_from = fields.Date(string="Начало даты", required=True, default=lambda self: self._init_date_from()) + date_to = fields.Date(string="Конец даты", required=True, default=fields.Date.context_today) + fy_start_date = fields.Date(compute="_compute_fy_start_date") + target_move = fields.Selection( + [("posted", "Все проведенные проводки"), ("all", "Все проводки")], + string="Цель операции", + required=True, + default="posted", + ) + account_ids = fields.Many2many( + comodel_name="account.account", string=_("Filter accounts") + ) + centralize = fields.Boolean(string=_("Activate centralization"), default=True) + hide_account_at_0 = fields.Boolean( + string=_("Hide account ending balance at 0"), + help=_("Use this filter to hide an account or a partner " + "with an ending balance at 0. " + "If partners are filtered, " + "debits and credits totals will not match the trial balance."), + ) + receivable_accounts_only = fields.Boolean() + payable_accounts_only = fields.Boolean() + partner_ids = fields.Many2many( + comodel_name="res.partner", + string=_("Filter partners"), + default=lambda self: self._default_partners(), + ) + account_journal_ids = fields.Many2many( + comodel_name="account.journal", string=_("Filter journals") + ) + cost_center_ids = fields.Many2many( + comodel_name="account.analytic.account", string=_("Filter cost centers") + ) + + not_only_one_unaffected_earnings_account = fields.Boolean(readonly=True) + foreign_currency = fields.Boolean( + string=_("Show foreign currency"), + help=_("Display foreign currency for move lines, unless " + "account currency is not setup through chart of accounts " + "will display initial and final balance in that currency."), + default=lambda self: self._default_foreign_currency(), + ) + account_code_from = fields.Many2one( + comodel_name="account.account", + help="Starting account in a range", + ) + account_code_to = fields.Many2one( + comodel_name="account.account", + help="Ending account in a range", + ) + grouped_by = fields.Selection( + selection=[("", "None"), ("partners", "Partners"), ("taxes", "Taxes")], + default="partners", + ) + show_cost_center = fields.Boolean( + string="Show Analytic Account", + default=True, + ) + domain = fields.Char( + string="Journal Items Domain", + default=[], + help="This domain will be used to select specific domain for Journal " "Items", + ) + + # def _print_report(self, report_type): + # self.ensure_one() + # data = self._prepare_report_general_ledger() + # report = self.env["ir.actions.report"].search( + # [("report_name", "=", "act_revise.general_ledger"), ("report_type", "=", report_type)], limit=1, ) + # if self.partner_ids[0].parent_id: + # partner = int(self.partner_ids[0].parent_id.id) + # else: + # partner = int(self.partner_ids[0].id) + # return { + # 'type': 'ir.actions.act_url', + # 'url': '/my/act_revise_contact/%s?date_to=%s&date_from=%s&target_move=%s&company=%s&partner=%s' % ( + # urllib.parse.quote(self.get_report_filename()), self.date_to, self.date_from, self.target_move, + # self.company_id.id, partner), + # 'target': 'new', + # } + + def _get_account_move_lines_domain(self): + domain = literal_eval(self.domain) if self.domain else [] + return domain + + @api.onchange("account_code_from", "account_code_to") + def on_change_account_range(self): + if ( + self.account_code_from + and self.account_code_from.code.isdigit() + and self.account_code_to + and self.account_code_to.code.isdigit() + ): + start_range = self.account_code_from.code + end_range = self.account_code_to.code + self.account_ids = self.env["account.account"].search( + [("code", ">=", start_range), ("code", "<=", end_range)] + ) + if self.company_id: + self.account_ids = self.account_ids.filtered( + lambda a: a.company_id == self.company_id + ) + + def _init_date_from(self): + """set start date to begin of current year if fiscal year running""" + today = fields.Date.context_today(self) + company = self.company_id or self.env.company + last_fsc_month = company.fiscalyear_last_month + last_fsc_day = company.fiscalyear_last_day + + if ( + today.month < int(last_fsc_month) + or today.month == int(last_fsc_month) + and today.day <= last_fsc_day + ): + return time.strftime("%Y-01-01") + else: + return False + + def _default_foreign_currency(self): + return self.env.user.has_group("base.group_multi_currency") + + @api.depends("date_from") + def _compute_fy_start_date(self): + for wiz in self: + if wiz.date_from: + date_from, date_to = date_utils.get_fiscal_year( + wiz.date_from, + day=self.company_id.fiscalyear_last_day, + month=int(self.company_id.fiscalyear_last_month), + ) + wiz.fy_start_date = date_from + else: + wiz.fy_start_date = False + + @api.onchange("company_id") + def onchange_company_id(self): + """Handle company change.""" + count = self.env["account.account"].search_count( + [ + ("account_type", "=", "equity_unaffected"), + ("company_id", "=", self.company_id.id), + ] + ) + self.not_only_one_unaffected_earnings_account = count != 1 + # if ( + # self.company_id + # and self.date_range_id.company_id + # and self.date_range_id.company_id != self.company_id + # ): + # self.date_range_id = False + if self.company_id and self.account_journal_ids: + self.account_journal_ids = self.account_journal_ids.filtered( + lambda p: p.company_id == self.company_id or not p.company_id + ) + if self.company_id and self.partner_ids: + self.partner_ids = self.partner_ids.filtered( + lambda p: p.company_id == self.company_id or not p.company_id + ) + if self.company_id and self.account_ids: + if self.receivable_accounts_only or self.payable_accounts_only: + self.onchange_type_accounts_only() + else: + self.account_ids = self.account_ids.filtered( + lambda a: a.company_id == self.company_id + ) + if self.company_id and self.cost_center_ids: + self.cost_center_ids = self.cost_center_ids.filtered( + lambda c: c.company_id == self.company_id + ) + res = { + "domain": { + "account_ids": [], + "partner_ids": [], + "account_journal_ids": [], + "cost_center_ids": [], + # "date_range_id": [], + } + } + if not self.company_id: + return res + else: + res["domain"]["account_ids"] += [("company_id", "=", self.company_id.id)] + res["domain"]["account_journal_ids"] += [ + ("company_id", "=", self.company_id.id) + ] + res["domain"]["partner_ids"] += self._get_partner_ids_domain() + res["domain"]["cost_center_ids"] += [ + ("company_id", "=", self.company_id.id) + ] + # res["domain"]["date_range_id"] += [ + # "|", + # ("company_id", "=", self.company_id.id), + # ("company_id", "=", False), + # ] + return res + + # @api.onchange("date_range_id") + # def onchange_date_range_id(self): + # """Handle date range change.""" + # if self.date_range_id: + # self.date_from = self.date_range_id.date_start + # self.date_to = self.date_range_id.date_end + + # @api.constrains("company_id", "date_range_id") + # def _check_company_id_date_range_id(self): + # for rec in self.sudo(): + # if ( + # rec.company_id + # and rec.date_range_id.company_id + # and rec.company_id != rec.date_range_id.company_id + # ): + # raise ValidationError( + # _( + # "The Company in the General Ledger Report Wizard and in " + # "Date Range must be the same." + # ) + # ) + + @api.onchange("receivable_accounts_only", "payable_accounts_only") + def onchange_type_accounts_only(self): + """Handle receivable/payable accounts only change.""" + if self.receivable_accounts_only or self.payable_accounts_only: + domain = [("company_id", "=", self.company_id.id)] + if self.receivable_accounts_only and self.payable_accounts_only: + domain += [ + ("account_type", "in", ("asset_receivable", "liability_payable")) + ] + elif self.receivable_accounts_only: + domain += [("account_type", "=", "asset_receivable")] + elif self.payable_accounts_only: + domain += [("account_type", "=", "liability_payable")] + self.account_ids = self.env["account.account"].search(domain) + else: + self.account_ids = None + + @api.onchange("partner_ids") + def onchange_partner_ids(self): + """Handle partners change.""" + if self.partner_ids: + self.receivable_accounts_only = self.payable_accounts_only = True + else: + self.receivable_accounts_only = self.payable_accounts_only = False + + @api.depends("company_id") + def _compute_unaffected_earnings_account(self): + for record in self: + record.unaffected_earnings_account = self.env["account.account"].search( + [ + ("account_type", "=", "equity_unaffected"), + ("company_id", "=", record.company_id.id), + ] + ) + + unaffected_earnings_account = fields.Many2one( + comodel_name="account.account", + compute="_compute_unaffected_earnings_account", + store=True, + ) + + # def _print_report(self, report_type): + # self.ensure_one() + # data = self._prepare_report_general_ledger() + # report_name = "act_revise.general_ledger" + # return ( + # self.env["ir.actions.report"] + # .search( + # [("report_name", "=", report_name), ("report_type", "=", report_type)], + # limit=1, + # ) + # .report_action(self, data=data) + # ) + def _print_report(self, report_type): + self.ensure_one() + data = self._prepare_report_general_ledger() + report = self.env["ir.actions.report"].search( + [("report_name", "=", "l10n_ru_act_rev.general_ledger"), ("report_type", "=", report_type)], limit=1, ) + + if self.partner_ids[0].parent_id: + partner = int(self.partner_ids[0].parent_id.id) + else: + partner = int(self.partner_ids[0].id) + account_data = self.env['account.move.line'].sudo().search([ + ('partner_id', '=', partner), + ('account_id.account_type', 'in', ('liability_payable', 'asset_receivable')), + ('account_id.non_trade', '=', False), + ('date', '<=', self.date_to), + ('date', '>=', self.date_from) + ]) + logging.warning(f'account_data {account_data}') + if self.target_move == 'posted' and not account_data.filtered(lambda p: p.parent_state == 'posted') or not account_data: + raise UserError(f'Проводок для формирования акта по введенным условиям не найдено.') + return { + 'type': 'ir.actions.act_url', + 'url': '/my/act_revise_contact/%s?date_to=%s&date_from=%s&target_move=%s&company=%s&partner=%s' % ( + urllib.parse.quote(self.get_report_filename()), self.date_to, self.date_from, self.target_move, + self.company_id.id, partner), + 'target': 'new', + } + + def _prepare_report_general_ledger(self): + self.ensure_one() + return { + "wizard_id": self.id, + "date_from": self.date_from, + "date_to": self.date_to, + "only_posted_moves": self.target_move == "posted", + "hide_account_at_0": self.hide_account_at_0, + "foreign_currency": self.foreign_currency, + "company_id": self.company_id.id, + "account_ids": self.account_ids.ids, + "partner_ids": self.partner_ids.ids, + "grouped_by": self.grouped_by, + "cost_center_ids": self.cost_center_ids.ids, + "show_cost_center": self.show_cost_center, + "journal_ids": self.account_journal_ids.ids, + "centralize": self.centralize, + "fy_start_date": self.fy_start_date, + "unaffected_earnings_account": self.unaffected_earnings_account.id, + "account_financial_report_lang": self.env.lang, + "domain": self._get_account_move_lines_domain(), + } + + def _export(self, report_type): + """Default export is PDF.""" + return self._print_report(report_type) + + def _get_atr_from_dict(self, obj_id, data, key): + try: + return data[obj_id][key] + except KeyError: + return data[str(obj_id)][key] + + def numer(self, name): + if name: + numeration = re.findall('\d+$', name) + if numeration: return numeration[0] + return name + + def get_data_format(self, date): + if date and date != 'False': + return dt.ru_strftime(u'%d.%m.%Y г.', date=datetime.strptime(str(date), "%Y-%m-%d"), inflected=True) + return '' + + def initials(self, fio): + if fio: + return (fio.split()[0] + ' ' + ''.join([fio[0:1] + '.' for fio in fio.split()[1:]])).strip() + return '' + + def rubles(self, sum): + "Transform sum number in rubles to text" + text_rubles = numeral.rubles(int(sum)) + copeck = round((sum - int(sum)) * 100) + text_copeck = numeral.choose_plural(int(copeck), (u"копейка", u"копейки", u"копеек")) + return ("%s %02d %s") % (text_rubles, copeck, text_copeck) + + def img(self, img, type='png', width=0, height=0): + if width: + width = "width='%spx'" % (width) + else: + width = " " + if height: + height = "height='%spx'" % (height) + else: + height = " " + toreturn = "" % ( + width, + height, + type, + str(pycompat.to_text(img))) + return toreturn + + def get_contract(self): + partner = int(self.partner_ids[0].id) + contract = self.env['partner.contract.customer'].search( + [('partner_id', '=', partner), ('state', '=', 'signed')], limit=1) + if contract: + return contract + + def get_function_partner(self, partner): + director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1) + if director: + if director.function: + return director.function or 'отсутствует' + + def get_name_partner(self, partner): + director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1) + if director: + return director.name or 'отсутствует' + + def get_report_filename(self): + today = date.today() + d1 = today.strftime("%d-%m-%Y") + if self.partner_ids[0].parent_id: + p = ''.join(self.partner_ids[0].parent_id.name) + else: + p = ''.join(self.partner_ids[0].name) + # return 'Акт Сверки '+ d1 + ' ' + self.company_id.name+'_'+p + return str(self.company_id.id) + ' - ' + ' ' + d1 + + def sorted_lines(self, list): + list = sorted(list, key=lambda k: k.get('date'), reverse=False) + return list + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# +# import time +# from ast import literal_eval +# from odoo import _, api, fields, models +# from odoo.tools import date_utils,pycompat +# from pytils import dt,numeral +# from datetime import datetime, date +# import re +# import urllib +# +# class GeneralLedgerReportWizard(models.TransientModel): +# """General ledger report wizard.""" +# +# _name = "general.ledger.act_revise.wizard" +# _description = "General Ledger Report Wizard" +# _inherit = "act_revise.abstract_wizard" +# +# # date_range_id = fields.Many2one(comodel_name="date.range", string="Date range") +# date_from = fields.Date(string="Начало даты", required=True, default=lambda self: self._init_date_from()) +# date_to = fields.Date(string="Конец даты", required=True, default=fields.Date.context_today) +# fy_start_date = fields.Date(compute="_compute_fy_start_date") +# target_move = fields.Selection( +# [("posted", "Р’СЃРµ проведенные РїСЂРѕРІРѕРґРєРё"), ("all", "Р’СЃРµ РїСЂРѕРІРѕРґРєРё")], +# string="Цель операции", +# required=True, +# default="posted", +# ) +# account_ids = fields.Many2many( +# comodel_name="account.account", string=_("Filter accounts") +# ) +# centralize = fields.Boolean(string=_("Activate centralization"), default=True) +# hide_account_at_0 = fields.Boolean( +# string=_("Hide account ending balance at 0"), +# help=_("Use this filter to hide an account or a partner " +# "with an ending balance at 0. " +# "If partners are filtered, " +# "debits and credits totals will not match the trial balance."), +# ) +# receivable_accounts_only = fields.Boolean() +# payable_accounts_only = fields.Boolean() +# partner_ids = fields.Many2many( +# comodel_name="res.partner", +# string=_("Filter partners"), +# default=lambda self: self._default_partners(), +# ) +# account_journal_ids = fields.Many2many( +# comodel_name="account.journal", string=_("Filter journals") +# ) +# cost_center_ids = fields.Many2many( +# comodel_name="account.analytic.account", string=_("Filter cost centers") +# ) +# +# not_only_one_unaffected_earnings_account = fields.Boolean(readonly=True) +# foreign_currency = fields.Boolean( +# string=_("Show foreign currency"), +# help=_("Display foreign currency for move lines, unless " +# "account currency is not setup through chart of accounts " +# "will display initial and final balance in that currency."), +# default=lambda self: self._default_foreign_currency(), +# ) +# account_code_from = fields.Many2one( +# comodel_name="account.account", +# help="Starting account in a range", +# ) +# account_code_to = fields.Many2one( +# comodel_name="account.account", +# help="Ending account in a range", +# ) +# grouped_by = fields.Selection( +# selection=[("", "None"), ("partners", "Partners"), ("taxes", "Taxes")], +# default="partners", +# ) +# show_cost_center = fields.Boolean( +# string="Show Analytic Account", +# default=True, +# ) +# domain = fields.Char( +# string="Journal Items Domain", +# default=[], +# help="This domain will be used to select specific domain for Journal " "Items", +# ) +# +# # def _print_report(self, report_type): +# # self.ensure_one() +# # data = self._prepare_report_general_ledger() +# # report = self.env["ir.actions.report"].search( +# # [("report_name", "=", "act_revise.general_ledger"), ("report_type", "=", report_type)], limit=1, ) +# # if self.partner_ids[0].parent_id: +# # partner = int(self.partner_ids[0].parent_id.id) +# # else: +# # partner = int(self.partner_ids[0].id) +# # return { +# # 'type': 'ir.actions.act_url', +# # 'url': '/my/act_revise_contact/%s?date_to=%s&date_from=%s&target_move=%s&company=%s&partner=%s' % ( +# # urllib.parse.quote(self.get_report_filename()), self.date_to, self.date_from, self.target_move, +# # self.company_id.id, partner), +# # 'target': 'new', +# # } +# +# def _get_account_move_lines_domain(self): +# domain = literal_eval(self.domain) if self.domain else [] +# return domain +# +# @api.onchange("account_code_from", "account_code_to") +# def on_change_account_range(self): +# if ( +# self.account_code_from +# and self.account_code_from.code.isdigit() +# and self.account_code_to +# and self.account_code_to.code.isdigit() +# ): +# start_range = self.account_code_from.code +# end_range = self.account_code_to.code +# self.account_ids = self.env["account.account"].search( +# [("code", ">=", start_range), ("code", "<=", end_range)] +# ) +# if self.company_id: +# self.account_ids = self.account_ids.filtered( +# lambda a: a.company_id == self.company_id +# ) +# +# def _init_date_from(self): +# """set start date to begin of current year if fiscal year running""" +# today = fields.Date.context_today(self) +# company = self.company_id or self.env.company +# last_fsc_month = company.fiscalyear_last_month +# last_fsc_day = company.fiscalyear_last_day +# +# if ( +# today.month < int(last_fsc_month) +# or today.month == int(last_fsc_month) +# and today.day <= last_fsc_day +# ): +# return time.strftime("%Y-01-01") +# else: +# return False +# +# def _default_foreign_currency(self): +# return self.env.user.has_group("base.group_multi_currency") +# +# @api.depends("date_from") +# def _compute_fy_start_date(self): +# for wiz in self: +# if wiz.date_from: +# date_from, date_to = date_utils.get_fiscal_year( +# wiz.date_from, +# day=self.company_id.fiscalyear_last_day, +# month=int(self.company_id.fiscalyear_last_month), +# ) +# wiz.fy_start_date = date_from +# else: +# wiz.fy_start_date = False +# +# @api.onchange("company_id") +# def onchange_company_id(self): +# """Handle company change.""" +# count = self.env["account.account"].search_count( +# [ +# ("account_type", "=", "equity_unaffected"), +# ("company_id", "=", self.company_id.id), +# ] +# ) +# self.not_only_one_unaffected_earnings_account = count != 1 +# # if ( +# # self.company_id +# # and self.date_range_id.company_id +# # and self.date_range_id.company_id != self.company_id +# # ): +# # self.date_range_id = False +# if self.company_id and self.account_journal_ids: +# self.account_journal_ids = self.account_journal_ids.filtered( +# lambda p: p.company_id == self.company_id or not p.company_id +# ) +# if self.company_id and self.partner_ids: +# self.partner_ids = self.partner_ids.filtered( +# lambda p: p.company_id == self.company_id or not p.company_id +# ) +# if self.company_id and self.account_ids: +# if self.receivable_accounts_only or self.payable_accounts_only: +# self.onchange_type_accounts_only() +# else: +# self.account_ids = self.account_ids.filtered( +# lambda a: a.company_id == self.company_id +# ) +# if self.company_id and self.cost_center_ids: +# self.cost_center_ids = self.cost_center_ids.filtered( +# lambda c: c.company_id == self.company_id +# ) +# res = { +# "domain": { +# "account_ids": [], +# "partner_ids": [], +# "account_journal_ids": [], +# "cost_center_ids": [], +# # "date_range_id": [], +# } +# } +# if not self.company_id: +# return res +# else: +# res["domain"]["account_ids"] += [("company_id", "=", self.company_id.id)] +# res["domain"]["account_journal_ids"] += [ +# ("company_id", "=", self.company_id.id) +# ] +# res["domain"]["partner_ids"] += self._get_partner_ids_domain() +# res["domain"]["cost_center_ids"] += [ +# ("company_id", "=", self.company_id.id) +# ] +# # res["domain"]["date_range_id"] += [ +# # "|", +# # ("company_id", "=", self.company_id.id), +# # ("company_id", "=", False), +# # ] +# return res +# +# # @api.onchange("date_range_id") +# # def onchange_date_range_id(self): +# # """Handle date range change.""" +# # if self.date_range_id: +# # self.date_from = self.date_range_id.date_start +# # self.date_to = self.date_range_id.date_end +# +# # @api.constrains("company_id", "date_range_id") +# # def _check_company_id_date_range_id(self): +# # for rec in self.sudo(): +# # if ( +# # rec.company_id +# # and rec.date_range_id.company_id +# # and rec.company_id != rec.date_range_id.company_id +# # ): +# # raise ValidationError( +# # _( +# # "The Company in the General Ledger Report Wizard and in " +# # "Date Range must be the same." +# # ) +# # ) +# +# @api.onchange("receivable_accounts_only", "payable_accounts_only") +# def onchange_type_accounts_only(self): +# """Handle receivable/payable accounts only change.""" +# if self.receivable_accounts_only or self.payable_accounts_only: +# domain = [("company_id", "=", self.company_id.id)] +# if self.receivable_accounts_only and self.payable_accounts_only: +# domain += [ +# ("account_type", "in", ("asset_receivable", "liability_payable")) +# ] +# elif self.receivable_accounts_only: +# domain += [("account_type", "=", "asset_receivable")] +# elif self.payable_accounts_only: +# domain += [("account_type", "=", "liability_payable")] +# self.account_ids = self.env["account.account"].search(domain) +# else: +# self.account_ids = None +# +# @api.onchange("partner_ids") +# def onchange_partner_ids(self): +# """Handle partners change.""" +# if self.partner_ids: +# self.receivable_accounts_only = self.payable_accounts_only = True +# else: +# self.receivable_accounts_only = self.payable_accounts_only = False +# +# @api.depends("company_id") +# def _compute_unaffected_earnings_account(self): +# for record in self: +# record.unaffected_earnings_account = self.env["account.account"].search( +# [ +# ("account_type", "=", "equity_unaffected"), +# ("company_id", "=", record.company_id.id), +# ] +# ) +# +# unaffected_earnings_account = fields.Many2one( +# comodel_name="account.account", +# compute="_compute_unaffected_earnings_account", +# store=True, +# ) +# +# # def _print_report(self, report_type): +# # self.ensure_one() +# # data = self._prepare_report_general_ledger() +# # report_name = "act_revise.general_ledger" +# # return ( +# # self.env["ir.actions.report"] +# # .search( +# # [("report_name", "=", report_name), ("report_type", "=", report_type)], +# # limit=1, +# # ) +# # .report_action(self, data=data) +# # ) +# def _print_report(self, report_type): +# self.ensure_one() +# data = self._prepare_report_general_ledger() +# report = self.env["ir.actions.report"].search( +# [("report_name", "=", "act_revise.general_ledger"), ("report_type", "=", report_type)], limit=1, ) +# # report.report_name='Test' +# # report.headers.add('Content-Disposition', 'attachment; filename="Test.pdf";') +# # pdf, _ = request.env.ref('act_revise.action_print_report_general_ledger_qweb').sudo().render_qweb_pdf(self,data=data) +# # pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf)),('Content-Disposition', 'attachment; filename="%s";' % report_name),] +# # return request.make_response(pdf, headers=pdfhttpheaders) +# # return ( +# # self.env["ir.actions.report"] +# # .search( +# # [("report_name", "=", "act_revise.general_ledger"), ("report_type", "=", report_type)], +# # limit=1, +# # ) +# # report.report_action(self, data=data) +# # ) +# # name='Test' +# if self.partner_ids[0].parent_id: +# partner = int(self.partner_ids[0].parent_id.id) +# else: +# partner = int(self.partner_ids[0].id) +# account_data = self.env['account.move.line'].sudo().search([ +# ('partner_id', '=', partner.id), +# ('account_id.account_type', 'in', ('liability_payable', 'asset_receivable')), +# ('account_id.non_trade', '=', False), +# ('date', '<=', self.date_to), +# ('date', '>=', self.date_from) +# ]) +# if not account_data: +# raise UserError(f'Проводок для формирования акта по введенным условиям не найдено.') +# return { +# 'type': 'ir.actions.act_url', +# 'url': '/my/act_revise_contact/%s?date_to=%s&date_from=%s&target_move=%s&company=%s&partner=%s' % ( +# urllib.parse.quote(self.get_report_filename()), self.date_to, self.date_from, self.target_move, +# self.company_id.id, partner), +# 'target': 'new', +# } +# +# def _prepare_report_general_ledger(self): +# self.ensure_one() +# return { +# "wizard_id": self.id, +# "date_from": self.date_from, +# "date_to": self.date_to, +# "only_posted_moves": self.target_move == "posted", +# "hide_account_at_0": self.hide_account_at_0, +# "foreign_currency": self.foreign_currency, +# "company_id": self.company_id.id, +# "account_ids": self.account_ids.ids, +# "partner_ids": self.partner_ids.ids, +# "grouped_by": self.grouped_by, +# "cost_center_ids": self.cost_center_ids.ids, +# "show_cost_center": self.show_cost_center, +# "journal_ids": self.account_journal_ids.ids, +# "centralize": self.centralize, +# "fy_start_date": self.fy_start_date, +# "unaffected_earnings_account": self.unaffected_earnings_account.id, +# "account_financial_report_lang": self.env.lang, +# "domain": self._get_account_move_lines_domain(), +# } +# +# def _export(self, report_type): +# """Default export is PDF.""" +# return self._print_report(report_type) +# +# def _get_atr_from_dict(self, obj_id, data, key): +# try: +# return data[obj_id][key] +# except KeyError: +# return data[str(obj_id)][key] +# +# def numer(self, name): +# if name: +# numeration = re.findall('\d+$', name) +# if numeration: return numeration[0] +# return name +# +# def get_data_format(self, date): +# if date and date != 'False': +# return dt.ru_strftime(u'%d.%m.%Y Рі.', date=datetime.strptime(str(date), "%Y-%m-%d"), inflected=True) +# return '' +# +# def initials(self, fio): +# if fio: +# return (fio.split()[0] + ' ' + ''.join([fio[0:1] + '.' for fio in fio.split()[1:]])).strip() +# return '' +# +# def rubles(self, sum): +# "Transform sum number in rubles to text" +# text_rubles = numeral.rubles(int(sum)) +# copeck = round((sum - int(sum)) * 100) +# text_copeck = numeral.choose_plural(int(copeck), (u"копейка", u"копейки", u"копеек")) +# return ("%s %02d %s") % (text_rubles, copeck, text_copeck) +# +# def img(self, img, type='png', width=0, height=0): +# if width: +# width = "width='%spx'" % (width) +# else: +# width = " " +# if height: +# height = "height='%spx'" % (height) +# else: +# height = " " +# toreturn = "" % ( +# width, +# height, +# type, +# str(pycompat.to_text(img))) +# return toreturn +# +# def get_contract(self): +# partner = int(self.partner_ids[0].id) +# contract = self.env['partner.contract.customer'].search( +# [('partner_id', '=', partner), ('state', '=', 'signed')], limit=1) +# if contract: +# return contract +# +# def get_function_partner(self, partner): +# director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1) +# if director: +# if director.function: +# return director.function or 'отсутствует' +# +# def get_name_partner(self, partner): +# director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1) +# if director: +# return director.name or 'отсутствует' +# +# def get_report_filename(self): +# today = date.today() +# d1 = today.strftime("%d-%m-%Y") +# if self.partner_ids[0].parent_id: +# p = ''.join(self.partner_ids[0].parent_id.name) +# else: +# p = ''.join(self.partner_ids[0].name) +# # return 'РђРєС‚ Сверки '+ d1 + ' ' + self.company_id.name+'_'+p +# return str(self.company_id.id) + ' - ' + ' ' + d1 +# +# def sorted_lines(self, list): +# list = sorted(list, key=lambda k: k.get('date'), reverse=False) +# return list diff --git a/l10n_ru_act_rev/wizard/general_ledger_wizard_view.xml b/l10n_ru_act_rev/wizard/general_ledger_wizard_view.xml new file mode 100644 index 0000000..7ea248f --- /dev/null +++ b/l10n_ru_act_rev/wizard/general_ledger_wizard_view.xml @@ -0,0 +1,167 @@ + + + + + Акт сверки + general.ledger.act_revise.wizard + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +

+ General Ledger can be computed only if selected company have + only one unaffected earnings account. +

+ +
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + Акт сверки + general.ledger.act_revise.wizard + form + + new + + + + Печатать акт сверки + general.ledger.act_revise.wizard + + form + {'default_receivable_accounts_only': 1, 'default_payable_accounts_only': 1} + + new + + + + +
diff --git a/l10n_ru_attorney/README.md b/l10n_ru_attorney/README.md new file mode 100644 index 0000000..58c8d91 --- /dev/null +++ b/l10n_ru_attorney/README.md @@ -0,0 +1,21 @@ +# Российская локализация - Доверенность +name: l10n_ru_attorney + +## Описание +Создание списка доверенностей на получение ТМЦ и их печать. + +###Создание доверенности: +1. Меню Покупки - Доверенности - кнопка "Создать"; +2. На форме указываем: + + 2.1. Контрагент - поставщик; + + 2.2. Заказ на закупку; + + 2.3. Даты действия доверенности ("дата выдачи" и "действительно по"). + + +###Для печати: +1. Меню Настройки - Техническое - Отчеты; +2. Находим в списке l10n_ru_attorney и добавляем в меню "Печать"; +3. Открываем созданную запись доверенности - Действие - "Доверенность". \ No newline at end of file diff --git a/l10n_ru_attorney/__init__.py b/l10n_ru_attorney/__init__.py new file mode 100644 index 0000000..5305644 --- /dev/null +++ b/l10n_ru_attorney/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models \ No newline at end of file diff --git a/l10n_ru_attorney/__manifest__.py b/l10n_ru_attorney/__manifest__.py new file mode 100644 index 0000000..b076846 --- /dev/null +++ b/l10n_ru_attorney/__manifest__.py @@ -0,0 +1,42 @@ +# -*- 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', + ], +} diff --git a/l10n_ru_attorney/models/__init__.py b/l10n_ru_attorney/models/__init__.py new file mode 100644 index 0000000..0cad714 --- /dev/null +++ b/l10n_ru_attorney/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from . import base_consent +from . import hr_employee +from . import purchase_order \ No newline at end of file diff --git a/l10n_ru_attorney/models/base_consent.py b/l10n_ru_attorney/models/base_consent.py new file mode 100644 index 0000000..70df0bf --- /dev/null +++ b/l10n_ru_attorney/models/base_consent.py @@ -0,0 +1,46 @@ +# -*- 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['res.company']._company_default_get('base.consent'), + required=1) + + @api.model + def create(self, val): + name = self.env['ir.sequence'].next_by_code('base.consent') + if name: + if 'name' in val: + if val['name'] == False: + val.update({ + 'name': name, + }) + + result = super(BaseConsent, self).create(val) + return result + + @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 diff --git a/l10n_ru_attorney/models/hr_employee.py b/l10n_ru_attorney/models/hr_employee.py new file mode 100644 index 0000000..1e63258 --- /dev/null +++ b/l10n_ru_attorney/models/hr_employee.py @@ -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=_('Дата выдачи паспорта')) diff --git a/l10n_ru_attorney/models/purchase_order.py b/l10n_ru_attorney/models/purchase_order.py new file mode 100644 index 0000000..aa178c6 --- /dev/null +++ b/l10n_ru_attorney/models/purchase_order.py @@ -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=_('Доверенность')) diff --git a/l10n_ru_attorney/report/consent_report.xml b/l10n_ru_attorney/report/consent_report.xml new file mode 100644 index 0000000..d2dc293 --- /dev/null +++ b/l10n_ru_attorney/report/consent_report.xml @@ -0,0 +1,560 @@ + + + + + + + Доверенность + base.consent + (u'Доверенность - %s.pdf' % (object.name)) + qweb-html + l10n_ru_attorney.report_consent + + + + A4 + + A4 + 0 + 0 + Portrait + 15 + 15 + 7 + 7 + + 10 + 90 + + + + + diff --git a/l10n_ru_attorney/security/ir.model.access.csv b/l10n_ru_attorney/security/ir.model.access.csv new file mode 100644 index 0000000..ee8128f --- /dev/null +++ b/l10n_ru_attorney/security/ir.model.access.csv @@ -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 diff --git a/l10n_ru_attorney/views/base_consent_views.xml b/l10n_ru_attorney/views/base_consent_views.xml new file mode 100644 index 0000000..db8dc9a --- /dev/null +++ b/l10n_ru_attorney/views/base_consent_views.xml @@ -0,0 +1,65 @@ + + + + + Consents + base.consent + + + + + + + + + + + + + consent.form + base.consent + +
+
+ + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + Доверенности + base.consent + tree,form + + + + + + Consents + base.consent + CON + 5 + + + +
+
diff --git a/l10n_ru_attorney/views/hr_employee_views.xml b/l10n_ru_attorney/views/hr_employee_views.xml new file mode 100644 index 0000000..440c5d4 --- /dev/null +++ b/l10n_ru_attorney/views/hr_employee_views.xml @@ -0,0 +1,19 @@ + + + + + view_employee_form.inherit + hr.employee + + + + + + + + + + + + + diff --git a/l10n_ru_attorney/views/purchase_order_views.xml b/l10n_ru_attorney/views/purchase_order_views.xml new file mode 100644 index 0000000..4003990 --- /dev/null +++ b/l10n_ru_attorney/views/purchase_order_views.xml @@ -0,0 +1,16 @@ + + + + + purchase.order.form.inherit + purchase.order + + + + + + + + + diff --git a/l10n_ru_base/README.md b/l10n_ru_base/README.md new file mode 100644 index 0000000..d8b931c --- /dev/null +++ b/l10n_ru_base/README.md @@ -0,0 +1,16 @@ +# Российская локализация - Базовый +name: l10n_ru_base + +## Описание +Российская локализация: основные отчеты и печатные формы. Это базовый модуль для работы с модулями локализации. + +###Для включения модулей: +1. Меню Настройки - в боковом меню "Российская локализация"; +2. Выбирается нужный блок для подключения дополнительных возможностей по локализации. + +###Перечень модулей локализации: +1. Российская локализация - Акт сверки (l10n_ru_act_rev) +2. Российская локализация - Доверенность (l10n_ru_attorney) +3. Российская локализация - Договоры (l10n_ru_contract) +4. Российская локализация - Документы (l10n_ru_doc) +5. Российская локализация - УПД в xml-формате (l10n_ru_upd_xml) diff --git a/l10n_ru_base/__init__.py b/l10n_ru_base/__init__.py new file mode 100644 index 0000000..899bcc9 --- /dev/null +++ b/l10n_ru_base/__init__.py @@ -0,0 +1,2 @@ +from . import models + diff --git a/l10n_ru_base/__manifest__.py b/l10n_ru_base/__manifest__.py new file mode 100644 index 0000000..45f2703 --- /dev/null +++ b/l10n_ru_base/__manifest__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Российская локализация - Базовый>", + 'summary': """ + Российская локализация: основные отчеты и печатные формы. + """, + + 'description': """ + Российская локализация: основные отчеты и печатные формы. + + Для включения модулей: + 1. Меню Настройки - в боковом меню "Российская локализация" + 2. Выбирается нужный блок. + """, + + 'author': "MK.Lab", + 'website': "https://www.inf-centre.ru/", + + 'version': '17.0.1.0.0', + 'license': 'LGPL-3', + 'category': 'Uncategorized', + + 'depends': [], + + 'data': [ + 'views/res_config_settings_views.xml', + ], +} diff --git a/l10n_ru_base/i18n/ru_RU.po b/l10n_ru_base/i18n/ru_RU.po new file mode 100644 index 0000000..4e0f84e --- /dev/null +++ b/l10n_ru_base/i18n/ru_RU.po @@ -0,0 +1,109 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * base_russian_localization +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0+e-20240904\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-10-29 07:45+0000\n" +"PO-Revision-Date: 2024-10-29 07:45+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: base_russian_localization +#. odoo-python +#: code:addons/base_russian_localization/models/res_config_settings.py:0 +#: model:ir.model.fields,field_description:base_russian_localization.field_res_config_settings__module_act_revise +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +#, python-format +msgid "Act revise" +msgstr "Акт сверки" + +#. module: base_russian_localization +#: model:ir.model.fields,field_description:base_russian_localization.field_res_config_settings__company_status_rf +msgid "Company Status Rf" +msgstr "Статус компании" + +#. module: base_russian_localization +#: model:ir.model,name:base_russian_localization.model_res_config_settings +msgid "Config Settings" +msgstr "Параметры конфигурации" + +#. module: base_russian_localization +#. odoo-python +#: code:addons/base_russian_localization/models/res_config_settings.py:0 +#: model:ir.model.fields,field_description:base_russian_localization.field_res_config_settings__module_fehu_base_consent +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +#, python-format +msgid "Consent" +msgstr "Доверенность" + +#. module: base_russian_localization +#. odoo-python +#: code:addons/base_russian_localization/models/res_config_settings.py:0 +#: model:ir.model.fields,field_description:base_russian_localization.field_res_config_settings__module_contract +#, python-format +msgid "Contract" +msgstr "Договор" + +#. module: base_russian_localization +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +msgid "Contracts" +msgstr "Договоры" + +#. module: base_russian_localization +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +msgid "Powers of attorney" +msgstr "Доверенность на получение ТМЦ" + +#. module: base_russian_localization +#. odoo-python +#: code:addons/base_russian_localization/models/res_config_settings.py:0 +#: model:ir.model.fields,field_description:base_russian_localization.field_res_config_settings__module_l10n_ru_doc +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +#, python-format +msgid "Print forms" +msgstr "Печатные формы" + +#. module: base_russian_localization +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +msgid "Report act revise" +msgstr "Отчет Акт сверки" + +#. module: base_russian_localization +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +msgid "Report contract" +msgstr "Договоры" + +#. module: base_russian_localization +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +msgid "Report report_xml" +msgstr "УПД в формате xml для ЭДО" + +#. module: base_russian_localization +#. odoo-python +#: code:addons/base_russian_localization/models/res_config_settings.py:0 +#: model:ir.model.fields,field_description:base_russian_localization.field_res_config_settings__module_report_xml +#, python-format +msgid "Report_xml" +msgstr "Универсальный передаточный документ (УПД) в формате xml для ЭДО" + +#. module: base_russian_localization +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +msgid "Russian Localization" +msgstr "Российская локализация" + +#. module: base_russian_localization +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +msgid "UPD xml" +msgstr "УПД в формате xml для ЭДО" + +#. module: base_russian_localization +#: model_terms:ir.ui.view,arch_db:base_russian_localization.res_config_settings_view_form +msgid "print_forms" +msgstr "Печатные формы документов" diff --git a/l10n_ru_base/models/__init__.py b/l10n_ru_base/models/__init__.py new file mode 100644 index 0000000..4a30401 --- /dev/null +++ b/l10n_ru_base/models/__init__.py @@ -0,0 +1,4 @@ +from . import res_config_settings + + + diff --git a/l10n_ru_base/models/res_config_settings.py b/l10n_ru_base/models/res_config_settings.py new file mode 100644 index 0000000..60e3061 --- /dev/null +++ b/l10n_ru_base/models/res_config_settings.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + +_FIELDS_MODUL = [ + 'module_l10n_ru_act_rev', + 'module_l10n_ru_contract', + 'module_l10n_ru_upd_xml', + 'module_l10n_ru_doc', + 'module_l10n_ru_attorney' +] + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + module_l10n_ru_act_rev = fields.Boolean(_("Act revise")) + module_l10n_ru_contract = fields.Boolean(_("Contract")) + module_l10n_ru_upd_xml = fields.Boolean(_("Report_xml")) + module_l10n_ru_doc = fields.Boolean(_("Print forms")) + module_l10n_ru_attorney = fields.Boolean(_("Consent")) + + @api.model + def write(self, values): + company = self.env.company + if company.country_id.code != 'RU': + raise UserError("Признак Российской компании не обнаружен!") + if _FIELDS_MODUL: + missing_modules = set() + for field in _FIELDS_MODUL: + if self.mapped(field)[0]: + module_name = field[7:] + module_installed = self.env['ir.module.module'].search([('name', '=', module_name)], limit=1) + if not module_installed: + missing_modules.add(module_name) + if missing_modules: + message = "Обратитесь в тех.поддержку для получения лицензии для следующих модулей:\n" + \ + "\n".join(missing_modules) + raise UserError(message) + return super(ResConfigSettings, self).write(values) diff --git a/l10n_ru_base/static/description/icon.png b/l10n_ru_base/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..5ea24f8c0237018667c1537a5581be89262b0c34 GIT binary patch literal 4308 zcmeAS@N?(olHy`uVBq!ia0y~yV6J3fU<%}51B(2psIvl6jKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sBugD~Uq{1qt-3<8;+E{-7;ac^%L=FJTiaSJqexx%Ah zs-e8#q|FS4P^)JX*;2XYv9uoS^AMb?J@?ML+_k#8f48aL|982v>gW3B&!1mE&tIQ^ zdtd#pd)sRNf7zS+``^pz+u#0P{=V()@8$1vZ-4i{e|y{e`TMr#-nXx%r^4@hdu==? zsdxq{EBgbfNlucLAWG!aiOE1}Nr2ltAf?i3^a(_1PMN3s-P0;1h|AMI0-7Jj6e#R zVnAdQxU?Eo&M_J?qlsWN5j2pP2paOI?>TR8zxVH_#c}`NU;A=z$e{1}wLd@ndm68k W{QmBoKZ`&k6AYfNelF{r5}E)mk#imZ literal 0 HcmV?d00001 diff --git a/l10n_ru_base/views/res_config_settings_views.xml b/l10n_ru_base/views/res_config_settings_views.xml new file mode 100644 index 0000000..c60513a --- /dev/null +++ b/l10n_ru_base/views/res_config_settings_views.xml @@ -0,0 +1,42 @@ + + + + + res.config.settings.view.form.inherit.russian.localization + res.config.settings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_ru_contract/__init__.py b/l10n_ru_contract/__init__.py new file mode 100644 index 0000000..7db6694 --- /dev/null +++ b/l10n_ru_contract/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import models +from . import report diff --git a/l10n_ru_contract/__manifest__.py b/l10n_ru_contract/__manifest__.py new file mode 100644 index 0000000..c1ad9b9 --- /dev/null +++ b/l10n_ru_contract/__manifest__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +{ + 'name': 'Контракты клиентов', + 'version': '17.0.2024.02.02', + 'sequence': 0, + 'author': 'StarlingSoft', + 'website': 'https://inf-centre.ru', + 'depends': [ + 'base', + 'mail', + 'account', 'sale', 'sale_management', 'purchase' + ], + 'data': [ + 'data/data.xml', + 'views/contract_customer_view.xml', + 'security/ir.model.access.csv', + 'report/report_contract.xml', + 'report/report_contract_order.xml', + 'report/report_contract_order1.xml', + 'report/report_contract_invoce.xml', + + ], + 'installable': True, + 'auto_install': False, +} diff --git a/l10n_ru_contract/data/data.xml b/l10n_ru_contract/data/data.xml new file mode 100644 index 0000000..3b1bf11 --- /dev/null +++ b/l10n_ru_contract/data/data.xml @@ -0,0 +1,21 @@ + + + + + Договор последовательность клиент + partner.contract.customer.sequence + + + + 5 + + + Договор последовательность поставщик + partner.contract.supplier.sequence + + + + 5 + + + diff --git a/l10n_ru_contract/models/__init__.py b/l10n_ru_contract/models/__init__.py new file mode 100644 index 0000000..837d2e2 --- /dev/null +++ b/l10n_ru_contract/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import contract_customer, invoice_saleorder, dop_field, crutch_fields_header diff --git a/l10n_ru_contract/models/contract_customer.py b/l10n_ru_contract/models/contract_customer.py new file mode 100644 index 0000000..a9464d0 --- /dev/null +++ b/l10n_ru_contract/models/contract_customer.py @@ -0,0 +1,334 @@ +# -*- coding: utf-8 -*- +from odoo import api, fields, models, exceptions, tools +import pymorphy2 +from datetime import datetime, timedelta +from dateutil.relativedelta import relativedelta +from .crutch_fields_header import IP_CONTACT_HEADER, ENTITY_CONTRACT_HEADER, INDIVIDUAL_CONTRACT_HEADER + + +class PartnerContractCustomer(models.Model): + _name = 'partner.contract.customer' + _inherit = ['mail.thread', 'mail.activity.mixin', 'mail.render.mixin'] + + def get_dateend(self): + if self.date_start: + six_months = fields.Datetime.from_string(self.date_start) + relativedelta(months=+11) + else: + six_months = datetime.today() + relativedelta(months=+11) + return fields.Datetime.to_string(six_months) + + name = fields.Char(string='Номер') + date_start = fields.Date(string='Дата договора', required=True, default=fields.Datetime.now()) + partner_id = fields.Many2one('res.partner', string='Контрагент', required=True) + sec_partner_id = fields.Many2one('res.partner', string='Контрагент как в заказе') + company_id = fields.Many2one('res.company', string='Компания', required=True) + name_print = fields.Char(string='Имя для печати', compute='_get_name_print') + name_print1 = fields.Char(string='Имя для печати, И.П.', compute='_get_name_printip') + date_end = fields.Date(string='Дата окончания', required=True, default=get_dateend) + name_dirprint = fields.Char(string='Имя нашего директора для печати') + name_dirprint1 = fields.Char(string='Имя нашего директора для печати И.П.') + lines = fields.One2many('contract.line', 'contract_id', string='Договорные цены') + type = fields.Selection( + [('customer', 'С покупателем'), + ('supplier', 'С поставщиком'), + ('other', 'Прочие расчеты'), + + ], + string='Тип договора', default='customer', required=True) + saleorder_id = fields.Many2one('sale.order', string='Заказ/Сделка') + stamp = fields.Boolean(string='Печать и подпись') + signed = fields.Boolean(string='Договор подписан') + state = fields.Selection( + [('draft', 'Черновик'), + ('progress', 'На согласовании'), + ('signed', 'Подписан, действует'), + ('closed', 'Истёк'), + ], + string='Статус', default='draft', group_expand='_expand_states', index=True + ) + is_template = fields.Boolean('Это шаблон') + copy_from = fields.Many2one('partner.contract.customer', string='Копировать из этого шаблона') + profile_id = fields.Many2one('contract.profile', string='Вид договора', required=True) + credit_limit = fields.Float(string='Лимит кредита') + guid_1s = fields.Char('Код договора из 1С') + buh_code = fields.Char('Код договора из бухгалтерии') + payment_term_id = fields.Many2one('account.payment.term', string='Условие оплаты') + manager_id = fields.Many2one('res.users', string='Менеджер по продажам') + accountant_id = fields.Many2one('res.users', string='Бухгалтер по взаиморасчетам') + time_to_delivery_from = fields.Datetime('Время доставки от') + time_to_delivery_to = fields.Datetime('Время доставки до') + day_of_delivery = fields.Float('Дни доставки') + day_of_otgruzki = fields.Float('Дни отгрузки') + + channel_id = fields.Many2one('saleorder.channel', string='Канал продаж') + team_id = fields.Many2one('crm.team', string='Команда продаж') + order_days_ids = fields.Many2many(comodel_name='contract.day', relation='orderdays', string='Дни доставки', + column1='contract_id', column2='day_id') + shipment_days_ids = fields.Many2many(comodel_name='contract.day', relation='shipmentdays', string='Дни отгрузки', + column1='contract_id', + column2='day_id') + # Доработка хедера договора + partner_type = fields.Selection(string='Тип контрагента', selection=[ + ('person', 'Физ. лицо'), + ('company_ip', 'ИП'), + ('company', 'Юр. лицо') + ], required=True) + contract_header = fields.Html('Шапка договора') + + @api.onchange('partner_type') + def generate_contract_header(self): + self.ensure_one() + self.render_model = 'partner.contract.customer' + if self.partner_type == 'company_ip': + self.contract_header = IP_CONTACT_HEADER + elif self.partner_type == 'person': + self.contract_header = INDIVIDUAL_CONTRACT_HEADER + else: + self.contract_header = ENTITY_CONTRACT_HEADER + # # Рендер Jinja выражение типа {{object.field}} + result = self._render_template(self.contract_header, self.render_model, res_ids=[self.id]) + result = tools.html_sanitize(result[self.id]) + self.contract_header = result + + @api.onchange('sec_partner_id') + def set_pid(self): + self.partner_id = self.sec_partner_id.parent_id if self.sec_partner_id.parent_id else self.sec_partner_id + + def _expand_states(self, states, domain, order): + return [key for key, val in type(self).state.selection] + + def copy_it(self): + if self.copy_from: + for line in self.copy_from.lines: + line.copy({'contract_id': self.id}) + + def _get_name_print(self): + morph = pymorphy2.MorphAnalyzer() + self.name_print = False + director = self.env['res.partner'].search([('parent_id', '=', self.partner_id.id), ('type', '=', 'director')], + limit=1) + if director: + if len(director.name.split(' ')) == 3: + lastname_old, firstname_old, middlename_old = director.name.split(' ') + + if lastname_old: + lastname_n = morph.parse(lastname_old)[0] + if lastname_n.inflect({'gent'}): + lastname_n = lastname_n.inflect({'gent'}).word + else: + lastname_n = lastname_old + else: + lastname_n = '' + + if firstname_old: + firstname_n = morph.parse(firstname_old)[0] + firstname_n = firstname_n.inflect({'gent'}).word + else: + firstname_n = '' + + if middlename_old: + middlename_n = morph.parse(middlename_old)[0] + middlename_n = middlename_n.inflect({'gent'}).word + else: + middlename_n = '' + + name_print = lastname_n + ' ' + firstname_n + ' ' + middlename_n + + self.name_print = name_print.title() + + def _get_name_print1(self): + # morph = pymorphy2.MorphAnalyzer() + director = self.company_id.chief_id.partner_id if self.company_id.chief_id else False + # raise exceptions.UserError(str(director)) + self.name_dirprint = False + if director: + if len(director.name.split(' ')) == 3: + lastname_old, firstname_old, middlename_old = director.name.split(' ') + + if lastname_old: + lastname_n = morph.parse(lastname_old)[0] + lastname_n = lastname_n.inflect({'gent'}).word + else: + lastname_n = '' + + if firstname_old: + firstname_n = morph.parse(firstname_old)[0] + firstname_n = firstname_n.inflect({'gent'}).word + else: + firstname_n = '' + + if middlename_old: + middlename_n = morph.parse(middlename_old)[0] + middlename_n = middlename_n.inflect({'gent'}).word + else: + middlename_n = '' + + name_print = lastname_n + ' ' + firstname_n + ' ' + middlename_n + + self.name_dirprint = name_print.title() + + @api.model + def create(self, values): + res = super(PartnerContractCustomer, self).create(values) + + if values.get('is_template'): + return res + + if values.get('type') == 'customer': + sequence_code = 'partner.contract.customer.sequence' + elif values.get('type') == 'supplier': + sequence_code = 'partner.contract.supplier.sequence' + else: + return res + + name = self.env['ir.sequence'].next_by_code(sequence_code) + + res.update({ + 'name': name, + }) + + return res + + # @api.model + def write(self, values): + + if 'state' in values: + if self.state != values['state']: + msg = 'Статус: ' + dict(self._fields['state'].selection).get(self.state) + ' -> ' + dict( + self._fields['state'].selection).get(values['state']) + self.message_post(body=msg) + res = super(PartnerContractCustomer, self).write(values) + return res + + def _get_name_print1ip(self): + self.name_dirprint1 = self.company_id.chief_id.partner_id.name if self.company_id.chief_id else False + + def _get_name_printip(self): + self.name_print1 = False + director = self.env['res.partner'].search([('parent_id', '=', self.partner_id.id), ('type', '=', 'director')], + limit=1) + if director: + self.name_print1 = director.name + + def print_supp(self): + # self.filtered(lambda s: s.state == 'draft').write({'state': 'sent'}) + return self.env['report'].get_action(self, 'mta_base.action_mtacontractsupp_report') + + def print_contract_cust(self): + if self.saleorder_id: + return self.saleorder_id.print_contract() + else: + raise exceptions.UserError( + 'Вы не можете напечатать договор с Клиентом, потому что нет связи с Заказом. Нужно зайти в Заказ и привязать этот договор.') + + def contract_action_confirm(self): + if self.state == 'draft': + self.state = 'progress' + elif self.state == 'progress': + self.state = 'signed' + + def contract_in_draft(self): + self.state = 'draft' + + @api.onchange('name') + def set_comp_and_partn(self): + context = self._context + order_id = context.get('sale_order_id') + if order_id: + sale_order = self.env['sale.order'].browse(order_id) + + self.company_id = sale_order.company_id + self.partner_id = sale_order.partner_id + + @api.onchange('profile_id') + def set_payment(self): + if self.profile_id.payment_term_id: + self.payment_term_id = self.profile_id.payment_term_id + + # @api.constrains('name') + def check_name(self): + obj = self.search([('name', '=', self.name), ('id', '!=', self.id), ('state', '!=', 'closed')]) + if obj: + raise exceptions.ValidationError('Договор с таким номером уже существует') + + """ + @api.constrains('profile_id') + def check_profile_id(self): + contracts = self.search([('partner_id', '=', self.partner_id.id), ('id', '!=', self.id)]) + if contracts: + profiles_in_contracts = contracts.profile_id + # raise exceptions.ValidationError(profiles_in_contracts.ids) + if profiles_in_contracts: + ads = self.env['contract.allowed.profiles'].search( + [('allowed_profiles', 'in', profiles_in_contracts.ids)]) + if ads: + raise exceptions.ValidationError((self.profile_id.name, ads.name)) + # raise exceptions.ValidationError(contracts) + """ + + +class Partner(models.Model): + _inherit = 'res.partner' + + contract_count = fields.Integer(string='Договоры', compute='get_count_contract') + pol = fields.Selection(string="Пол", selection=[('m', 'Муж.'), ('j', 'Жен'), ], required=False) + type = fields.Selection(selection_add=[('director', 'Директор')]) + + def get_count_contract(self): + contract = self.env['partner.contract.customer'] + self.contract_count = contract.search_count([('partner_id', '=', self.id)]) + + def action_view_contract(self): + action = self.env.ref('contract.contract_customer_action').read()[0] + + action['domain'] = [('partner_id', '=', self.id)] + + return action + + +class ContractLine(models.Model): + _name = 'contract.line' + contract_id = fields.Many2one('partner.contract.customer', string='Order Reference', required=True, + ondelete='cascade', index=True, copy=False) + _order = "sequence desc" + # name = fields.Text(string='Название для договора') + # price_unit = fields.Float('Цена', default=0.0) + # product_uom = fields.Many2one('uom.uom', string='Единица измерения') + # product_id = fields.Many2one('product.product', string='Услуга', domain=[('sale_ok', '=', True)], change_default=True, ondelete='restrict') + sequence = fields.Integer('Порядок') + name = fields.Char('Номер пункта') + punct = fields.Html('Текст пункта') + + @api.onchange('product_id') + def set_name(self): + self.name = self.product_id.name + + +class AllowedProfiles(models.Model): + _name = 'contract.allowed.profiles' + name = fields.Char(string='Одновременно включены следующие виды договоров:') + allowed_profiles = fields.Many2many('contract.profile', string='Виды договоров', required=True) + + @api.onchange('allowed_profiles') + def set_name(self): + self.name = '' + for profile in self.allowed_profiles: + self.name += profile.name + ' + ' + if self.name: + if self.name[-2] == '+': + self.name = self.name[:-2] + + +class ContractProfile(models.Model): + _name = 'contract.profile' + name = fields.Char(string='Вид договора', required=True) + payable_account_id = fields.Many2one('account.account', string='Счет кредиторской задолженности', required=True) + receivable_account_id = fields.Many2one('account.account', string='Счет дебиторской задолженности', required=True) + max_receivable_id = fields.Float(string='Максимальная деб. задолженность', required=True) + payment_term_id = fields.Many2one('account.payment.term', string='Условие оплаты', required=True) + journal_id = fields.Many2one('account.journal', string='Журнал', required=True) + + +class ContractDay(models.Model): + _name = 'contract.day' + name = fields.Char('День') diff --git a/l10n_ru_contract/models/crutch_fields_header.py b/l10n_ru_contract/models/crutch_fields_header.py new file mode 100644 index 0000000..f290eff --- /dev/null +++ b/l10n_ru_contract/models/crutch_fields_header.py @@ -0,0 +1,33 @@ +ENTITY_CONTRACT_HEADER = """ +{{object.company_id.partner_id.name}}, +именуемое в дальнейшем «Поставщик», в лице +{{(object.company_id.chief_id.partner_id.function or '').lower()}} +{{(object.name_dirprint1 or '').title()}}, + действующего на основании ОГРНИП № {{object.company_id.company_registry or ''}}, с одной стороны, и {{object.partner_id.name or ''}}, +именуемое в дальнейшем «Покупатель», в лице +{{(object.get_function_partner1(object.partner_id.id) or '').lower()}} +{{(object.name_print1 or '').title()}}, действующего на основании устава общества, с другой стороны, вместе именуемые в дальнейшем «Стороны» заключили +настоящий Договор о нижеследующем: + """ +IP_CONTACT_HEADER = """ +{{object.company_id.partner_id.name}}, +именуемое в дальнейшем «Поставщик», в лице +{{(object.company_id.chief_id.partner_id.function or '').lower()}} +{{(object.name_dirprint1 or '').title()}}, + действующего на основании ОГРНИП № {{object.company_id.company_registry or ''}}, с одной стороны, и {{object.partner_id.name or ''}}, +именуемое в дальнейшем «Покупатель», в лице +{{(object.get_function_partner1(object.partner_id.id) or '').lower()}} +{{(object.name_print1 or '').title()}}, действующего на основании ОГРНИП №{{object.partner_id.ogrn or ''}}, + с другой стороны, вместе именуемые в дальнейшем «Стороны» заключили +настоящий Договор о нижеследующем: +""" + +INDIVIDUAL_CONTRACT_HEADER = """ +{{object.company_id.partner_id.name}}, +именуемое в дальнейшем «Поставщик», в лице +{{(object.company_id.chief_id.partner_id.function or '').lower()}} +{{(object.name_dirprint1 or '').title()}}, + действующего на основании ОГРНИП № {{object.company_id.company_registry or ''}}, с одной стороны, и {{object.partner_id.name or ''}}, +именуемое в дальнейшем «Покупатель», вместе именуемые в дальнейшем «Стороны» заключили +настоящий Договор о нижеследующем: + """ diff --git a/l10n_ru_contract/models/dop_field.py b/l10n_ru_contract/models/dop_field.py new file mode 100644 index 0000000..9c8626d --- /dev/null +++ b/l10n_ru_contract/models/dop_field.py @@ -0,0 +1,353 @@ +from odoo import api, fields, models, exceptions +from datetime import datetime +import re +import pymorphy2 +from odoo.tools import pycompat + +FRACTIONS = ( + (u"десятая", u"десятых", u"десятых"), + (u"сотая", u"сотых", u"сотых"), + (u"тысячная", u"тысячных", u"тысячных"), + (u"десятитысячная", u"десятитысячных", u"десятитысячных"), + (u"стотысячная", u"стотысячных", u"стотысячных"), + (u"миллионная", u"милллионных", u"милллионных"), + (u"десятимиллионная", u"десятимилллионных", u"десятимиллионных"), + (u"стомиллионная", u"стомилллионных", u"стомиллионных"), + (u"миллиардная", u"миллиардных", u"миллиардных"), +) + +ONES = { + 0: (u"", u"", u""), + 1: (u"один", u"одна", u"одно"), + 2: (u"два", u"две", u"два"), + 3: (u"три", u"три", u"три"), + 4: (u"четыре", u"четыре", u"четыре"), + 5: (u"пять", u"пять", u"пять"), + 6: (u"шесть", u"шесть", u"шесть"), + 7: (u"семь", u"семь", u"семь"), + 8: (u"восемь", u"восемь", u"восемь"), + 9: (u"девять", u"девять", u"девять"), +} + +TENS = { + 0: u"", + 10: u"десять", + 11: u"одиннадцать", + 12: u"двенадцать", + 13: u"тринадцать", + 14: u"четырнадцать", + 15: u"пятнадцать", + 16: u"шестнадцать", + 17: u"семнадцать", + 18: u"восемнадцать", + 19: u"девятнадцать", + 2: u"двадцать", + 3: u"тридцать", + 4: u"сорок", + 5: u"пятьдесят", + 6: u"шестьдесят", + 7: u"семьдесят", + 8: u"восемьдесят", + 9: u"девяносто", +} + +HUNDREDS = { + 0: u"", + 1: u"сто", + 2: u"двести", + 3: u"триста", + 4: u"четыреста", + 5: u"пятьсот", + 6: u"шестьсот", + 7: u"семьсот", + 8: u"восемьсот", + 9: u"девятьсот", +} + +MALE = 1 +FEMALE = 2 + +import operator +import sys +import types + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + +class Partner_Bank(models.Model): + _inherit = 'res.partner.bank' + bank_corr_acc = fields.Char('Кор.счет') + + +# class Bank(models.Model): +# _inherit = 'res.bank' + +# corr_acc = fields.Char('Corresponding account', size=64) + +# class Users(models.Model): +# _inherit = 'res.users' + +# facsimile = fields.Binary("Facsimile") + +class Company(models.Model): + _inherit = 'res.company' + + inn = fields.Char(related='partner_id.inn', readonly=False) + kpp = fields.Char(related='partner_id.kpp', readonly=False) + okpo = fields.Char(related='partner_id.okpo', readonly=False) + chief_id = fields.Many2one('res.users', 'Имя директора') + stamp = fields.Binary("Stamp") + + +class Partner(models.Model): + _inherit = 'res.partner' + ogrn = fields.Char('ОГРН') + okpo = fields.Char('ОКПО') + inn = fields.Char('ИНН') + kpp = fields.Char('KPP') + passport = fields.Char('Паспорт') + + +class Report_contract_customer(models.Model): + _inherit = 'partner.contract.customer' + + def img(self, img, type='png', width=0, height=0): + if width: + width = "width='%spx'" % (width) + else: + width = " " + if height: + height = "height='%spx'" % (height) + else: + height = " " + toreturn = "" % ( + width, + height, + type, + str(pycompat.to_text(img))) + return toreturn + + def numer(self, name): + if name: + numeration = re.findall('\d+$', name) + if numeration: return numeration[0] + return '' + + def ru_date(self, date): + if date and date != 'False': + return dt.ru_strftime(u'"%d" %B %Y года', date=datetime.strptime(str(date), "%Y-%m-%d"), inflected=True) + return '' + + def ru_date2(self, date): + if date and date != 'False': + return dt.ru_strftime(u'%d %B %Y г.', date=datetime.strptime(str(date), "%Y-%m-%d %H:%M:%S"), + inflected=True) + return '' + + def in_words(self, number): + return numeral.in_words(number) + + def rubles(self, sum): + "Transform sum number in rubles to text" + text_rubles = self.numeral_rubles(int(sum)) + copeck = round((sum - int(sum)) * 100) + text_copeck = self.numeral_choose_plural(int(copeck), (u"копейка", u"копейки", u"копеек")) + return ("%s %02d %s") % (text_rubles, copeck, text_copeck) + + def numeral_rubles(self, amount, zero_for_kopeck=False): + self.check_positive(amount) + pts = [] + amount = round(amount, 2) + pts.append(self.sum_string(int(amount), 1, (u"рубль", u"рубля", u"рублей"))) + remainder = self._get_float_remainder(amount, 2) + iremainder = int(remainder) + + if iremainder != 0 or zero_for_kopeck: + if iremainder < 10 and len(remainder) == 1: + iremainder *= 10 + pts.append(self.sum_string(iremainder, 2, + (u"копейка", u"копейки", u"копеек"))) + return u" ".join(pts) + + def _get_float_remainder(self, fvalue, signs=9): + self.check_positive(fvalue) + if isinstance(fvalue, integer_types): + return "0" + if isinstance(fvalue, Decimal) and fvalue.as_tuple()[2] == 0: + return "0" + + def sum_string(self, amount, gender, items=None): + if isinstance(items, text_type): + items = split_values(items) + if items is None: + items = (u"", u"", u"") + try: + one_item, two_items, five_items = items + except ValueError: + raise ValueError("Items must be 3-element sequence") + self.check_positive(amount) + if amount == 0: + return u"ноль %s" % five_items + into = u'' + tmp_val = amount + into, tmp_val = self._sum_string_fn(into, tmp_val, gender, items) + into, tmp_val = self._sum_string_fn(into, tmp_val, FEMALE, + (u"тысяча", u"тысячи", u"тысяч")) + into, tmp_val = self._sum_string_fn(into, tmp_val, MALE, + (u"миллион", u"миллиона", u"миллионов")) + into, tmp_val = self._sum_string_fn(into, tmp_val, MALE, + (u"миллиард", u"миллиарда", u"миллиардов")) + if tmp_val == 0: + return into + else: + raise ValueError("Cannot operand with numbers bigger than 10**11") + + def _sum_string_fn(self, into, tmp_val, gender, items=None): + if items is None: + items = (u"", u"", u"") + one_item, two_items, five_items = items + self.check_positive(tmp_val) + if tmp_val == 0: + return into, tmp_val + words = [] + rest = tmp_val % 1000 + tmp_val = tmp_val // 1000 + if rest == 0: + if into == u"": + into = u"%s " % five_items + return into, tmp_val + end_word = five_items + words.append(HUNDREDS[rest // 100]) + rest = rest % 100 + rest1 = rest // 10 + tens = rest1 == 1 and TENS[rest] or TENS[rest1] + words.append(tens) + if rest1 < 1 or rest1 > 1: + amount = rest % 10 + end_word = self.numeral_choose_plural(amount, items) + words.append(ONES[amount][gender - 1]) + words.append(end_word) + words.append(into) + words = filter(lambda x: len(x) > 0, words) + return u" ".join(words).strip(), tmp_val + + def check_positive(self, value, strict=False): + if not strict and value < 0: + raise ValueError("Value must be positive or zero, not %s" % str(value)) + if strict and value <= 0: + raise ValueError("Value must be positive, not %s" % str(value)) + + def numeral_choose_plural(self, amount, variants): + if isinstance(variants, text_type): + variants = split_values(variants) + self.check_length(variants, 3) + amount = abs(amount) + if amount % 10 == 1 and amount % 100 != 11: + variant = 0 + elif amount % 10 >= 2 and amount % 10 <= 4 and \ + (amount % 100 < 10 or amount % 100 >= 20): + variant = 1 + else: + variant = 2 + return variants[variant] + + def check_length(self, value, length): + _length = len(value) + if _length != length: + raise ValueError("length must be %d, not %d" % \ + (length, _length)) + + def initials(self, fio): + if fio: + return (fio.split()[0] + ' ' + ''.join([fio[0:1] + '.' for fio in fio.split()[1:]])).strip() + return '' + + def address(self, partner): + repr = [] + if partner.zip: repr.append(partner.zip) + if partner.city: repr.append(partner.city) + if partner.street: repr.append(partner.street) + if partner.street2: repr.append(partner.street2) + return ', '.join(repr) + + def address_delivery(self, partner): + if partner: + addr = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'delivery')], limit=1) + repr = [] + if addr: + if addr.zip: repr.append(addr.zip) + if addr.city: repr.append(addr.city) + if addr.street: repr.append(addr.street) + if addr.street2: repr.append(addr.street2) + return ', '.join(repr) + + def get_function_print(self, function): + morph = pymorphy2.MorphAnalyzer() + if function: + f = morph.parse(function)[0] + f = f.inflect({'gent'}).word + return f.title() + + def get_function_partnerip(self, partner): + director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1) + if director: + if director.function: + return director.function + + def get_function_partner(self, partner): + res = [] + morph = pymorphy2.MorphAnalyzer() + if partner: + director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1) + if director: + if director.function: + list_f = str(director.function).split(' ') + for func in list_f: + f = morph.parse(func)[0] + f = f.inflect({'gent'}).word + res.append(f) + return ' '.join(res) + + def get_function_partner1(self, partner): + if partner: + director = self.env['res.partner'].search([('parent_id', '=', partner), ('type', '=', 'director')], limit=1) + if director: + if director.function: + return director.function + + def get_date_text(self, date): + month_list = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', + 'ноября', 'декабря'] + if date: + date_list = str(date).split('-') + if date_list[0] and date_list[1] and date_list[2]: + return ('"' + date_list[2] + '" ' + month_list[int(date_list[1]) - 1] + ' ' + date_list[0] + ' г.') + + def get_bank(self, partner): + repr = [] + bank = None + if partner.bank_ids: + bank = partner.bank_ids[0] + elif partner.parent_id.bank_ids: + bank = partner.parent_id.bank_ids[0] + if bank and bank.bank_name: repr.append(bank.bank_name) + if bank and bank.acc_number: repr.append(u"Р/счет " + bank.acc_number) + if bank and bank.bank_bic: repr.append(u"БИК " + bank.bank_bic) + if bank and bank.bank_corr_acc: repr.append(u"к/с " + bank.bank_corr_acc) + return '
'.join(repr) diff --git a/l10n_ru_contract/models/invoice_saleorder.py b/l10n_ru_contract/models/invoice_saleorder.py new file mode 100644 index 0000000..3bfa5bd --- /dev/null +++ b/l10n_ru_contract/models/invoice_saleorder.py @@ -0,0 +1,128 @@ +from odoo import api, fields, models, exceptions +from datetime import datetime + + +class contract_sale_order(models.Model): + _inherit = 'sale.order' + mt_contractid = fields.Many2one('partner.contract.customer', string='Номер договора') + sec_partner_id = fields.Many2one('res.partner', string='Контрагент', store=True, compute='get_pid') + stamp = fields.Boolean(string='Печать и подпись', related='mt_contractid.stamp') + + @api.depends('partner_id') + def get_pid(self): + for s in self: + s.sec_partner_id = s.partner_id.parent_id if s.partner_id.parent_id else s.partner_id + + @api.onchange('mt_contractid') + def set_ons(self): + if self.mt_contractid: + self.payment_term_id = self.mt_contractid.payment_term_id + + @api.constrains('state') + def late_payment_check(self): + if self.mt_contractid: + if self.state == 'sale': + late_invoices_count = 0 + max_receivable = self.mt_contractid.profile_id.max_receivable_id # макс. деб. задолженность в договоре + # ищу просроченные инвойсы контрагента указанного в заказе со стейтом "Подтверждено" + invoices_obj = self.env['account.move'].search([('partner_id', '=', self.partner_id.id), + ('state', '=', 'posted'), + ('invoice_date_due', '<', datetime.now().date())]) + + for invoice in invoices_obj: + late_invoices_count += invoice.amount_residual # складываю деб. задолженность по просроченным инвойсам + + if late_invoices_count > max_receivable: + raise exceptions.ValidationError( + f'Нельзя подтвердить заказ, так как у контрагента {self.sec_partner_id.name} нарушено ' + f'условие по дебиторской задолженности.\n\n' + f'Контрагент {self.sec_partner_id.name} должен {late_invoices_count}руб.\n' + f'Максимальная дебиторская задолженность указанная в ' + f'договоре №{self.mt_contractid.name} - {max_receivable}руб.\n\n' + f'Проверьте следующие неоплаченные счета контрагента:\n' + f'{", ".join([invoice.name for invoice in invoices_obj])}') + + # при выбора счета "Обычный счет" + @api.model + def _create_invoices(self, grouped=False, final=False, date=None): + res = super(contract_sale_order, self)._create_invoices(grouped, final, date) + if self.mt_contractid: + res.write({'mt_contractid': self.mt_contractid, + 'journal_id': self.mt_contractid.profile_id.journal_id}) + # 'invoice_payment_term_id': self.mt_contractid.profile_id.payment_term_id + # 'line_ids': [(0, 0, { + # 'account_id': self.mt_contractid.profile_id.receivable_account_id.id})] + return res + + +class ContractCreateInvoice(models.TransientModel): + _inherit = 'sale.advance.payment.inv' + + # при выбора счета "Авансовый платеж" + @api.model + def _create_invoice(self, order, so_line, amount): + res = super(ContractCreateInvoice, self)._create_invoice(order, so_line, amount) + if order.mt_contractid: + res.write({'mt_contractid': order.mt_contractid, + 'journal_id': order.mt_contractid.profile_id.journal_id, }) + # 'invoice_payment_term_id': order.mt_contractid.profile_id.payment_term_id + return res + + +class contract_invoice(models.Model): + _inherit = 'account.move' + mt_contractid = fields.Many2one('partner.contract.customer', string='Номер договора') + sf_number = fields.Char(string='Номер с/ф') + osnovanie = fields.Char(string='Основание') + sec_partner_id = fields.Many2one('res.partner', string='Контрагент', store=True, compute='get_pid') + stamp = fields.Boolean(string='Печать и подпись', related='mt_contractid.stamp') + + @api.depends('partner_id') + def get_pid(self): + for s in self: + s.sec_partner_id = s.partner_id.parent_id if s.partner_id.parent_id else s.partner_id + + @api.onchange('mt_contractid') + def set_ons(self): + if self.mt_contractid: + self.osnovanie = 'Договор № ' + self.mt_contractid.name + ' от ' + fields.Datetime.from_string( + self.mt_contractid.date_start).strftime("%d.%m.%Y") + + @api.constrains('state') + def invoice_fields_check(self): + for s in self: + if s.state == 'posted': + if s.mt_contractid: + errors_list = [] + journal_in_contract = s.mt_contractid.profile_id.journal_id + payment_term_in_contract = s.mt_contractid.profile_id.payment_term_id + receivable_in_contract = s.mt_contractid.profile_id.receivable_account_id + + if journal_in_contract != s.journal_id: + errors_list.append(f'Отличается Журнал - [{s.journal_id.name}] ' + f'и указанный в договоре №{s.mt_contractid.name} ' + f'Журнал - [{journal_in_contract.name}]\n\n') + + if payment_term_in_contract != s.invoice_payment_term_id: + errors_list.append(f'Отличается поле "Условие оплаты" в инвойсе ' + f'[Условие оплаты - {s.invoice_payment_term_id.name}] ' + f'и указанный в договоре №{s.mt_contractid.name} ' + f'[Условие оплаты - {payment_term_in_contract.name}]\n\n') + + if receivable_in_contract not in s.line_ids.account_id: + errors_list.append(f'Отличается поле "Счет дебиторской задолженности" в инвойсе ' + f'и указанный в договоре №{s.mt_contractid.name}') + + if errors_list: + raise exceptions.ValidationError(''.join(errors_list)) + + +class contact_purchase_order(models.Model): + _inherit = 'purchase.order' + mt_contractid = fields.Many2one('partner.contract.customer', string='Номер договора') + sec_partner_id = fields.Many2one('res.partner', string='Контрагент', store=True, compute='get_pid') + + @api.depends('partner_id') + def get_pid(self): + for s in self: + s.sec_partner_id = s.partner_id.parent_id if s.partner_id.parent_id else s.partner_id diff --git a/l10n_ru_contract/report/__init__.py b/l10n_ru_contract/report/__init__.py new file mode 100644 index 0000000..6527450 --- /dev/null +++ b/l10n_ru_contract/report/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import report_contract,report_contract_order,report_contract_invoce diff --git a/l10n_ru_contract/report/report_contract.py b/l10n_ru_contract/report/report_contract.py new file mode 100644 index 0000000..3baf414 --- /dev/null +++ b/l10n_ru_contract/report/report_contract.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +from odoo import api, models + +class ContractCustomerReport(models.AbstractModel): + _name = 'contract.customer.report' + + + def get_report_values(self, docids, data=None): + docs = self.env['partner.contract.customer'].browse(docids) + return { + 'doc_ids': docs.ids, + 'doc_model': 'partner.contract.customer', + 'docs': docs, + } diff --git a/l10n_ru_contract/report/report_contract.xml b/l10n_ru_contract/report/report_contract.xml new file mode 100644 index 0000000..361871d --- /dev/null +++ b/l10n_ru_contract/report/report_contract.xml @@ -0,0 +1,398 @@ + + + + + + A4 + + A4 + 0 + 0 + Portrait + 15 + 30 + 7 + 7 + + 10 + 90 + + + + Договор + partner.contract.customer + qweb-pdf + contract.report_contract_customer + contract.report_contract_customer + 'Договор - %s' % (object.name) + + + report + + diff --git a/l10n_ru_contract/report/report_contract_invoce.py b/l10n_ru_contract/report/report_contract_invoce.py new file mode 100644 index 0000000..f07f090 --- /dev/null +++ b/l10n_ru_contract/report/report_contract_invoce.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from odoo import api, models + + +class ContractCustomerReportOrder(models.AbstractModel): + _name = 'contract.customer.report_invoce' + + + def get_report_values(self, docids, data=None): + docs = self.env['account.move'].browse(docids) + return { + 'doc_ids': docs.ids, + 'doc_model': 'account.move', + 'docs': docs, + } diff --git a/l10n_ru_contract/report/report_contract_invoce.xml b/l10n_ru_contract/report/report_contract_invoce.xml new file mode 100644 index 0000000..634df7f --- /dev/null +++ b/l10n_ru_contract/report/report_contract_invoce.xml @@ -0,0 +1,592 @@ + + + + + + A4 + + A4 + 0 + 0 + Portrait + 15 + 30 + 7 + 7 + + 10 + 90 + + + + Договор со спецификацией + account.move + qweb-pdf + contract.report_contract_customer_invoce + contract.report_contract_customer_invoce + 'Договор со спецификацией - %s' % (object.name) + + + report + + diff --git a/l10n_ru_contract/report/report_contract_order.py b/l10n_ru_contract/report/report_contract_order.py new file mode 100644 index 0000000..42a679d --- /dev/null +++ b/l10n_ru_contract/report/report_contract_order.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from odoo import api, models + + +class ContractCustomerReportOrder(models.AbstractModel): + _name = 'contract.customer.report_order' + + + def get_report_values(self, docids, data=None): + docs = self.env['sale.order'].browse(docids) + return { + 'doc_ids': docs.ids, + 'doc_model': 'sale.order', + 'docs': docs, + } + + + diff --git a/l10n_ru_contract/report/report_contract_order.xml b/l10n_ru_contract/report/report_contract_order.xml new file mode 100644 index 0000000..4e03297 --- /dev/null +++ b/l10n_ru_contract/report/report_contract_order.xml @@ -0,0 +1,594 @@ + + + + + + A4 + + A4 + 0 + 0 + Portrait + 15 + 30 + 7 + 7 + + 10 + 90 + + + + Договор со спецификацией + sale.order + qweb-pdf + contract.report_contract_customer_order + contract.report_contract_customer_order + 'Договор со спецификацией - %s' % (object.name) + + + report + + diff --git a/l10n_ru_contract/report/report_contract_order1.xml b/l10n_ru_contract/report/report_contract_order1.xml new file mode 100644 index 0000000..2b8a887 --- /dev/null +++ b/l10n_ru_contract/report/report_contract_order1.xml @@ -0,0 +1,406 @@ + + + + + + A4 + + A4 + 0 + 0 + Portrait + 15 + 30 + 7 + 7 + + 10 + 90 + + + + Спецификация + sale.order + qweb-pdf + contract.report_contract_customer_order1 + contract.report_contract_customer_order1 + 'Спецификация - %s' % (object.name) + + + report + + diff --git a/l10n_ru_contract/security/ir.model.access.csv b/l10n_ru_contract/security/ir.model.access.csv new file mode 100644 index 0000000..4f09569 --- /dev/null +++ b/l10n_ru_contract/security/ir.model.access.csv @@ -0,0 +1,6 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_partner_contract_customer,access_partner_contract_customer,model_partner_contract_customer,,1,1,1,1 +access_contract_profile,access_contract_profile,model_contract_profile,,1,1,1,1 +access_contract_day,access_contract_day,model_contract_day,,1,1,1,1 +access_contract_allowed_profiles,access_contract_allowed_profiles,model_contract_allowed_profiles,,1,1,1,1 +access_partner_contract_customerline,access_partner_contract_customerline,model_contract_line,,1,1,1,1 diff --git a/l10n_ru_contract/views/contract_customer_view.xml b/l10n_ru_contract/views/contract_customer_view.xml new file mode 100644 index 0000000..ca1ecd9 --- /dev/null +++ b/l10n_ru_contract/views/contract_customer_view.xml @@ -0,0 +1,358 @@ + + + + + + Договор + partner.contract.customer + +
+
+ +
+ +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + view_saleorder_form + sale.order + + + + + + + + + + + + + view_purchaseorder_formcontr + purchase.order + + + + + + + + + + + + + + view_invoice_form + account.move + + + + + + + + + + + + + + + + Договор + partner.contract.customer + + + + + + + + + + +
+
+
+ Номер: +
+
+ Контрагент:
+ Тип:
+ Вид договора: +
+
+ Наша компания: +
+
+
+
+
+
+ + +
+
+ + + + + + + + + + + + + + + + +
+
diff --git a/l10n_ru_doc/__init__.py b/l10n_ru_doc/__init__.py new file mode 100644 index 0000000..10a94a5 --- /dev/null +++ b/l10n_ru_doc/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from . import models +from . import report_helper +from . import report diff --git a/l10n_ru_doc/__manifest__.py b/l10n_ru_doc/__manifest__.py new file mode 100644 index 0000000..49537f1 --- /dev/null +++ b/l10n_ru_doc/__manifest__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Russia - Documents", + + 'summary': "Первичные документы", + + 'description': """ +The module for print documents in accordance laws of Russia. +============================================================ +Возможности: + * Товарная накладная (ТОРГ-12) + * Счет на оплату + * Счет-фактура + * Акт выполненных работ + * Вывод подписей и печати + """, + + 'author': "CodUP and MKLab", + 'website': "https://inf-centre.ru", + + 'license': 'AGPL-3', + 'category': 'Localization', + 'version': '17.0.2024.06.28', + + 'depends': ['base','sale','account','sale_stock','uom'], + + 'external_dependencies': {'python' : ['pytils']}, + + 'data': [ + 'views/account_invoice_view.xml', + 'views/res_partner_view.xml', + 'views/res_company_view.xml', + 'views/res_users_view.xml', + 'views/res_bank_view.xml', + 'views/uom.xml', + 'views/tax.xml', + 'views/product.xml', + 'views/l10n_ru_doc_data.xml', + 'report/l10n_ru_doc_report.xml', + 'report/report_order.xml', + 'report/report_invoice.xml', + 'report/report_bill.xml', + 'report/report_act.xml', + 'report/report_upd.xml', + 'report/report_updn.xml', + ], + + 'demo': [ + 'demo/l10n_ru_doc_demo.xml', + ], +} diff --git a/l10n_ru_doc/__pycache__/__init__.cpython-310.pyc b/l10n_ru_doc/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59706c9521038cecf93a70179385c40553fb15cf GIT binary patch literal 240 zcmYk0OA5k342I`XMWh9fVHY}zTM$V?edpz7(IM5$~_M{@^3;qRzKQ|!& literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/__pycache__/report_helper.cpython-310.pyc b/l10n_ru_doc/__pycache__/report_helper.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..371ad1eba8ee01dd57d5c644c6073992d20a0816 GIT binary patch literal 3752 zcmai1&2JmW72ny}U9Kofm1X%uiIFgFSecD2I=kBqFGytz8r?&_ixTfFM$Dy18u(v@V+d3-ooaJ^7qlP$2!i*`-3tPP^31ym|BH z%em`#*|EA95XQ6W)CB2DC7=ndH&uAKqXftF@hL(qBk2iVG zYFe6ag?7(rI?VWyA#CB?HH71r?(n87%-cr2^av{%b*5a=%KR+o`5Sdpm7;#nm#t8l zBBQZnw;lJAR@Nrr$&aIR9VP9c@(nsb(-cn$F08w($@2}HmM97LuF1jXy?Q-j{LML|K#WX<}E)=e5rU6 zZApgR+cv84=YViget?qRKsDsDB-oIjHuiXA3UiMSEx902gJWrqC9EO(Lo+inwr>vE z0lULGG;R-V>}zifD(?j%+kR!GmL~77C{`WJZTrF2c2;l(FRTZ>t!gc$zf`tgS%Fbo zYeBEIW;EfKkO)ug_M=;Ccd)u zrpn2;Qf?MYKkLir(2yrE_w$z<+i}ltWPX}8ViCueg#WH48ZFTXU%VW7vhRtw-H?6~ z%go!>hFeW`Wd+k`P|~MRS**+~Gp|jS|0>M+k7W<$zqI!%&eb*{KK=*+1WRq{Du^MI z^O>>FU~P6_?wLbV&JSVnW#cx$2|HRF1M4mE!t>f|$^hI<>8nyFh(s$4>s-!a6=g-O zp0CO|5VIhTw6b}%NCLJVS_YX?&{(X(EasvN7AB6Xg{BTnhbMT@fj_&53I|>q;_h&rL)&U_(h)}bxQVrmwC0RlP{b&`&yTyzuNCAS=! z+7$8}=;PX#$fsDlim}g-DvSzSAg6s{GUp4+94t=Qpb-5^D@ZaTG?N5_K7pbpjN~Q(8Tu(wM3gC8#{EdBx%PG(r@ohj zeWYzjYP;~X-&3=cSC9hq9H$*8etV~2=AGkayMU86P*O^u^K1#gnrDL(Q@*3crc6gB zE}>}8t%E>Rog1=!;{c{w#_eEGsFysL{W9*v;;}iibQc9O} z0u8e^b;lp=MXtJyl2UMN8AIdk@*a>vcOtDx`+Z=(LpL1POFg0m6kFBGQp#DqtavAg zk14Op>tT>)blY9~4lPf6oihe26WRw+kOfEqtLtIhMtcp!c#gabd1Q7wO~N2kRyPhJ zbTSzv1z6>`AaQ(GAUa?3+q5TTCyQOBR5lqgW0@(tQ$SGBcK-#4Edwc+bqzT?G%0qv z#sOonc-NGt3Xa+31<#Vt7Ch^SXUhu(&n~1K`C`Fw3QkF`6`T@r1lxCqCPnF?x$(Jq zv09%|d=MncX(fpdc$V8hX(o5QK*-ZLBqcf|FLagF4zgY4z(l^EsZ!ovkuO2&u(%3J zNlRuC?s^M1*zqV=rIrxVPt!Hb&}gujgS)^1X!AmJUXTMO^I|daF?$lWv_0Pf@jvW& znruMVTo-67EW_nuql@t=sBoq1P`~ab2RcMdL{X$9FRy>Yh>wvtgcmc^5|0@dicx6!(To8Z8cBZf2ofCJi0gf zCzAF3!f_wKjUQI~6uqMdkS%;TD{q0L>|{FzhP5ka0BHD!;O}m>q8$*aD!1BgFTcpt zjOOYW5Rvchc$-1HkR@tPkGEqfJPCpF2X=nco(kb22 z6eWvzLoFipP|Ua}WepXA%eV}lnSjj`mYc#3$FfK9M9J|h;wg_2ps9!vwvUUHGK%~z zCP6t$8`^sR2mVXbx_N02kIF747q3LpYrzEgpPkU+Npm)Eb5L;RHxXSQ^?Bub9(l#{ zRN3=-vFL|HS3K{Xek;sJ^s8E)rJ3icdY-BpRTrpwnJOK@1Pl37s^}t{aFh;c3Ry{5 zqBEqloNJU#cfl>W4t^ZPMsK!qN=wye^b1lhK~Oo#ZWe^8elFxs%`*LCu$sj&xa1Dy f#G75bNcG$&ZLQq(T)k_gxwc)!aDjmeTjKu(vchOS literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/demo/l10n_ru_doc_demo.xml b/l10n_ru_doc/demo/l10n_ru_doc_demo.xml new file mode 100644 index 0000000..16d7d63 --- /dev/null +++ b/l10n_ru_doc/demo/l10n_ru_doc_demo.xml @@ -0,0 +1,63 @@ + + + + + + ОАО "СБЕРБАНК РОССИИ" + г.Москва + 044525225 + 30101810400000000225 + + + + 40707810600025341231 + + + + + + + iVBORw0KGgoAAAANSUhEUgAAALQAAABACAYAAACzzl09AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2lpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoxMGE3N2JhNy01MThlLTMwNGEtODcxOC0wMmQ5MWYzYTdiNTUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MjQ2QTI3QjdCQ0JCMTFFMzgwRTQ4NjcwRjlEM0QyMTAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MjQ2QTI3QjZCQ0JCMTFFMzgwRTQ4NjcwRjlEM0QyMTAiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkYzOTcwMjU2QkNCOTExRTM5OEZFRDU5OUQxQUU3MUUzIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkYzOTcwMjU3QkNCOTExRTM5OEZFRDU5OUQxQUU3MUUzIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+LLXcsQAAAjFJREFUeNrs3TFKM0EUB3BXv+QAgqViYWflBQLbWNhZKwE7QQSPkCMIItgJQW+gtjmCBxLZr34zsMPDiCK/X6c7swPxz/B4zJhuGIYN+Cs2fQQINAg0fL9/5S+6o6NUUT28v3dh/s1NnP/5OT7/7i7Ov7qK83d24vjFoht7X/f4GOfv78f5fd/5s9uhQaBBoGGdNXSzRs7W2GWNfH09On+4v4/jF4vcehcXcf5qpdFuhwaBBoEGgQaBRqBBoOHnNPvQ2b7zxtZWnF+e7SieV+uVZzkOD0efV33r8ixH38f5RV/a2Q47NAg0CDQkde4UYocGgQaBhpT6TuF8Hovq7e3w43B7O36nr+9z55dXq9hHXi7j/N3dOL7RN+6Oj8fXn07j+15e9KHt0CDQINDwpRp6WC5TdwDTNXKjxh7m8zB+mr0TOJnE972+xvVPTzXe7dAg0CDQsNYa+rf58DfCDo1Ag0DDL6+hu7Oz2Kc9OIjPi7MeZd+6/H/Q3WyW6vtWZzlms/j86Smuf34e1/+IVXd1tqM4y4EdGgQaBBqS3CnEDg0CDQINOXUf+u0tdyfw5CSeN354iPP39kbHV+snz19X3+FS9tHLO5HFeOzQINAg0PDVGrpZIzdq7OHyMjU+XSO3vufw+XmtdyKxQ4NAg0BDq4aeNCZMfGbYoUGgQaBRQ4+aJvvI1VmO8k5g8bzsW1fvS/aRm3cii/c522GHBoEGgYYkdwqxQ4NAg0BDzn8BBgBlrqW6k1gn5wAAAABJRU5ErkJggg== + codup-test@mail.ru + www.codup.com + 0000000000 + 000000000 + 00000000 + + + + ООО "CodUP" + ул.Земляничная + дом № 13 + 123456 + г.Москва + CodUP + + + 1 + 1 + iVBORw0KGgoAAAANSUhEUgAAAOYAAADmCAMAAAD2tAmJAAAC2VBMVEUWAGH///8WAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGEWAGF7Mdv3AAAA83RSTlMAAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0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 + + + + Иванов Иван Петрович + codup-test@mail.ru + + + + Иванов Иван Петрович + iVBORw0KGgoAAAANSUhEUgAAAZQAAAETCAMAAAAmrgDyAAAC61BMVEUOF9r///8OF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9oOF9r/ATCgAAAA+HRSTlMAAAECAwQFBgcICQoLDA0ODxAREhQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJj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 + + + + Сидоров Семен Иванович + codup-test@mail.ru + + + + Сидоров Семен Иванович + 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 + + + + diff --git a/l10n_ru_doc/i18n/ru.po b/l10n_ru_doc/i18n/ru.po new file mode 100644 index 0000000..59d03de --- /dev/null +++ b/l10n_ru_doc/i18n/ru.po @@ -0,0 +1,116 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_ru_doc +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-08-19 09:27+0000\n" +"PO-Revision-Date: 2020-08-19 09:27+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: l10n_ru_doc +#: model:ir.actions.report,name:l10n_ru_doc.report_account_invoice_act +msgid "Act" +msgstr "Акт об оказании услуг" + +#. module: l10n_ru_doc +#: model:ir.actions.report,name:l10n_ru_doc.report_account_invoice_bill +msgid "Bill" +msgstr "Товарная накладная (ТОРГ-12)" + +#. module: l10n_ru_doc +#: model:ir.model.fields,help:l10n_ru_doc.field_res_company__print_facsimile +#: model:ir.model.fields,help:l10n_ru_doc.field_res_users__print_facsimile +msgid "Check this for adding Facsimiles of responsible persons to documents." +msgstr "Отметьте, для вставки подписей ответственных лиц в документы." + +#. module: l10n_ru_doc +#: model:ir.model.fields,help:l10n_ru_doc.field_res_company__print_stamp +msgid "Check this for adding Stamp of company to documents." +msgstr "Отметьте, для вставки печати организации в документы." + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_company__chief_id +msgid "Chief" +msgstr "Руководитель организации" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_account_setup_bank_manual_config__bank_corr_acc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_bank__corr_acc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_partner_bank__bank_corr_acc +msgid "Corresponding account" +msgstr "Корр. счет" + +#. module: l10n_ru_doc +#: model_terms:ir.ui.view,arch_db:l10n_ru_doc.view_company_ru_form +msgid "Documents" +msgstr "Документы" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_users__facsimile +msgid "Facsimile" +msgstr "Подпись" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_company__inn +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_partner__inn +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_users__inn +msgid "INN" +msgstr "ИНН" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_company__kpp +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_partner__kpp +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_users__kpp +msgid "KPP" +msgstr "КПП" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_company__okpo +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_partner__okpo +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_users__okpo +msgid "OKPO" +msgstr "ОКПО" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_company__print_anywhere +msgid "Print Anywhere" +msgstr "Документы" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_company__print_facsimile +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_users__print_facsimile +msgid "Print Facsimile" +msgstr "Выводить подписи" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_company__print_stamp +msgid "Print Stamp" +msgstr "Выводить печать" + +#. module: l10n_ru_doc +#: model_terms:ir.ui.view,arch_db:l10n_ru_doc.view_company_ru_form +msgid "Responsible Persons" +msgstr "Ответственные лица" + +#. module: l10n_ru_doc +#: model:ir.model.fields,field_description:l10n_ru_doc.field_res_company__stamp +msgid "Stamp" +msgstr "Печать" + +#. module: l10n_ru_doc +#: model:ir.model.fields,help:l10n_ru_doc.field_res_company__print_anywhere +msgid "Uncheck this, if you want add Facsimile and Stamp only in email." +msgstr "Снимите отметку, если хотите добавлять подписи и печать только в email." + +#. module: l10n_ru_doc +#: model:ir.actions.report,name:l10n_ru_doc.report_account_invoice_upd +msgid "Upd" +msgstr "Универсальный платежный документ (УПД)" diff --git a/l10n_ru_doc/models/__init__.py b/l10n_ru_doc/models/__init__.py new file mode 100644 index 0000000..d378530 --- /dev/null +++ b/l10n_ru_doc/models/__init__.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +from . import res_partner +from . import res_company +from . import res_users +from . import res_bank +from . import account_invoice +from . import account_move_line +from . import sale +from . import uom +from . import tax +from . import product diff --git a/l10n_ru_doc/models/__pycache__/__init__.cpython-310.pyc b/l10n_ru_doc/models/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d51288d82ed1d05c9883cd4053eb49107f2c530 GIT binary patch literal 471 zcmY+AOG*SW5QdX}zXlbI$r6%kM1#$7fcb|N-*Cry%W9MA)K7f&!-S9%0jRs{w$ zAzyue1-e7o&88u+KEB@`OG?NmhQBL;a0|!30u)hnBopP7q9@=9Pok&bDNmzk;2F=N z=ioWdqZi->FQS*=C5KIy#LpFbvXf>(`@pQS_DtzD3X_VB qmlsC3MJU^|$tpd1Cg90K5aN8^?W=2OE~CD|Vfa%(mvr?1KBm8l8*W7a literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/models/__pycache__/account_invoice.cpython-310.pyc b/l10n_ru_doc/models/__pycache__/account_invoice.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9900076d9fec4f4bb4d321cce9f3b2b85cd313b9 GIT binary patch literal 5013 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 literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/models/__pycache__/product.cpython-310.pyc b/l10n_ru_doc/models/__pycache__/product.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2e4d98f7de4e52d46e53bec8d3808afc7ce13f76 GIT binary patch literal 461 zcmYjNJ5R$f5VjpBgwpa@7?_xlGJs)3LZ}i06BQCnS*)n%s)Zy5C#h6cm>Cc(NJzlO zz{bpP@a&a|zrci@RM3;|@!g%jyR+y<`p%!$l78}+80-T}@$2cP~ z!RQbH0q+KZC&-z1?Zp)635xu0+lwM%g270nP?#W-Akw1m(zD`O(6w5uStC%40mTGx z>Wa9}Bozx@geW)K@F^y?)f6`eR+c>L-1t-}QYjnlmBi zd6EgvO^b88MU}d^&G}`Oq|-{sNBK~wQK^WfG4x=VC^LU9ftPOD8&V54Uz?v@Hk6rQ zr6@`!LCQ@K<2qmouykiT=c?i$`>eT`{Vh6C?kC;BMPN;cC|<;Mt{3@+I<9)WaxKO` aavxTg|A#kG+ttIp=9Ycz2p#h>S|z`dfOU%i literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/models/__pycache__/res_bank.cpython-310.pyc b/l10n_ru_doc/models/__pycache__/res_bank.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d73d6d5733baa2accf4406d1fa3063ed831ce15c GIT binary patch literal 980 zcmZ`&TWb?R6rP!#-JQfFP2&YYP+tR@t*=s~7{Mot=-Yw}+nq_XaWCm?A~aMG+E@RB zKK3uot55j}76i|kZDSQXFdyGJJLfXroUOXuHi5PNay^~J&1gI(_eD57Xi z3L4Xb#jNmRkCN9!G3A{R%de%$knGGhH&Q)!L zqEb4qQ~Y*)ZR$P*uO=~7BxZ`np5`+jD=Pk##ewo6b71+)r2M!NM%SYQU>A4Cl>uX3 zl`1O_A17&AEz8Av4|1JT%j;~V_lKbsQkF@frL=7+p^;^dyd&k&GRZH$2$_{rZL)>& zAlmZrG%;4BkY7UDb7K17c5v}LnpTC57P?+Um8zr3T+bN}4N>!y%bLR*; zl-TZQer$Zmf(7aTKoCv`%=vB>W(N-5EQ}7n3FUvMDp27WIi+z+36QE~d+&7pHZhA* z8z)*HMVmJcC!WC$Oo$)=Y=|w&OrH%m5{G%mc<9 z^MM6NOcCgUg81e(L|Kk1+mOHKdrYt%b$*;dj+5fDH5G91t^Wr93O4}m;QumPvD=L73w#(i LH+RT@-3xvLOkm%p literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/models/__pycache__/res_company.cpython-310.pyc b/l10n_ru_doc/models/__pycache__/res_company.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aaaff1882e174ac5b2ee460aeaf614990d7d32ef GIT binary patch literal 1075 zcmZuw&2H2%5YGQ*ce}f7`MH67Ku9aWE+CG8+OB9%t&j?rTq2Wk*tCfqoP=t_5e{7X z4)n;0XW%t_<-{v+0LDpZ7YRoh&F8Vd8P8{n(P&`c`1XDkf3*$cy9VpSL9l~=aTg63 zV5UZ924-djmT4RqV1fP70GnAS_6Iv~z&SRi?hjmROfBWb2}_|+UM7I0MWmE*mIh7@6GE88W zaK4WR>`9i=l7aFiqab*?s@GSY=6O9?+a*qOQTH`xRWMm7cd<-ZTyGyRq@^j@jUrL; zlJc^iypRbm$v%yWBui3OKVK|abV|x)Qjl0kLID!~=4wGfL`;x67raPbr;Oy70ew;m z0wSt1#>--+MJY<8exsZvOY?fz<~c5Dme-H}pQ8zC`mPiIQYyFIJZ_nG`RZ)RB&&B` z@#wPTdnAd;N>tuisA1RnS-z6`MdC{}iaTh0!!gI! z*c_W1_<5#fdcQqO+kvH#We$EdJC3F?U0&4xrh2$HsP!CTJN@w`%l{5J~MSX Kop;l?Y5f7p9zl`- literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/models/__pycache__/res_partner.cpython-310.pyc b/l10n_ru_doc/models/__pycache__/res_partner.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed7504ea182f9612bc05bdcec394bdde5101b1df GIT binary patch literal 767 zcmYjPJ#Q2-5ViN?vbVY092At$AzeWhdO!#Ygd#2{(k+E$-8i`o`-OKm(xu7=h$blz zv_L57B0(esQfMi?ty`-61uDjS0bP<%{Q^ z`4p>yL=;G50gY_oY`Vr8oI@+>w8(`HEFfBFkq6xtdBQnz!T(63F4lcmgx-b){X-fp zBGZEanSPrsVHUsu+qx4R@P^x;HPK zG_TZgv)3GqhD+LGEaRzQO#6)C#OuW5J;t8bJUM4P7H3l-<4RiSpq&R(F0~zJnYN!5 zg?931MUHVpX1crfw+Zc3vqI?3{W#-trn~EWQpRbV2+B2yy)EeEiGBOq!K2t(9gt9&u=31vH>O9pDXU r%a4XG_K4o?C!~!^?LIau*3$o*nP=Aw@7xzPZGj7B&dq@XKooOC3CA>ma2z3~4s@P;@!vvphv?wdK%yJ_NAtAxGuR&%N@I^AP zF=J&`0AqH@nCq#Qo{t#2tuy(PiJ2%@phcyLYs&WLN=e8{JNYMVdvj4{y0L@b-`d*mCE^nu9$ literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/models/__pycache__/sale.cpython-310.pyc b/l10n_ru_doc/models/__pycache__/sale.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..94725f82c54ced185eced3bf4bf3388c57208516 GIT binary patch literal 773 zcmZ`%J#Q015S_gb=Que6QXr?LGYB6vRFM^lA{C}^cg^a!S(6LvTeG`PgymG^hu9^5 zXBMke6UKYvobkOOch4wnVMhotx`Vyg2_!^~*b~+*Tt%3k!Y_zyg+r` zB}IjWe)Y1Ib}iA=MK4Ivky(8X*_p1E@3EQ=cqcEJ+ci|plrC@cHkiv@=b|Qy`V&NfZm1c?AJub4zY97a(t>T{$QNhMm z6m0Z2Y`v|Of5AeWO$2XXW@qM`{pKON-4+7*xt@(~;Qchgyx0&7K=V~F3^6QFf&-k8 zfMB$T7-7~GViqT-)}nK`A|IB$S)k&PEf nl^c4Fwhd3!KQkrTIWQNi;Qz+8*D<)eRWGxR4WVIPL`&os{h)U? literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/models/__pycache__/uom.cpython-310.pyc b/l10n_ru_doc/models/__pycache__/uom.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3399650bd7d8f335d48645b1f0ba063b8dbf64ac GIT binary patch literal 464 zcmYjNu};G<5VakrjY^A{7??UCGC*KpLkNihG0+9EWU->2s}_6Hv}BXPMvEfJXm|0W1%kqtrNO3SLOM zfJ_m7wu7!pWH6A~AW)#xI>^fc1Q7)B)@EO%xd7D;%8v(j;`3o@muY3Q3I>mGx=0JI m<-3MkouX-K*J9iwyR)MF-?&6|TlaR#AM8>qXqA`9GW`X)r+x|m literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/models/account_invoice.py b/l10n_ru_doc/models/account_invoice.py new file mode 100644 index 0000000..bf5c88a --- /dev/null +++ b/l10n_ru_doc/models/account_invoice.py @@ -0,0 +1,144 @@ +from datetime import datetime +from odoo import api, fields, models + +class AccountInvoice(models.Model): + _inherit = 'account.move' + kladov=fields.Many2one('res.users', string='Ответственный за передачу товаров/услуг') + gruzopol=fields.Many2one('res.partner', string='Грузополучатель') + gruzootpr=fields.Many2one('res.partner', string='Грузоотправитель') + transport=fields.Char('Данные о транспортировке и грузе') + osnovanie=fields.Char('Основание') + payment_text=fields.Char('Текст для платежек в УПД', compute='_compute_get_txtpayment') + payment_num=fields.Char('Номер платежки в УПД', compute='_compute_get_txtpayment') + payment_date = fields.Char('Дата платежки в УПД', compute='_compute_get_txtpayment') + only_service = fields.Boolean('Только услуги', compute='_compute_get_check_service') + + @api.depends('invoice_line_ids') + def _compute_get_check_service(self): + for s in self: + s.only_service = all((line.product_id.type=='service') for line in s.invoice_line_ids) + + def _compute_get_txtpayment(self): + for s in self: + payments = s._get_reconciled_payments() + payment_text = '' + + for payment in payments: + if payment.date: + payment_text += payment.name + ' от ' + \ + fields.Datetime.from_string(payment.date).strftime("%d.%m.%Y") + if payments[-1]!=payment: + payment_text += ', ' + if payments: + s.payment_num = payments[0].name + s.payment_date = fields.Datetime.from_string(payments[0].date).strftime("%d.%m.%Y") + else: + s.payment_num = '' + s.payment_text = '' + s.payment_date = '' + + s.payment_text = payment_text + + def action_bill_sent(self): + assert len(self) == 1, 'This option should only be used for a single id at a time.' + template = self.env.ref('account.email_template_edi_invoice', False) + compose_form = self.env.ref('mail.email_compose_message_wizard_form', False) + ctx = { + 'default_model': 'account.move', + 'default_res_id': self.id, + 'default_use_template': bool(template), + 'default_template_id': template.id, + 'default_composition_mode': 'comment', + 'mark_invoice_as_sent': True, + } + return { + 'name': 'Compose Email', + 'type': 'ir.actions.act_window', + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'mail.compose.message', + 'views': [(compose_form.id, 'form')], + 'view_id': compose_form.id, + 'target': 'new', + 'context': ctx, + } + + def bill_print(self): + assert len(self) == 1, 'This option should only be used for a single id at a time.' + return self.env['report'].get_action(self, 'l10n_ru_doc.report_upd') + + def get_delivery_doc_name(self): + for s in self: + pickings = [] + pickings_list = '0' + orders = self.env['sale.order'].sudo().search([('name','=',s.invoice_origin)]) + for o in orders: + if o.picking_ids: + for p in o.picking_ids: + pickings.append(p.name) + if len(pickings)>0: + pickings_list = ';'.join(pickings) + if pickings_list != '0': + return pickings_list + if s.name.find('/') > -1: + return 'УПД № ' + s.name[len(s.name) - 4:] + return 'УПД № ' + s.name + + def get_delivery_doc_date(self): + for s in self: + pickings = [] + pickings_list = '0' + orders = self.env['sale.order'].sudo().search([('name','=',s.invoice_origin)]) + for o in orders: + if o.picking_ids: + for p in o.picking_ids: + pickings.append(datetime.strftime(p.date, '%d.%m.%Y')) + if len(pickings)>0: + pickings_list = ';'.join(pickings) + if pickings_list != '0': + return pickings_list + return datetime.strftime(s.date, '%d.%m.%Y') + + def get_function_partner(self, partner=False, type='director'): + if partner: + if partner.parent_id: + partner = partner.parent_id + director = self.env['res.partner'].search([('parent_id', '=', partner.id), + ('type', '=', type)], limit=1) + if director: + if director.function: + return director.function + return '' + + def get_name_partner(self, partner=False, type='director'): + if partner: + if partner.parent_id: + partner = partner.parent_id + director = self.env['res.partner'].search([('parent_id', '=', partner.id), + ('type', '=', type)], limit=1) + if director: + if director.name: + return director.name + return '' + + def get_facsimile_partner(self, partner=False, type='director'): + if partner: + if partner.parent_id: + partner = partner.parent_id + director = self.env['res.partner'].search([('parent_id', '=', partner.id), + ('type', '=', type)], + limit=1) + if director: + if director.facsimile: + return director.facsimile + return '' + + def get_stamp_partner(self, partner=False): + if partner: + if partner.parent_id: + partner = partner.parent_id + if partner.stamp: + return partner.stamp + return False + + diff --git a/l10n_ru_doc/models/account_move_line.py b/l10n_ru_doc/models/account_move_line.py new file mode 100644 index 0000000..06e0f5e --- /dev/null +++ b/l10n_ru_doc/models/account_move_line.py @@ -0,0 +1,29 @@ +from datetime import datetime +from odoo import api, fields, models + +class AccountMoveLine(models.Model): + _inherit = 'account.move.line' + + price_total_pf = fields.Monetary( + string='TotalPF', + compute='_compute_totals', + currency_field='currency_id', + ) + + @api.depends('quantity', 'discount', 'price_unit', 'tax_ids', 'currency_id') + def _compute_totals(self): + super(AccountMoveLine,self)._compute_totals() + for line in self: + line_discount_price_unit = line.price_unit * (1 - (line.discount / 100.0)) + if line.tax_ids.filtered(lambda tax: tax.invisiblePF == False): + taxes_res = line.tax_ids.filtered(lambda tax: tax.invisiblePF == False).compute_all( + line_discount_price_unit, + quantity=line.quantity, + currency=line.currency_id, + product=line.product_id, + partner=line.partner_id, + is_refund=line.is_refund, + ) + line.price_total_pf = taxes_res['total_included'] + else: + line.price_total_pf = line.price_total \ No newline at end of file diff --git a/l10n_ru_doc/models/product.py b/l10n_ru_doc/models/product.py new file mode 100644 index 0000000..c230841 --- /dev/null +++ b/l10n_ru_doc/models/product.py @@ -0,0 +1,5 @@ +from odoo import fields, models + +class ProductTnved(models.Model): + _inherit = 'product.product' + kod_tnved = fields.Char('Код ТНВЭД') diff --git a/l10n_ru_doc/models/res_bank.py b/l10n_ru_doc/models/res_bank.py new file mode 100644 index 0000000..f22d430 --- /dev/null +++ b/l10n_ru_doc/models/res_bank.py @@ -0,0 +1,19 @@ +from odoo import api, fields, models + +class Bank(models.Model): + _inherit = 'res.bank' + + corr_acc = fields.Char('Corresponding account', size=64) + + +class ResPartnerBank(models.Model): + _inherit = 'res.partner.bank' + + bank_corr_acc = fields.Char('Corresponding account', size=64) + + @api.onchange('bank_id') + def onchange_bank_id(self): + for s in self: + s.bank_name = s.bank_id.name + s.bank_bic = s.bank_id.bic + s.bank_corr_acc = s.bank_id.corr_acc diff --git a/l10n_ru_doc/models/res_company.py b/l10n_ru_doc/models/res_company.py new file mode 100644 index 0000000..9ca4ae7 --- /dev/null +++ b/l10n_ru_doc/models/res_company.py @@ -0,0 +1,18 @@ +from odoo import fields, models + +class Company(models.Model): + _inherit = 'res.company' + + inn = fields.Char(related='partner_id.inn', readonly=False) + kpp = fields.Char(related='partner_id.kpp', readonly=False) + okpo = fields.Char(related='partner_id.okpo', readonly=False) + chief_id = fields.Many2one('res.users', 'Chief') + accountant_id = fields.Many2one('res.users', 'General Accountant') + print_facsimile = fields.Boolean(string='Print Facsimile', + help="Check this for adding Facsimiles of responsible persons to documents.") + print_stamp = fields.Boolean(string='Print Stamp', + help="Check this for adding Stamp of company to documents.") + stamp = fields.Binary("Stamp") + print_anywhere = fields.Boolean(string='Print Anywhere', + help="Uncheck this, if you want add Facsimile and Stamp only in email.", + default=True) diff --git a/l10n_ru_doc/models/res_partner.py b/l10n_ru_doc/models/res_partner.py new file mode 100644 index 0000000..e918a39 --- /dev/null +++ b/l10n_ru_doc/models/res_partner.py @@ -0,0 +1,11 @@ +from odoo import fields, models +class ResPartner(models.Model): + _inherit = 'res.partner' + + inn = fields.Char('INN', related='vat') + kpp = fields.Char('KPP', size=9) + okpo = fields.Char('OKPO', size=14) + ogrn = fields.Char('ОГРН') + type = fields.Selection(selection_add=[('director', 'Директор'), ('accountant', 'Бухгалтер')]) + facsimile = fields.Binary("Подпись") + stamp = fields.Binary("Печать") diff --git a/l10n_ru_doc/models/res_users.py b/l10n_ru_doc/models/res_users.py new file mode 100644 index 0000000..aaf70cb --- /dev/null +++ b/l10n_ru_doc/models/res_users.py @@ -0,0 +1,7 @@ +from odoo import fields, models + +class Users(models.Model): + _inherit = 'res.users' + + print_facsimile = fields.Boolean(related='company_id.print_facsimile') + facsimile = fields.Binary() diff --git a/l10n_ru_doc/models/sale.py b/l10n_ru_doc/models/sale.py new file mode 100644 index 0000000..54707e2 --- /dev/null +++ b/l10n_ru_doc/models/sale.py @@ -0,0 +1,8 @@ +from odoo import models + +class SaleOrder(models.Model): + _inherit = 'sale.order' + def print_quotation(self): + self.filtered(lambda s: s.state == 'draft').write({'state': 'sent'}) + return self.env['report'].get_action(self, 'l10n_ru_doc.report_order') + diff --git a/l10n_ru_doc/models/tax.py b/l10n_ru_doc/models/tax.py new file mode 100644 index 0000000..081adb1 --- /dev/null +++ b/l10n_ru_doc/models/tax.py @@ -0,0 +1,6 @@ +from odoo import fields, models + +class TaxInherit(models.Model): + _inherit = 'account.tax' + + invisiblePF = fields.Boolean('Не видно в ПФ') diff --git a/l10n_ru_doc/models/uom.py b/l10n_ru_doc/models/uom.py new file mode 100644 index 0000000..1de1e3b --- /dev/null +++ b/l10n_ru_doc/models/uom.py @@ -0,0 +1,4 @@ +from odoo import fields, models +class UomInherit(models.Model): + _inherit = 'uom.uom' + kod = fields.Char('Код единицы измерения') diff --git a/l10n_ru_doc/report/__init__.py b/l10n_ru_doc/report/__init__.py new file mode 100644 index 0000000..b058f02 --- /dev/null +++ b/l10n_ru_doc/report/__init__.py @@ -0,0 +1,5 @@ +from . import report_order +from . import report_invoice +from . import report_bill +from . import report_act +from . import report_upd diff --git a/l10n_ru_doc/report/__pycache__/__init__.cpython-310.pyc b/l10n_ru_doc/report/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af59652add5da1dea3b73abfc29e1364574d9fd4 GIT binary patch literal 325 zcmYk2y-ve05XbF&wJHhXH8K>pYgHkhfQ8MARdTMdhF8kU#49jy7c%rL z|NZ;j;4iGIji9PNuIEo$zgcc8A$g`baDV{mMJu(G%n5O#lbKWERHrj%#F@@!&WUrK z6Bny!t3}6HK{o<~>pld93?v~D*^PY6G=&6Y}HumsR7n2Bl&5&|r z963ip@g>5VndA4M-m$eR+94_g#4Xs%4C(~R?{}REqXBHx|5?fy*SToSV}G62#};Aq Q_K6=b@Sl~Ulsq2fA2at(Hvj+t literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/report/__pycache__/report_act.cpython-310.pyc b/l10n_ru_doc/report/__pycache__/report_act.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8bc325c14ee776823e19c5a28081a8232c440c0 GIT binary patch literal 758 zcmZuvy^ho{5cXff-jaob0tqB2kSJ1+aQzA0i2@o{;wX^PSlNt^W0k~>1Da8(Yt2Q-bp8mHg5vtA500CN) zh8C0t%xc!~f>ZLG00(hJKq$Htm%NA|dQH;!C!QfG^>L#?)fUn8)f=^Vq3V?~Rd9}l zrUA{%xV)f`&2MN z8IJh(=E10k*}sQUI!_}%k+LltC8eLrz^|(VPNaO_mG#aO^&#dK7U&6#%zoGlJ&#ds zFcTu^4c70?@gYSZXc#*DqX4rKK)3dPZ#lGl=;Z8pVVyz7FT=m;vyG~TE}BrwaFW1HD*N>HvoU7UQUg!~ALu?SooqPh$X5TKgW zw4gL#rdiDkPRUCG9K;m?q3BXv@*;xhElJ~_c!s3Z$F%{a9ir)*cWUuU>6NloaE^uJ z;tSgnk0H+OA6XZrD@M%qq-sj^{9E--3d zg~Wd)@QF}gpt}2Lwq%K{Zj&!`OTW^Oyk(bU%aX6@sJH6NU^;SQc-Bszps`ozZ=7ETH%+tNpPE|bt#WN{z?g@i);-8e$VV*mf#q)M$!4nye^b6!t=x5BUFuG`JxuEoH2YLA zK^czt_vYTXjoH7aQaVo~KasL2YbB+h%D}MG0Vh(PcctEWqCUhPV1=H-$n1x`(Dk4$ zMl&ITUT6K@93N8zik6|nKL{`@0Zilm_nbr1hhEN(7Ou5r)xHjYtIsy78v1BMX+L=~ Q-1!;)?xB7{5_*gM0lsX-B>(^b literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/report/__pycache__/report_invoice.cpython-310.pyc b/l10n_ru_doc/report/__pycache__/report_invoice.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7818d1abcda6d713add4a7268a301e52cb0eaafb GIT binary patch literal 774 zcmZuvv5wR*5cR}PZdvVecN9p_aT3KAB+w(Yhyo~BiK9SDV`VcwZdXaX*h$c>mWJaS zs3@T1kC0m`egRQ1PWGe-7;DDQp7D&|*m^o0Gm=jqF3!FKV?X?2D1sJqQX7*&hET8) zQUH&GA}D#vfjwo&QG8@56s*N1PeTk}v03z!&afG{sMM$mOKAM^wOT$?#YUOjJBPw) zF(#42#HVKD1fUC>v2`J0Wuf zA`lSJh<FDG;~^vY{_*_u2Qco;opLg|&Vv*7Ft zr^O+uyGur~3XoL^Ld7wS>7f#sgtUJDxIL-0dSy}BW3@82+1#^nF7%VfOKDq)W>$1t z(uAnLQAR zfP_Z&XY=4nFN>>3bC~3*A4s{Z7fMP$l!0ff10G5FzOD7nlg1FcPh}#Jp4kg~q4PoG zZ3axh4TyUadR7sL+JwCRVSq)AXqN7OZ`!rK>*)B|)HSxAH7~<2i`jZrLpNHV%6uFWV<%(D@2c$bedZqNU0Tkh;%b zs?k%GO_fQ}*(4~)C12eFL6MkB5_^)y41!}q8guDESl@0PS1+dWSWUGl=eLbJ!|eXO zT$oBoorbkZR8u)jG3+nG{#w9~fme3`7Gw-v?vYP)K|j-Xtn@C(f{mG^3nsmf{Ddso za2_OSs;j&VCwis^-1=v(1KWmN;(v!7{iB4qmA2 z)cSA@zvMD06SD>WB{A3F_4}O;Rg{sIS|3O?b3&BJsL^CpH@QBr*Km4ncf>1I zigo|9B&$@>hN!CmV4HG}QxAUrk9of_!|?BqmUOsm*^Ur-GEqX|>_P(9Km)F$4d;!#@&P)8)63M^Qc(XO9MTc6!7ag-gGPngR2pXzlx?C0Q3E3;tjJgH}UEo!tXdva>4e&aRr@y1k{Fuw&l1>b%(WZ0pxmKbqd7QBj&CEuZ0E$PLbg+?3gN4(lB~q>!fQ00cCkJKk>hC;2P* A0RR91 literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/report/l10n_ru_doc_report.xml b/l10n_ru_doc/report/l10n_ru_doc_report.xml new file mode 100644 index 0000000..328441b --- /dev/null +++ b/l10n_ru_doc/report/l10n_ru_doc_report.xml @@ -0,0 +1,107 @@ + + + + + A4 + + A4 + 0 + 0 + Portrait + 7 + 7 + 7 + 7 + + 35 + 75 + + + A4 Landscape + + A4 + 0 + 0 + Landscape + 7 + 7 + 7 + 7 + + 75 + 60 + + + + Счет по форме 1С + sale.order + qweb-pdf + l10n_ru_doc.report_order + l10n_ru_doc.report_order + 'Счет - %s ' % (object.name+' '+(object.partner_id.parent_id.name if object.partner_id.parent_id else object.partner_id.name)) + + + report + + + + Счет-фактура + account.move + qweb-pdf + l10n_ru_doc.report_invoice + l10n_ru_doc.report_invoice + 'Счет-фактура - %s ' % (object.name+' '+(object.partner_id.parent_id.name if object.partner_id.parent_id else object.partner_id.name)) + + + report + + + + Товарная накладная (ТОРГ-12) + account.move + qweb-pdf + l10n_ru_doc.report_bill + l10n_ru_doc.report_bill + 'Товарная накладная - %s ' % (object.name+' '+(object.partner_id.parent_id.name if object.partner_id.parent_id else object.partner_id.name)) + + + report + + + + Акт выполненных работ + account.move + qweb-pdf + l10n_ru_doc.report_act + l10n_ru_doc.report_act + 'Акт - %s ' % (object.name+' '+(object.partner_id.parent_id.name if object.partner_id.parent_id else object.partner_id.name)) + + + report + + + + Универсальный передаточный документ(УПД) + account.move + qweb-pdf + l10n_ru_doc.report_upd + l10n_ru_doc.report_upd + 'УПД' + + + report + + + + УПД без печатей + account.move + qweb-pdf + l10n_ru_doc.report_updn + l10n_ru_doc.report_updn + 'УПД без печатей' + + + report + + + diff --git a/l10n_ru_doc/report/report_act.py b/l10n_ru_doc/report/report_act.py new file mode 100644 index 0000000..133336e --- /dev/null +++ b/l10n_ru_doc/report/report_act.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from odoo import models +from odoo.addons.l10n_ru_doc.report_helper import QWebHelper + +class RuActReport(models.AbstractModel): + _name = 'report.l10n_ru_doc.report_act' + + def _get_report_values(self, docids, data=None): + docs = self.env['account.move'].browse(docids) + return { + 'helper': QWebHelper(), + 'doc_ids': docs.ids, + 'doc_model': 'account.move', + 'docs': docs + } diff --git a/l10n_ru_doc/report/report_act.xml b/l10n_ru_doc/report/report_act.xml new file mode 100644 index 0000000..4af4ce3 --- /dev/null +++ b/l10n_ru_doc/report/report_act.xml @@ -0,0 +1,203 @@ + + + + + + diff --git a/l10n_ru_doc/report/report_bill.py b/l10n_ru_doc/report/report_bill.py new file mode 100644 index 0000000..400d3ad --- /dev/null +++ b/l10n_ru_doc/report/report_bill.py @@ -0,0 +1,14 @@ +from odoo import models +from odoo.addons.l10n_ru_doc.report_helper import QWebHelper + +class RuBillReport(models.AbstractModel): + _name = 'report.l10n_ru_doc.report_bill' + + def _get_report_values(self, docids, data=None): + docs = self.env['account.move'].browse(docids) + return { + 'helper': QWebHelper(), + 'doc_ids': docs.ids, + 'doc_model': 'account.move', + 'docs': docs + } diff --git a/l10n_ru_doc/report/report_bill.xml b/l10n_ru_doc/report/report_bill.xml new file mode 100644 index 0000000..c7f5568 --- /dev/null +++ b/l10n_ru_doc/report/report_bill.xml @@ -0,0 +1,758 @@ + + + + + + diff --git a/l10n_ru_doc/report/report_invoice.py b/l10n_ru_doc/report/report_invoice.py new file mode 100644 index 0000000..a71c09a --- /dev/null +++ b/l10n_ru_doc/report/report_invoice.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from odoo import models +from odoo.addons.l10n_ru_doc.report_helper import QWebHelper +class RuInvoiceReport(models.AbstractModel): + _name = 'report.l10n_ru_doc.report_invoice' + def _get_report_values(self, docids, data=None): + docs = self.env['account.move'].browse(docids) + return { + 'helper': QWebHelper(), + 'doc_ids': docs.ids, + 'doc_model': 'account.move', + 'docs': docs + } diff --git a/l10n_ru_doc/report/report_invoice.xml b/l10n_ru_doc/report/report_invoice.xml new file mode 100644 index 0000000..78b8b21 --- /dev/null +++ b/l10n_ru_doc/report/report_invoice.xml @@ -0,0 +1,329 @@ + + + + + + diff --git a/l10n_ru_doc/report/report_order.py b/l10n_ru_doc/report/report_order.py new file mode 100644 index 0000000..eb94aca --- /dev/null +++ b/l10n_ru_doc/report/report_order.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from odoo import models +from odoo.addons.l10n_ru_doc.report_helper import QWebHelper +class RuSaleOrderReport(models.AbstractModel): + _name = 'report.l10n_ru_doc.report_order' + def _get_report_values(self, docids, data=None): + docs = self.env['sale.order'].browse(docids) + return { + 'helper': QWebHelper(), + 'doc_ids': docs.ids, + 'doc_model': 'sale.order', + 'docs': docs + } diff --git a/l10n_ru_doc/report/report_order.xml b/l10n_ru_doc/report/report_order.xml new file mode 100644 index 0000000..f9d2127 --- /dev/null +++ b/l10n_ru_doc/report/report_order.xml @@ -0,0 +1,330 @@ + + + + + + diff --git a/l10n_ru_doc/report/report_upd.py b/l10n_ru_doc/report/report_upd.py new file mode 100644 index 0000000..1537ba8 --- /dev/null +++ b/l10n_ru_doc/report/report_upd.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from odoo import models +from odoo.addons.l10n_ru_doc.report_helper import QWebHelper + +class RuUpdReport(models.AbstractModel): + _name = 'report.l10n_ru_doc.report_upd' + def _get_report_values(self, docids, data=None): + docs = self.env['account.move'].browse(docids) + return { + 'helper': QWebHelper(), + 'doc_ids': docs.ids, + 'doc_model': 'account.move', + 'docs': docs + } +class RuUpdReportn(models.AbstractModel): + _name = 'report.l10n_ru_doc.report_updn' + def _get_report_values(self, docids, data=None): + docs = self.env['account.move'].browse(docids) + return { + 'helper': QWebHelper(), + 'doc_ids': docs.ids, + 'doc_model': 'account.move', + 'docs': docs + } diff --git a/l10n_ru_doc/report/report_upd.xml b/l10n_ru_doc/report/report_upd.xml new file mode 100644 index 0000000..1825c87 --- /dev/null +++ b/l10n_ru_doc/report/report_upd.xml @@ -0,0 +1,1108 @@ + + + + + + diff --git a/l10n_ru_doc/report/report_updn.xml b/l10n_ru_doc/report/report_updn.xml new file mode 100644 index 0000000..b3013c4 --- /dev/null +++ b/l10n_ru_doc/report/report_updn.xml @@ -0,0 +1,1177 @@ + + + + + + diff --git a/l10n_ru_doc/report_helper.py b/l10n_ru_doc/report_helper.py new file mode 100644 index 0000000..4ae4803 --- /dev/null +++ b/l10n_ru_doc/report_helper.py @@ -0,0 +1,112 @@ +from datetime import datetime +import re +from pytils import numeral, dt +from odoo.tools import pycompat + + +class QWebHelper(object): + + def img(self, img, type='png', width=0, height=0) : + if width : + width = "width='%spx'"%(width) + else : + width = " " + if height : + height = "height='%spx'"%(height) + else : + height = " " + toreturn = ""%( + width, + height, + type, + str(pycompat.to_text(img))) + return toreturn + + def numer(self, name): + if name: + numeration = re.findall(r'\d+$', name) + if numeration: + return numeration[0] + return '' + + def ru_date(self, date): + if date and date != 'False': + return dt.ru_strftime('"%d" %B %Y года', date=datetime.strptime(str(date), + "%Y-%m-%d"), inflected=True) + return '' + + def ru_date2(self, date): + if date and date != 'False': + return dt.ru_strftime('%d %B %Y г.', date=datetime.strptime(str(date), + "%Y-%m-%d %H:%M:%S"), inflected=True) + return '' + + def in_words(self, number): + return numeral.in_words(number) + + def rubles(self, sum): + text_rubles = numeral.rubles(int(sum)) + copeck = round((sum - int(sum))*100) + text_copeck = numeral.choose_plural(int(copeck), ("копейка", "копейки", "копеек")) + return ("%s %02d %s")%(text_rubles, copeck, text_copeck) + + def initials(self, fio): + if fio: + return (fio.split()[0]+' '+''.join([fio[0:1]+'.' for fio in fio.split()[1:]])).strip() + return '' + + def address(self, partner): + repr = [] + if partner.zip: + repr.append(partner.zip) + if partner.country_id: + repr.append(partner.country_id.name) + if partner.state_id: + repr.append(partner.state_id.name) + if partner.city: + repr.append(partner.city) + if partner.street: + repr.append(partner.street) + if partner.street2: + repr.append(partner.street2) + return ', '.join(repr) + + def representation(self, partner): + repr = [] + if partner.name: + repr.append(partner.name) + if partner.inn: + repr.append("ИНН " + partner.inn) + if partner.kpp: + repr.append("КПП " + partner.kpp) + repr.append(self.address(partner)) + return ', '.join(repr) + + def full_representation(self, partner): + repr = [self.representation(partner)] + if partner.phone: + repr.append("тел.: " + partner.phone) + elif partner.parent_id.phone: + repr.append("тел.: " + partner.parent_id.phone) + bank = None + if partner.bank_ids: + bank = partner.bank_ids[0] + elif partner.parent_id.bank_ids: + bank = partner.parent_id.bank_ids[0] + if bank and bank.acc_number: + repr.append("р/сч " + bank.acc_number) + if bank and bank.bank_name: + repr.append("в банке " + bank.bank_name) + if bank and bank.banvk_bic: + repr.append("БИК " + bank.bank_bic) + if bank and bank.bank_corr_acc: + repr.append("к/с " + bank.bank_corr_acc) + return ', '.join(repr) + + def representation_small(self, partner): + repr = [] + if partner.name: + repr.append(partner.name) + + repr.append(self.address(partner)) + return ', '.join(repr) diff --git a/l10n_ru_doc/static/description/docs.png b/l10n_ru_doc/static/description/docs.png new file mode 100644 index 0000000000000000000000000000000000000000..7cc91a81c1e5583ece913c89fa54443514169dfc GIT binary patch literal 16383 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 nMS(3-fsB#$P4+IZxfe>7RySo$Ioe(^@U*6sC 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 +
+

Первичные документы РФ

+
+

+Модуль для печати первичных документов в соответствии с законами РФ. +

+

+Возможности: +

    +
  • Товарная накладная (ТОРГ-12)
  • +
  • Счет на оплату
  • +
  • Счет-фактура
  • +
  • Акт выполненных работ
  • +
  • Вывод подписей и печати
  • +
+

+
+
+
+ +
+
+
+ + +
+
+

Помощь и поддержка

+
+
+ +
+
+ +
+
\ No newline at end of file diff --git a/l10n_ru_doc/static/description/support.png b/l10n_ru_doc/static/description/support.png new file mode 100644 index 0000000000000000000000000000000000000000..2805ec72a4dd9e7262b4c5b745e8228e2a46302e GIT binary patch literal 20040 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 literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/static/description/waybill.png b/l10n_ru_doc/static/description/waybill.png new file mode 100644 index 0000000000000000000000000000000000000000..8bab6182bcfeca85cdef52e55fe7dd685dfd0b24 GIT binary patch literal 16671 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 z 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 I!X)_r0fw&s6951J literal 0 HcmV?d00001 diff --git a/l10n_ru_doc/static/src/css/l10n_ru_doc.css b/l10n_ru_doc/static/src/css/l10n_ru_doc.css new file mode 100644 index 0000000..d77b69a --- /dev/null +++ b/l10n_ru_doc/static/src/css/l10n_ru_doc.css @@ -0,0 +1,7 @@ +@charset "utf-8"; +.openerp .codup_sign > img { + width: 235px; + height: 65px; + max-width: 235px; + max-height: 65px; +} \ No newline at end of file diff --git a/l10n_ru_doc/views/account_invoice_view.xml b/l10n_ru_doc/views/account_invoice_view.xml new file mode 100644 index 0000000..1d701fa --- /dev/null +++ b/l10n_ru_doc/views/account_invoice_view.xml @@ -0,0 +1,36 @@ + + + + + + account.invoice.ru.form + account.move + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_ru_doc/views/l10n_ru_doc_data.xml b/l10n_ru_doc/views/l10n_ru_doc_data.xml new file mode 100644 index 0000000..169bcd7 --- /dev/null +++ b/l10n_ru_doc/views/l10n_ru_doc_data.xml @@ -0,0 +1,14 @@ + + + + + + + 1 + + + + + + + diff --git a/l10n_ru_doc/views/product.xml b/l10n_ru_doc/views/product.xml new file mode 100644 index 0000000..7fea41d --- /dev/null +++ b/l10n_ru_doc/views/product.xml @@ -0,0 +1,16 @@ + + + + + tnved_product + product.product + + + + + + + + + + diff --git a/l10n_ru_doc/views/res_bank_view.xml b/l10n_ru_doc/views/res_bank_view.xml new file mode 100644 index 0000000..7468aac --- /dev/null +++ b/l10n_ru_doc/views/res_bank_view.xml @@ -0,0 +1,18 @@ + + + + + + res.bank.ru.form + res.bank + form + + + + + + + + + + diff --git a/l10n_ru_doc/views/res_company_view.xml b/l10n_ru_doc/views/res_company_view.xml new file mode 100644 index 0000000..6342ad2 --- /dev/null +++ b/l10n_ru_doc/views/res_company_view.xml @@ -0,0 +1,42 @@ + + + + + + res.companyruform + res.company + + + + + + + + + + ИНН + + + ОГРН + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_ru_doc/views/res_partner_view.xml b/l10n_ru_doc/views/res_partner_view.xml new file mode 100644 index 0000000..016701b --- /dev/null +++ b/l10n_ru_doc/views/res_partner_view.xml @@ -0,0 +1,36 @@ + + + + + + res.partner.ru.form + res.partner + + + + + + + + + + ИНН + + + + + + + + + + + + + + + + + + + diff --git a/l10n_ru_doc/views/res_users_view.xml b/l10n_ru_doc/views/res_users_view.xml new file mode 100644 index 0000000..e7ae0cf --- /dev/null +++ b/l10n_ru_doc/views/res_users_view.xml @@ -0,0 +1,33 @@ + + + + + + res.users.signature.form + res.users + + + + + + + + + + + + res.users.simple.form + res.users + + + + + + + + + + + + + diff --git a/l10n_ru_doc/views/tax.xml b/l10n_ru_doc/views/tax.xml new file mode 100644 index 0000000..3cefac6 --- /dev/null +++ b/l10n_ru_doc/views/tax.xml @@ -0,0 +1,17 @@ + + + + + view_taxiher_form + account.tax + + + + + + + + + + + diff --git a/l10n_ru_doc/views/uom.xml b/l10n_ru_doc/views/uom.xml new file mode 100644 index 0000000..08e8b0c --- /dev/null +++ b/l10n_ru_doc/views/uom.xml @@ -0,0 +1,28 @@ + + + + + view_uomiher_form + uom.uom + + + + + + + + + + view_uomiher_tree + uom.category + + + + + + + + + + + diff --git a/l10n_ru_upd_xml/__init__.py b/l10n_ru_upd_xml/__init__.py new file mode 100644 index 0000000..5a79dbb --- /dev/null +++ b/l10n_ru_upd_xml/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from . import controllers +from . import models +from . import reports diff --git a/l10n_ru_upd_xml/__manifest__.py b/l10n_ru_upd_xml/__manifest__.py new file mode 100644 index 0000000..4cb612d --- /dev/null +++ b/l10n_ru_upd_xml/__manifest__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Печать УПД в xml формате", + + 'summary': "Формирует УПД в формате XML, формат 5.01", + + 'description': """ +Формирует УПД в формате XML, формат 5.01 + """, + + 'author': "MKLab", + 'website': "https://inf-centre.ru", + + # Categories can be used to filter modules in modules listing + # Check https://github.com/odoo/odoo/blob/15.0/odoo/addons/base/data/ir_module_category_data.xml + # for the full list + 'category': 'Localization', + 'version': '17.0.1.230710', + + # any module necessary for this one to work correctly + 'depends': ['web','base','account','l10n_ru_doc','contract'], + + # always loaded + 'data': [ + 'views/ir_actions_report_view.xml', + 'views/res_partner_view.xml', + 'views/res_company_view.xml', + 'views/res_users_view.xml', + 'views/views_uom_okei.xml', + 'views/view_move.xml', + 'reports/report.xml', + 'reports/upd_report.xml', + ], + + 'assets': { + 'web.assets_backend': [ + 'upd_xml/static/src/js/report/action_manager_report.js', + ], + }, + # only loaded in demonstration mode + 'demo': [ + 'demo/demo.xml', + ], + + 'external_dependencies': { + 'python': [ + 'lxml' + ] + }, +} + diff --git a/l10n_ru_upd_xml/__pycache__/__init__.cpython-310.pyc b/l10n_ru_upd_xml/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f00f6c6be14ce006b48299ff2777ff8eeba715dc GIT binary patch literal 235 zcmYk0Jqp4=5QXZbKo*7QSt83qA}4#64?Y~%bKXr) zP)85WSs&02D=^j(jl6BZ$FR$jj(JM)k|aTSF+U_G`6_jR%BpBXRA2xW#$J0+N2A)t f=v(EK)@5Brt(VQc8?P{=b#_fJ1iF!ml+XAN5aBgO literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/controllers/__init__.py b/l10n_ru_upd_xml/controllers/__init__.py new file mode 100644 index 0000000..b0f26a9 --- /dev/null +++ b/l10n_ru_upd_xml/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import controllers diff --git a/l10n_ru_upd_xml/controllers/__pycache__/__init__.cpython-310.pyc b/l10n_ru_upd_xml/controllers/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d0fb94f9947e000856fff8c00e1974191853e3f0 GIT binary patch literal 188 zcmd1j<>g`kg69rX(~N=iV-N=!FabFZKwK;UBvKes7;_kM8KW2(8B&;n88n$+G6ID) z8E%z278UzxGTmY*0%=^yP{abHz{D?W{fzwFRQ;0F;u8J*l>B_%l+-dX xLq9P^zqBAFz9KhAAITW~`1s7c%#!$cy@JYH95%W6DWy57b|CwTL1qgu0RZYuEsFpE literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/controllers/__pycache__/controllers.cpython-310.pyc b/l10n_ru_upd_xml/controllers/__pycache__/controllers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fbaedf3b5840c5fd222b5fcaae49a3c9dd10af30 GIT binary patch literal 3152 zcmaJ@&2J<}6|buPoSsjQyJ*t{lRj;aEz4v~< zs=Qv02z=oWe!rJC3HduVu755xz7M6)P;tU(O1iUu+NIEDDa)L$L$S|E-OTHHncwxZ zpc`aiH?;k3TFIhrWMwa{X0>iDt9R?R?Wc{b*=yYq;f{PF81=k_PN}%ecs2!C0!p56`I!jc84FrDP*3e zLhkeyi{lP#+1Ygfu~JV_5VkxMcA$5HMeN zq5NwFsy@-=mwrhV(e#Y|jy;BTKP8`1;|xX$0?xMHFit$+atV}eb$Ne#KhMOrg5=rG zd7j_p;>Zfy3Ew^(^B7Fp#*~`{tGF(2jZaNVtMZ$$F?9n?7;}wTvaBlr`wn6VW9l-X( z0+8jUc>s6bR=)1>=$wad+dgD<@mivLs>(W1}wj? z)Oda_h;${6dudV>aXbt1Do*|?RLf9`??4s0K4p}>U<_*Ne#Sii-)^u%S80ugSi2Ez z(1^CEPhHS*|I>0Bbh7dPBicjXEI!-|Y1V;K{0+jS$P}P^K}!H5r|SgayG|G@z0&7S z2_WPyfc%bP0CL9y$Kl?&vr8s_(%#fXNa75T0+3(@fG$7|02%-|zYCCbd3ZrTWMxo> z${YF!$!VZL8-Pd3NQZKw$q@8)$Ro{o_1rD12uUD~5N0>#q*24!x-!K1k*>jf0O_zQ zPXW61GqB>oEl!o~({PheGtW$ydHVwW(}ea4PzVFEYCgjrHnSQS7Oh@+$}~lKDXTgf{{{BD z@%epqb+|gc$#1AN9i7n&Mv1O|01V+0wSM|fO3D@`lULQP>21EM1F)4@68nm70Ua*! zn|w_#@%5)p*;d~4j@m$bG}s1f(GP%`e*qU?+4^;Bcm97&k4fj&j>Y101mwhd@ZiBD z#N@vV+1X*U)b&(;AV!ng_AK8Kpxc-9!6n_6cVL!H=ZY;w8BbQ-M7F{LxSV2~?nI=oZk4(@P6` zI(f^g%&?1wPnH+l^YG;@J=u6i%3N+9?+;S3*%u=r6Ezt1H)k%{eEwIQx%3{e@aC?N z!2Fwb0^A60FXzGpnJ9{+FDxT;UXfn|efb(zn^2kNY@K*<82Ks=Aui=NaQsHx7YY~% zFZg&*=2>i62g$*B8ElXm|B=j(3t^VV5^juzu2uUct`lNq9Z-h=!rKCPw*YFENc*P7 z1=<KaaB~zUrRKcYn@8T>=uSiQK+=B?9H6~mTGF*{B z^A5!LYNl1F;Z1YJ?Nk^B?(qZ$Qhpm(eVJ?bq4_41;zOt+)}}7-X&X3p%}NbmRM-AO z>c3cV+IFl49NTi(M=cft>$afJwd@RO&1r5J*Pdf z1s1;35PAjPLm>g9S?h(nu|_41bXII~ngAmTDQ@b=LLN-SVSfu^Q_Rw(g71wjyuNHI z%rezlf>Ae-9aeb``WSq(^0H&=>g9SZC2!kt$Siy+0R3!XKFpsj(#E|40C?BtnEW}c nD1U+#+Ix*QuHtFJdoyp{M_McJu%QD%U~8-ffvT~Htvde&#aTgx literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/controllers/controllers.py b/l10n_ru_upd_xml/controllers/controllers.py new file mode 100644 index 0000000..537e3a8 --- /dev/null +++ b/l10n_ru_upd_xml/controllers/controllers.py @@ -0,0 +1,91 @@ +# Copyright (C) 2014-2015 Grupo ESOC +# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). + +import json +import logging + +from werkzeug.urls import url_parse + +from odoo.http import content_disposition, request, route, serialize_exception +from odoo.tools import html_escape +from odoo.tools.safe_eval import safe_eval, time + +from odoo.addons.web.controllers import report + +_logger = logging.getLogger(__name__) + + +class ReportController(report.ReportController): + @route() + def report_routes( + self, reportname, docids=None, converter=None, options=None, **kwargs + ): + if converter != "xml": + return super().report_routes( + reportname, + docids=docids, + converter=converter, + options=options, + **kwargs, + ) + if docids: + docids = [int(_id) for _id in docids.split(",")] + data = {**json.loads(options or "{}"), **kwargs} + context = dict(request.env.context) + if "context" in data: + data["context"] = json.loads(data["context"] or "{}") + # Ignore 'lang' here, because the context in data is the one from the + # webclient *but* if the user explicitely wants to change the lang, this + # mechanism overwrites it. + if "lang" in data["context"]: + del data["context"]["lang"] + context.update(data["context"]) + report_Obj = request.env["ir.actions.report"] + xml = report_Obj.with_context(**context)._render_qweb_xml( + reportname, docids, data=data + )[0] + xmlhttpheaders = [("Content-Type", "text/xml"), ("Content-Length", len(xml))] + return request.make_response(xml, headers=xmlhttpheaders) + + @route() + def report_download(self, data, context=None, token=None): + requestcontent = json.loads(data) + url, report_type = requestcontent[0], requestcontent[1] + reportname = "???" + if report_type != "qweb-xml": + return super().report_download(data, context=context, token=token) + try: + reportname = url.split("/report/xml/")[1].split("?")[0] + docids = None + if "/" in reportname: + reportname, docids = reportname.split("/") + report = request.env["ir.actions.report"]._get_report_from_name(reportname) + filename = None + if docids: + response = self.report_routes( + reportname, docids=docids, converter="xml", context=context + ) + ids = [int(x) for x in docids.split(",")] + obj = request.env[report.model].browse(ids) + if report.print_report_name and not len(obj) > 1: + report_name = safe_eval( + report.print_report_name, {"object": obj, "time": time} + ) + filename = f"{report_name}.{report.xml_extension}" + else: + data = url_parse(url).decode_query(cls=dict) + if "context" in data: + context = json.loads(context or "{}") + data_context = json.loads(data.pop("context")) + context = json.dumps({**context, **data_context}) + response = self.report_routes( + reportname, converter="xml", context=context, **data + ) + filename = filename or f"{report.name}.{report.xml_extension}" + response.headers.add("Content-Disposition", content_disposition(filename)) + return response + except Exception as e: + _logger.exception(f"Error while generating report {reportname}") + se = serialize_exception(e) + error = {"code": 200, "message": "Odoo Server Error", "data": se} + return request.make_response(html_escape(json.dumps(error))) \ No newline at end of file diff --git a/l10n_ru_upd_xml/demo/demo.xml b/l10n_ru_upd_xml/demo/demo.xml new file mode 100644 index 0000000..b5678e1 --- /dev/null +++ b/l10n_ru_upd_xml/demo/demo.xml @@ -0,0 +1,30 @@ + + + + + diff --git a/l10n_ru_upd_xml/models/__init__.py b/l10n_ru_upd_xml/models/__init__.py new file mode 100644 index 0000000..6c43466 --- /dev/null +++ b/l10n_ru_upd_xml/models/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +from . import ir_actions_report +from . import res_company +from . import res_partner +from . import res_users +from . import uom_okei +from . import move diff --git a/l10n_ru_upd_xml/models/__pycache__/__init__.cpython-310.pyc b/l10n_ru_upd_xml/models/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..069b0dbbdbf6b9d8b6cca771c0daa31bff356c49 GIT binary patch literal 347 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 ZtnK+%u!?p=Jvm#ga*jQ+;mJNaAirR#alrrp literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/models/__pycache__/res_partner.cpython-310.pyc b/l10n_ru_upd_xml/models/__pycache__/res_partner.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..de5e48698a2130748b9312d0a806690fd2fce30d GIT binary patch literal 1191 zcmah}&1(}u6rb6zY|UY5E0q#K`7-rBEZT(p zRLY=OsNBMpT|oc>G$sl4XkvIqVtOVecL^9^ZW1t=xnOOWo(xVPOAUu$AlY>BsG zCqJibyJAlqiUaW--QLu2=aVcvWi3C9(mUgZEX<`zGjB2Jauz_^h?nvqb!x@(wwUvzqbtVWQqIg0zoVj@vRPvXjcAhgL8dGdILw&?=lj})#LZDX4P z#eNviOn$H3)3MuNUBFj=XxSCErqTq}ILmevsYqADp zx^jK}0Z=o?Ro_*HYz)CA7A+Yis=g8Zxki<0pP6w-TB=<-ur7+LUx~Eut3QDD8HlYq V%~b;F-ss)%rh3mz9T_EK#$WYIM2`Rf literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/models/__pycache__/res_users.cpython-310.pyc b/l10n_ru_upd_xml/models/__pycache__/res_users.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7a5e740629b844cf8b35b351525e0ea9faa9f04e GIT binary patch literal 988 zcmZ8gJ!lkB5PpBVw|5s$gtWl>cZ7jXUe)T zFO<$~AAQsG_m+ons!2>0iJ77?*J3@u{7SrKapZAIw{#qZ7_guRgs-)C%kmS0{Txd&^4xYM3 zzsQGGsjCn}-qlCrz3Kw0@5kHYH}#kC>+yE|x&Gz^2KFhqP6?lcQH#KKAH;~v+$^Cy>nR1E?n4U>=nhr<88g@aove5~<^g7BumZ3?=OlUsGD(8i zEw;r+OtCpK;=mBO!4$!fEj!}qm19@~a*XA7L)Xj_Tl%iJ)@o`_^|sahVxYXkGy&>( zrUx#t!z?Yk!U?OhRY$FxnF8MU&${`Mm^q02eXF-tl^-i==;n zl&&QuTv25j^cg8PswBgSf)&Yhu%=B~8tjV`i))E7xIyMT3fu<6(9=+Qs0YgWy8P3o z#5}?R5SYYbctiy4unrU$f%Lv*Xt=-@_=NsGgL81f5`H!wGnEs&XE3pgZcmE8g9~Ue JWR_fFe*kwC`c41< literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/models/__pycache__/uom_okei.cpython-310.pyc b/l10n_ru_upd_xml/models/__pycache__/uom_okei.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2caf925289eaf2a996ee68f249414b6da6ee92c GIT binary patch literal 706 zcmZuvJ#W=86!m8kN(-eRCP1tiNH(SlRbpU*g)Ks|qIV51C5|6XQo&nc?TCaJ*x8wp z_y?K2GVudgn7B8oN+oK^NB16I-;ZPay}ccV>xX$^?{da|l5=q>bdGTMhX}xcx6JX1 zJ5dQIE6Ldt1_I;<2Ga6l^#>9EBZ6A}DjcuWivfeZ+ zI=i?eI!CzsI|!Cl99SiQSJJ9uO%+dhm4L#$I?B0Peh5wX>RFz~%$Tlr)|j|s4E8d%WbYdDW~|$@lgu>T+JzqZX+ z7Oo*R!=H!c+B;hgwjW9l-ai0)G8<(L<+uU!*0tp_Zi&4aN>FUx1&tX<**-zYnBx0l z=Kho6T>g6)c$o~KP6Y~~QHUgFRKxibyS-7bR(|Y;g1n+_Ivc3e_U0zwz^lPfWCH~? zl#7t!Sxkd%>%jtQ6fz{j6$1Jm;VJjh*^L+@UpBiJ6xXX5&qI8^(}TFZ|lFk +# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). + +from odoo import fields, models, api + + +class IrActionsReport(models.Model): + _inherit = "ir.actions.report" + + report_type = fields.Selection( + selection_add=[("qweb-xml", "XML")], ondelete={"qweb-xml": "set default"} + ) + xsd_schema = fields.Binary( + string="XSD Validation Schema", + attachment=True, + help="File with XSD Schema for checking content of result report. Can be empty " + "if validation is not required.", + ) + xml_encoding = fields.Selection( + selection=[ + ("WINDOWS-1251", "WINDOWS-1251") # will be used as default even if nothing is selected + ], + string="XML Encoding", + help=( + "Encoding for XML reports. If nothing is selected, " + "then UTF-8 will be applied." + ), + ) + xml_declaration = fields.Boolean( + string="XML Declaration", + help=( + """Add `` at the start """ + """of final report file.""" + ), + default=True, + ) + xml_extension = fields.Char( + default="xml", + help="Extension for XML Reports, by default is `xml`", + ) + + @api.model + def _render_qweb_xml(self, report_ref, res_ids, data=None): + """ + Call `generate_report` method of report abstract class + `report.` or of standard class for XML report + rendering - `report.upd_xml.abstract` + + Args: + * docids(list) - IDs of instances for those report will be generated + * data(dict, None) - variables for report rendering + + Returns: + * str - result content of report + * str - type of result content + """ + report = self._get_report(report_ref) + report_model = self.env.get( + f"report.{report.report_name}", self.env["report.upd_xml.abstract"] + ) + return report_model.generate_report( + ir_report=report, # will be used to get settings of report + docids=res_ids, + data=data or {}, + ) diff --git a/l10n_ru_upd_xml/models/move.py b/l10n_ru_upd_xml/models/move.py new file mode 100755 index 0000000..208e7b9 --- /dev/null +++ b/l10n_ru_upd_xml/models/move.py @@ -0,0 +1,209 @@ +from odoo import api, fields, models +import hashlib +from odoo.exceptions import UserError +from odoo.http import request + +class Users(models.Model): + _inherit = 'account.move' + + edi = fields.Char(string='ID EDI', compute='sh1_edi') + kpp = fields.Char(string='КПП', compute='get_kpp') + def get_kpp(self): + for s in self: + pid=self.partner_id.parent_id or self.partner_id + + s.kpp=pid.kpp if (s.partner_id==s.partner_shipping_id or not s.partner_shipping_id) else s.partner_shipping_id.kpp + + @api.depends('name') + def sh1_edi(self): + hash_object = hashlib.sha1((self.name).encode('utf-8')) + pid=self.partner_id.parent_id or self.partner_id + self.edi='ON_NSCHFDOPPR_2BM-'+str(pid.edi)+'_'+str(self.company_id.edi)+'_'+hash_object.hexdigest() + + def print_upd(self): + for s in self: + mes = str(s.check_correct_upd()).strip() + if mes != "": + raise UserError(u"Не удалось сформировать УПД. Выявлены следующие ошибки:\n{}".format(mes)) + else: + # pdf = \ + return self.env.ref('upd_xml.upd_xml_report').sudo().report_action(s.id) # render_qweb_xml(s.id) + # pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf)), ] + # return request.make_response(pdf, headers=pdfhttpheaders) + + def check_correct_upd(self, manually=True): + for s in self: + mes = "" + company = s.company_id + if s.name == '/': + mes += u"Отсутствует наименование документа. Проверидите документ, чтобы назваие сформировалось автоматически.\n" + if not s.only_service and s.get_delivery_doc_name()=='0': + mes += u"Отсутствуют связанные отгрузки.\n" + if not company: + company = self.env.company + if not company: + mes += u"Не указана компания.\n" + else: + if not company.edi: + mes += u"Не указан идентификатор компании для Diadoc.\n" + if not company.name: + mes += u"Не указано наименование компании.\n" + if not company.okpo: + mes += u"Не указано ОКПО компании.\n" + if not company.inn: + mes += u"Не указан ИНН компании.\n" + else: + if len(company.inn) == 12: + if not company.partner_id.last_name_IP: + mes += u"Не указана фамилия ИП для вашей компании.\n" + if not company.partner_id.first_name_IP: + mes += u"Не указано имя ИП для вашей компании.\n" + if not company.partner_id.middle_name_IP: + mes += u"Не указано отчество ИП для вашей компании.\n" + elif len(company.inn) == 10: + if not company.kpp: + mes += u"Не указан КПП компании.\n" + else: + mes += u"Некорректный ИНН компании.\n" + if not company.city: + mes += u"Не указан город компании.\n" + if not company.street: + mes += u"Не указан адрес компании.\n" + if not company.chief_id: + mes += u"Не указан руководитель компании.\n" + else: + if not company.chief_id.function: + mes += u"Не указана должность руководителя компании.\n" + if not company.chief_id.last_name: + mes += u"Не указана фамилия руководителя компании.\n" + if not company.chief_id.first_name: + mes += u"Не указано имя руководителя компании.\n" + if not company.chief_id.second_name: + mes += u"Не указано отчество руководителя компании.\n" + pid = s.partner_id.parent_id + if not pid: + pid = s.partner_id + if not pid: + mes += u"Не указан контрагент.\n" + else: + if not pid.edi: + mes += u"Не указан идентификатор контрагента для Diadoc.\n" + if not pid.name: + mes += u"Не указано наименование контрагента.\n" + if not pid.okpo: + mes += u"Не указано ОКПО контрагента.\n" + if not pid.inn: + mes += u"Не указан ИНН контрагента.\n" + else: + if len(pid.inn) == 12: + if not pid.last_name_IP: + mes += u"Не указана фамилия ИП для контрагента.\n" + if not pid.first_name_IP: + mes += u"Не указано имя ИП для контрагента.\n" + if not pid.middle_name_IP: + mes += u"Не указано отчество ИП для контрагента.\n" + elif len(pid.inn) == 10: + if not pid.kpp: + mes += u"Не указан КПП контрагента.\n" + else: + mes += u"Некорректный ИНН контрагента.\n" + if not pid.city: + mes += u"Не указан город контрагента.\n" + if not pid.street: + mes += u"Не указан адрес контрагента.\n" + if manually: + if not s.edi: + mes += u"Не указан идентификатор документа для Diadoc.\n" + if not s.name: + mes += u"Не указано наименование документа\n" + if not s.invoice_date: + mes += u"Не указана дата документа\n" + if not s.only_service: + gruzootpr = s.gruzootpr + if not gruzootpr: + gruzootpr = pid + if gruzootpr.parent_id: + gruzootpr = gruzootpr.parent_id + if not gruzootpr: + mes += u"Не указан грузоотправитель.\n" + else: + if not gruzootpr.name: + mes += u"Не указано наименование грузоотправителя.\n" + if not gruzootpr.okpo: + mes += u"Не указано ОКПО грузоотправителя.\n" + if not gruzootpr.inn: + mes += u"Не указан ИНН грузоотправителя.\n" + else: + if len(gruzootpr.inn) == 12: + if not gruzootpr.last_name_IP: + mes += u"Не указана фамилия ИП для грузоотправителя.\n" + if not gruzootpr.first_name_IP: + mes += u"Не указано имя ИП для грузоотправителя.\n" + if not gruzootpr.middle_name_IP: + mes += u"Не указано отчество ИП для грузоотправителя.\n" + elif len(gruzootpr.inn) == 10: + if not gruzootpr.kpp: + mes += u"Не указан КПП грузоотправителя.\n" + else: + mes += u"Некорректный ИНН грузоотправителя.\n" + if not gruzootpr.city: + mes += u"Не указан город грузоотправителя.\n" + if not gruzootpr.street: + mes += u"Не указан адрес грузоотправителя.\n" + gruzopol = s.gruzopol + if not gruzopol: + gruzopol = pid + if gruzopol.parent_id: + gruzopol = gruzopol.parent_id + if not gruzopol: + mes += u"Не указан грузополучатель.\n" + else: + if not gruzopol.name: + mes += u"Не указано наименование грузополучателя.\n" + if not gruzopol.okpo: + mes += u"Не указано ОКПО грузополучателя.\n" + if not gruzopol.inn: + mes += u"Не указан ИНН грузополучателя.\n" + else: + if len(gruzopol.inn) == 12: + if not gruzopol.last_name_IP: + mes += u"Не указана фамилия ИП для грузополучателя.\n" + if not gruzopol.first_name_IP: + mes += u"Не указано имя ИП для грузополучателя.\n" + if not gruzopol.middle_name_IP: + mes += u"Не указано отчество ИП для грузополучателя.\n" + elif len(gruzopol.inn) == 10: + if not gruzopol.kpp: + mes += u"Не указан КПП грузополучателя.\n" + else: + mes += u"Некорректный ИНН грузополучателя.\n" + if not gruzopol.city: + mes += u"Не указан город грузополучателя.\n" + if not gruzopol.street: + mes += u"Не указан адрес грузополучателя.\n" + if s.payment_num: + if not s.payment_date: + mes += u"Не указана дата платежки в УПД.\n" + if not s.invoice_line_ids: + mes += u"Отсутствуют строки заказа.\n" + else: + for line in s.invoice_line_ids: + if not line.price_unit: + mes += u"Не указана цена за единицу для товара {}.\n".format(line.name) + if not line.quantity: + mes += u"Не указано количество для товара {}.\n".format(line.name) + if not line.product_uom_id.okei: + mes += u"Не указан код ОКЕИ для единицы измерения {}.\n".format(line.product_uom_id.name) + if not s.mt_contractid: + mes += u"Не указан договор.\n" + else: + if not s.mt_contractid.name: + mes += u"Не указано наименование договора.\n" + if not s.mt_contractid.date_start: + mes += u"Не указана дата договора.\n" + if not s.kladov: + mes += u"Не указано лицо, ответственное за передачу товаров/услуг.\n" + else: + if not s.kladov.partner_id.function: + mes += u"Не указана должность лица, ответственного за передачу товаров/услуг.\n" + return str(mes) \ No newline at end of file diff --git a/l10n_ru_upd_xml/models/res_company.py b/l10n_ru_upd_xml/models/res_company.py new file mode 100755 index 0000000..945d134 --- /dev/null +++ b/l10n_ru_upd_xml/models/res_company.py @@ -0,0 +1,6 @@ +from odoo import api, fields, models + +class Company(models.Model): + _inherit = 'res.company' + + edi = fields.Char(string='ID EDI', readonly=False) \ No newline at end of file diff --git a/l10n_ru_upd_xml/models/res_partner.py b/l10n_ru_upd_xml/models/res_partner.py new file mode 100755 index 0000000..ddf1f85 --- /dev/null +++ b/l10n_ru_upd_xml/models/res_partner.py @@ -0,0 +1,33 @@ +from odoo import api, fields, models + +class ResPartner(models.Model): + _inherit = 'res.partner' + + edi = fields.Char('ID EDI') + house = fields.Char('Дом') + office = fields.Char('Квартира, офис') + fias_id = fields.Char('Код ФИАС') + last_name_IP = fields.Char('Фамилия ИП', compute='get_fio', readonly=False) + first_name_IP = fields.Char('Имя ИП', compute='get_fio',readonly=False) + middle_name_IP = fields.Char('Отчество ИП', compute='get_fio',readonly=False) + + @api.depends('name') + def get_fio(self): + for s in self: + if s.name: + name = s.name + if name.find('ИП ')!=-1: + name = name[name.find(' ')+1:] + s.last_name_IP = name[:name.find(' ')] + name = name[name.find(' ') + 1:] + s.first_name_IP = name[:name.find(' ')] + name = name[name.find(' ') + 1:] + s.middle_name_IP = name + else: + s.last_name_IP = "" + s.first_name_IP = "" + s.middle_name_IP = "" + else: + s.last_name_IP = "" + s.first_name_IP = "" + s.middle_name_IP = "" \ No newline at end of file diff --git a/l10n_ru_upd_xml/models/res_users.py b/l10n_ru_upd_xml/models/res_users.py new file mode 100755 index 0000000..30a844d --- /dev/null +++ b/l10n_ru_upd_xml/models/res_users.py @@ -0,0 +1,25 @@ +from odoo import api, fields, models + +class Users(models.Model): + _inherit = 'res.users' + + last_name = fields.Char(string='Фамилия', compute='update_name') + first_name = fields.Char(string='Имя', compute='update_name') + second_name = fields.Char(string='Отчество', compute='update_name') + + @api.depends('name') + def update_name(self): + for s in self: + s.last_name = '' + s.first_name = '' + s.second_name = '' + if s.name: + s.last_name = s.name + s.first_name = '' + s.second_name = '' + if len(s.name.split(' ')) == 3: + s.last_name, s.first_name, s.second_name = s.name.split(' ') + if len(s.name.split(' ')) == 4: + s.last_name, s.first_name, second_name1, second_name2 = s.name.split(' ') + s.second_name = second_name1 + ' ' + second_name2 + diff --git a/l10n_ru_upd_xml/models/uom_okei.py b/l10n_ru_upd_xml/models/uom_okei.py new file mode 100755 index 0000000..b40925b --- /dev/null +++ b/l10n_ru_upd_xml/models/uom_okei.py @@ -0,0 +1,12 @@ +from odoo import models, fields, api + + +class uom(models.Model): + _inherit="uom.uom" + + okei = fields.Char(string="Код ОКЕИ") + +class uom_move(models.Model): + _inherit="account.move.line" + + uom_okei = fields.Char(string='Код ОКЕИ',related='product_uom_id.okei') diff --git a/l10n_ru_upd_xml/reports/__init__.py b/l10n_ru_upd_xml/reports/__init__.py new file mode 100755 index 0000000..fff0f44 --- /dev/null +++ b/l10n_ru_upd_xml/reports/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). + +from . import report_report_xml_abstract diff --git a/l10n_ru_upd_xml/reports/__pycache__/__init__.cpython-310.pyc b/l10n_ru_upd_xml/reports/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a0e94a4cd12daf2c2b6758226ce35df6520d4a5d GIT binary patch literal 209 zcmd1j<>g`kf`jofsrf+qF^Gc(44TX@8G*u@ zjJKqUQVa5nO5&kZMQ%=fVp4HQQDSn5pC;2Sh9ZzTD;bJdfE1Yc<*1*LpPQ;*l3HA% zpP!PSubYxu24?8zR>mi$q~zxn>my8qGK=-&<1_OzOXB183My}L*yQG?l;)(`fgDi` IvO$0e0O&F{f&c&j literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/reports/__pycache__/__init__.cpython-36.pyc b/l10n_ru_upd_xml/reports/__pycache__/__init__.cpython-36.pyc new file mode 100755 index 0000000000000000000000000000000000000000..2055cb97dea4126d4a508c43029eda7636ee7865 GIT binary patch literal 199 zcmXr!<>fl}Ln|qtfq~&M5W@izkmUfx#R5Pgg&~D8has0Sijk2ag(;XplldhhP*{`k zmQ+z{L4Hw5Jd~=)&52J;DlREXOfK=$WV*#r1TtqOLlFy*0u#R+^)vEwQ}s(yi%azL zQ}Xk5Q&P*o4E@~7_{5Zy{Jdg)glSM_v3`7fW?p7Ve7s&kg`kf-9$8lJbG{V-N=hn1BoiATAaF5-AKRj5!Rsj8Tk?3@J>(44TX@8G*u@ zjJKqUQVa5nO5&kZMQ%=fVp4HQQDSn5pC;2Sh9ZzTD;bJdfE1YcWuTv%SE8R<0aT-# sn39s8SFDfF3}qJU$H!;pWtPOp>lIYq;;_lhPbtkwwPOYv@)?L3008GOtpET3 literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/reports/__pycache__/report_report_xml_abstract.cpython-310.pyc b/l10n_ru_upd_xml/reports/__pycache__/report_report_xml_abstract.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..baed71787dec3b2c92b6926ad92f8a9ff64fa283 GIT binary patch literal 1747 zcmah}&1)Pt6qhub+1c6kN0K(Bm*PSx-GFzK;)WcINr~O!(zwMNCt;urmd+z`?M8 z5uRvW648?WN%z7DmxMngz4o7QKj~51K770(WKs$Vi&mZ%sVH+`U1^k*J;yq6m0B+c zg-qM-@ZiUt{e$7oezdy{S}QN(EETay%VI~VQYCon?Q!GJ21q3dsURT}G;{b6!cyjXX0Wz6Jw=?xls0g&DaAFTPoS zGU~qC-P``*)o}gMmtQ@yG)O2owHOQ-2d2ik2IN;#lbRVpovbzr-A|vxE10XlqD&kx!jJNGnvC?vA@SyFOa%Kx` zSbkEb1=y*w)L>k-^%{&)VVPRrlu+b&DmYSQKIgj#e&I?luw2XR$hK28kAd|>nWREn z4zDq`fsz_Lhz`Nhod$^j#T$_~QV37W9%Q!ed<#NpZB-#jXwR~6ebw6#Xufw_!&&?1F0Fl&>>OFuxOC= z9Q8T!2t)N2(p#YK&QphtBYGQWr&2!vHI47VXQR*FNA&)I#vJq?KZ-D~QDlQCf<}0n zA>WOnH>Ytn-*Foi5DKXil~!0_3K~4IZqqu|06{)Pf{*AH!5FJHkS37rPBao4ji=jYR`Zwc zc4V(+xvZ~|cnuzd7vKT<$|-Mve4=W0*Rco^J*t}O>Yw`Rr|XNsApG<1J4b)Gg#1OW z4G!{GK>84vAc7X8q%ox^vx1dQ>~ykI@Y0RlPUeMI`mtXIanQ}(qF07-NXd6Zc*4IR z!k59czi{G61P5f)dj)rs5w*Red%HqrwU99J%e=}(U4rOJqof=$>!eL?y%IJQ8uY`% zw8%wj^1Av)saj=t&w5-T-vx~%F%=|cg2s+uF_-St6M^8uy`T#k``x_Pp~HC~9KaRY z8$ZdWR_0k*e0`*iN;5NiPj#yC@|T>I#W-EB-CFP3diLmtt>xKChCpzHKpxNoApIM# z*3m&u=1%KOA+Uli7$q&8(w4Q(f`Oh+84#?)j2k|6TfU%kw?*(n;l8AEPk3`*`13#n zQ(yE%ctKik8Z5{|vH(Y>J<*2~o(ZRYps4j06mA?ezqWyh;2XT;^IqE%8^;VB-kjL} z$}e-?NXv~pGnaJh6}kZN_VP-|%FNs+kH6i%KZ~AzKY94$(}V51pMQDR(lDd24F_A1 zhQHnd){>v!or7hC{*VQU2ug>9lIKhiuuLbI@m%XB%`nky{F&uNUdi8yx(OFt9_;*5 zmvYBQZFXu=*V{tA=!Bi}JV}M9E4}kNB`fht^?D^)Cu`iCU-tG+WF^lUwf`X^McACo zc9)5}mh>@hQ>l^3@}luxQD`uL{z~H&KZ|bE%Fl70(&MPp}6uH5`YU_1CrNZRez|>ISh&nu0b-9uw z^kD4|ya%pjacq0JS_Q&-qRw)mEr(Z_#-WlL97vAxD!$Pn5wLNsvfffwZ=*pkYr3-W zJMSvfrFqG2;rj4jG2aBGz732pPC1QeR!fV)U!d7V49P}hDib)@U%cVN|NWNX|Y;yyDgv;QfDe}u;>(Y zbYk7EXR1#@R*2&o+zvQ~Tm`@)AdM`*utG?q_c`rWCZmD%j#4e}?JA5{>_c&kp+PSz zj~6gq))L1D+Syg;t{vihEYC98A=1i6?O@$3A7MN1O#Bxr8|*E;-N!^}Y@(2R7O_pp F{Xae2ONFbD~ZKmXW2`rReu zFPy9f2jL4KeF#htK?_pSm{OEk!Ad7~I@u|B>Bep+^TI3r*e`=P=;m(GE5kUXBNx;4#=?gH{4Bz)b@@Z?FgCGLc+u^^C}m038E{Fl5)tblQy~aO4v|n z(61k+MJ`g4*VR`_)hfe#R^uA^4rnBasUR^EG%r5dRL_NX2G27lS?|Mvz`dyglEFjz6obh>&+?LIB0%p1JQ>sdd;W3wkHP1 z3>;n?+y2robJ0l4jXXCKz6k@O?d6q_m6^CdKL2{_@g#cj?RfwD7YADpK7aVY(lDdo z5)KCB0BNKTfVJeOdsDEhz?&JF6Ak}ELdh#82w0_K%yzDIlV+G?Hu}u+BCq6cMBRep zZ=P(ImDvU;D&0zjs4KmF6aA%lt-4uBR(TmU7jJsIC$f^~joSMNVIf9NCOeB9y_Me) zZd0j|$>O5XZc%4xq4!4D7g&B~jvqfCIyR6M6l-3c*mbCb1WLC^;VhJ+jT$A5xkwt7 zSH?Q9JY2J(mPW|q^sF%UUUDK07=f6=mXjo_D~z^XU#Joz%ccMv*BPnOQYwtA?Ki2? z^1$FZ+c)*X6qvC5w9YFq(-gVE2x{wf5T(K*w1KIiit$uW1$^CaRzI&*9 z0^?!N21$ZxP7)g?3ADMh0_7-4UY(`Ia>ebofKo`Esl35*Q_!}Fb-Tu>J_T8AA-jRw zNf>e!0E>V$vH-&hA&uVWv|AYu2i7}EwS2Ur@Qqj>iem&_cu{%0fa#)^crEI>v#Zcu tyN>gbJkMl@NGl(;gH=a-hCRD8@n5KHu)FYf50j*^Q$p@p#BM?E{{exC)dv6o literal 0 HcmV?d00001 diff --git a/l10n_ru_upd_xml/reports/report.xml b/l10n_ru_upd_xml/reports/report.xml new file mode 100755 index 0000000..bed15ef --- /dev/null +++ b/l10n_ru_upd_xml/reports/report.xml @@ -0,0 +1,14 @@ + + + + + УПД xml + account.move + qweb-xml + upd_xml.demo_report_xml_view + upd_xml.demo_report_xml_view + '%s' % (object.edi) + + report + + diff --git a/l10n_ru_upd_xml/reports/report_report_xml_abstract.py b/l10n_ru_upd_xml/reports/report_report_xml_abstract.py new file mode 100755 index 0000000..e4fd6a5 --- /dev/null +++ b/l10n_ru_upd_xml/reports/report_report_xml_abstract.py @@ -0,0 +1,48 @@ +# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). + +from base64 import b64decode +from xml.dom import minidom + +from lxml import etree + +from odoo import api, models,SUPERUSER_ID +from odoo.exceptions import ValidationError + + +class ReportXmlAbstract(models.AbstractModel): + _name = "report.upd_xml.abstract" + _description = "Abstract XML Report" + + @api.model + def generate_report(self, ir_report, docids, data=None): + data = data or {} + data.setdefault("report_type", "text") + data = ir_report._get_rendering_context(ir_report, docids, data) + + result_bin = ir_report._render_template(ir_report.report_name, data) + + parsed_result_bin = minidom.parseString(result_bin) + result = parsed_result_bin.toprettyxml(indent=" ") + + # remove empty lines + utf8 = "UTF-8" + cp1251="WINDOWS-1251" + result = "\n".join( + line for line in result.splitlines() if line and not line.isspace() + ).encode('utf8') + + content = etree.tostring( + etree.fromstring(result), + encoding=ir_report.xml_encoding or cp1251, + xml_declaration=True, + pretty_print=True, + ) + return content, "xml" + + @api.model + def _get_report_values(self, docids, data=None): + return data or {} + + # if not data: + # data = {} + # return data.decode('cp1251') diff --git a/l10n_ru_upd_xml/reports/upd_report.xml b/l10n_ru_upd_xml/reports/upd_report.xml new file mode 100755 index 0000000..50d47b5 --- /dev/null +++ b/l10n_ru_upd_xml/reports/upd_report.xml @@ -0,0 +1,186 @@ + + + + diff --git a/l10n_ru_upd_xml/security/ir.model.access.csv b/l10n_ru_upd_xml/security/ir.model.access.csv new file mode 100644 index 0000000..7a89480 --- /dev/null +++ b/l10n_ru_upd_xml/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_upd_xml_upd_xml,upd_xml.upd_xml,model_upd_xml_upd_xml,base.group_user,1,1,1,1 diff --git a/l10n_ru_upd_xml/static/src/js/report/action_manager_report.js b/l10n_ru_upd_xml/static/src/js/report/action_manager_report.js new file mode 100755 index 0000000..e83200e --- /dev/null +++ b/l10n_ru_upd_xml/static/src/js/report/action_manager_report.js @@ -0,0 +1,49 @@ +/** @odoo-module **/ + +import {download} from "@web/core/network/download"; +import {registry} from "@web/core/registry"; + +function getReportUrl({report_name, context, data}, env) { + // Rough copy of action_service.js _getReportUrl method. + let url = `/report/xml/${report_name}`; + const actionContext = context || {}; + if (data && JSON.stringify(data) !== "{}") { + const encodedOptions = encodeURIComponent(JSON.stringify(data)); + const encodedContext = encodeURIComponent(JSON.stringify(actionContext)); + return `${url}?options=${encodedOptions}&context=${encodedContext}`; + } + if (actionContext.active_ids) { + url += `/${actionContext.active_ids.join(",")}`; + } + const userContext = encodeURIComponent(JSON.stringify(env.services.user.context)); + return `${url}?context=${userContext}`; +} +async function triggerDownload(action, {onClose}, env) { + // Rough copy of action_service.js _triggerDownload method. + env.services.ui.block(); + const data = JSON.stringify([getReportUrl(action, env), action.report_type]); + const context = JSON.stringify(env.services.user.context); + try { + await download({url: "/report/download", data: {data, context}}); + } finally { + env.services.ui.unblock(); + } + if (action.close_on_report_download) { + return env.services.action.doAction( + {type: "ir.actions.act_window_close"}, + {onClose} + ); + } + if (onClose) { + onClose(); + } +} +registry + .category("ir.actions.report handlers") + .add("xml_handler", async function (action, options, env) { + if (action.report_type === "qweb-xml") { + await triggerDownload(action, options, env); + return true; + } + return false; + }); diff --git a/l10n_ru_upd_xml/views/ir_actions_report_view.xml b/l10n_ru_upd_xml/views/ir_actions_report_view.xml new file mode 100755 index 0000000..d5cd94f --- /dev/null +++ b/l10n_ru_upd_xml/views/ir_actions_report_view.xml @@ -0,0 +1,24 @@ + + + + ir.actions.report.view.form.report.xml + ir.actions.report + + + + + + + + + + + + + diff --git a/l10n_ru_upd_xml/views/res_company_view.xml b/l10n_ru_upd_xml/views/res_company_view.xml new file mode 100755 index 0000000..2d43a2c --- /dev/null +++ b/l10n_ru_upd_xml/views/res_company_view.xml @@ -0,0 +1,19 @@ + + + + + + res.company.ru.form + res.company + + + + + + + + + + + + diff --git a/l10n_ru_upd_xml/views/res_partner_view.xml b/l10n_ru_upd_xml/views/res_partner_view.xml new file mode 100755 index 0000000..c716587 --- /dev/null +++ b/l10n_ru_upd_xml/views/res_partner_view.xml @@ -0,0 +1,26 @@ + + + + + + res.partner.ru.form + res.partner + + + + + + + + + + + + + + + + + + + diff --git a/l10n_ru_upd_xml/views/res_users_view.xml b/l10n_ru_upd_xml/views/res_users_view.xml new file mode 100755 index 0000000..8dc9487 --- /dev/null +++ b/l10n_ru_upd_xml/views/res_users_view.xml @@ -0,0 +1,21 @@ + + + + + + res.users.signature.form + res.users + + + + + + + + + + + + + + diff --git a/l10n_ru_upd_xml/views/view_move.xml b/l10n_ru_upd_xml/views/view_move.xml new file mode 100755 index 0000000..21a699b --- /dev/null +++ b/l10n_ru_upd_xml/views/view_move.xml @@ -0,0 +1,17 @@ + + + + edi account move + account.move + + + + +