automatic update repo with commit - 'Update .gitlab-ci.yml' from project dadata_connector

This commit is contained in:
odoo-robot 2025-02-25 08:56:37 +00:00
commit 5ec2d7a228
16 changed files with 692 additions and 0 deletions

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# DaData Connector
Obtaining data on legal entities from the DaData service.

2
__init__.py Normal file
View File

@ -0,0 +1,2 @@
from . import models
from . import wizard

21
__manifest__.py Normal file
View File

@ -0,0 +1,21 @@
{
"name": "DaData Connector",
"summary": """Obtaining data on legal entities from the DaData service""",
"author": "RYDLAB",
"website": "http://rydlab.ru",
"category": "Marketing",
"version": "17.0.1.0.0",
"depends": ["base", "web", "contacts", "account", "l10n_ru_doc"],
"external_dependencies": {"python": ["dadata==21.10.1"]},
"data": [
"security/ir.model.access.csv",
"views/res_partner_views.xml",
"wizard/res_partner_auto_data_wizard_views.xml",
"views/res_config_settings_view.xml",
],
"assets": {
"web.assets_backend": [
"dadata_connector/static/src/views/fields/search/*",
],
},
}

225
i18n/ru.po Normal file
View File

@ -0,0 +1,225 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * dadata_connector
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-18 05:07+0000\n"
"PO-Revision-Date: 2024-07-18 05:07+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: dadata_connector
#: model:ir.model.fields.selection,name:dadata_connector.selection__res_partner_auto_data_wizard__status__active
msgid "Active"
msgstr "Действующая"
#. module: dadata_connector
#: model:ir.model.fields.selection,name:dadata_connector.selection__res_partner_auto_data_wizard__status__bankrupt
msgid "Bankrupt"
msgstr "Банкротство"
#. module: dadata_connector
#: model:ir.model,name:dadata_connector.model_res_config_settings
msgid "Config Settings"
msgstr "Конфигурационные настройки"
#. module: dadata_connector
#: model:ir.model,name:dadata_connector.model_res_partner
msgid "Contact"
msgstr "Контакт"
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__create_uid
msgid "Created by"
msgstr ""
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__create_date
msgid "Created on"
msgstr ""
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_config_settings__dadata_token
msgid "DaData token"
msgstr ""
#. module: dadata_connector
#. odoo-javascript
#: code:addons/dadata_connector/static/src/views/fields/search/search_field.js:0
#: code:addons/local_addons/dadata_connector/static/src/views/fields/search/search_field.js:0
#, python-format
msgid "Data updated."
msgstr "Данные обновлены."
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__display_name
msgid "Display Name"
msgstr ""
#. module: dadata_connector
#. odoo-python
#: code:addons/dadata_connector/models/res_partner.py:0
#: code:addons/local_addons/dadata_connector/models/res_partner.py:0
#, python-format
msgid ""
"Failed to connect to DaData server. The token in the settings may be "
"incorrect."
msgstr ""
"Не удалось подключиться к серверу DaData. Возможно, токен в настройках "
"указан не верно."
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__full_address
msgid "Full legal address"
msgstr "Юридический адрес"
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__name
msgid "Full name"
msgstr "Наименование"
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__id
msgid "ID"
msgstr ""
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__vat
msgid "Identification Number"
msgstr "ИНН"
#. module: dadata_connector
#: model:ir.model.fields,help:dadata_connector.field_res_partner_auto_data_wizard__vat
msgid "Identification Number for selected type"
msgstr ""
#. module: dadata_connector
#: model:ir.model.fields.selection,name:dadata_connector.selection__res_partner_auto_data_wizard__organization_type__individual
msgid "Individual entrepreneur"
msgstr "Индивидуальный предприниматель"
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard____last_update
msgid "Last Modified on"
msgstr ""
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__write_uid
msgid "Last Updated by"
msgstr ""
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__write_date
msgid "Last Updated on"
msgstr ""
#. module: dadata_connector
#: model:ir.model.fields.selection,name:dadata_connector.selection__res_partner_auto_data_wizard__organization_type__legal
msgid "Legal entity"
msgstr "Юридическое лицо"
#. module: dadata_connector
#: model:ir.model.fields,help:dadata_connector.field_res_partner_auto_data_wizard__organization_type
msgid "Legal entity or individual entrepreneur"
msgstr "Юридическое лицо или индивидуальный предприниматель"
#. module: dadata_connector
#: model:ir.model.fields.selection,name:dadata_connector.selection__res_partner_auto_data_wizard__status__liquidated
msgid "Liquidated"
msgstr "Ликвидирована"
#. module: dadata_connector
#: model:ir.model.fields.selection,name:dadata_connector.selection__res_partner_auto_data_wizard__status__liquidating
msgid "Liquidating"
msgstr "Ликвидируется"
#. module: dadata_connector
#: model_terms:ir.ui.view,arch_db:dadata_connector.res_partner_auto_data_wizard_view_form
msgid "No"
msgstr "Нет"
#. module: dadata_connector
#. odoo-python
#: code:addons/dadata_connector/models/res_partner.py:0
#: code:addons/local_addons/dadata_connector/models/res_partner.py:0
#, python-format
msgid "No data found for the organization"
msgstr "Не найдены данные для организации"
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__partner_id
msgid "Partner"
msgstr "Контакт"
#. module: dadata_connector
#: model:ir.model.fields.selection,name:dadata_connector.selection__res_partner_auto_data_wizard__status__reorganizing
msgid "Reorganizing"
msgstr ""
"В процессе присоединения к другому юр. лицу, с последующей ликвидацией"
#. module: dadata_connector
#. odoo-javascript
#: code:addons/dadata_connector/static/src/views/fields/search/search_field.js:0
#: code:addons/dadata_connector/static/src/views/fields/search/search_field.xml:0
#: code:addons/dadata_connector/static/src/views/fields/search/search_field.xml:0
#: code:addons/local_addons/dadata_connector/static/src/views/fields/search/search_field.js:0
#: code:addons/local_addons/dadata_connector/static/src/views/fields/search/search_field.xml:0
#: code:addons/local_addons/dadata_connector/static/src/views/fields/search/search_field.xml:0
#, python-format
msgid "Search"
msgstr "Поиск"
#. module: dadata_connector
#. odoo-python
#: code:addons/dadata_connector/models/res_partner.py:0
#: code:addons/local_addons/dadata_connector/models/res_partner.py:0
#, python-format
msgid "Set these details for the current contact?"
msgstr "Установить данные реквизиты для текущего контакта?"
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__status
msgid "Status"
msgstr "Статус"
#. module: dadata_connector
#. odoo-python
#: code:addons/dadata_connector/models/res_partner.py:0
#: code:addons/local_addons/dadata_connector/models/res_partner.py:0
#, python-format
msgid ""
"The token for DaData is not specified in the settings. (Settings - General "
"settings - Integrations - DaData token)"
msgstr ""
"В настройках не указан токен для DaData. (Настройки - Общие настройки - "
"Интеграции - DaData token)"
#. module: dadata_connector
#: model:ir.model.fields,field_description:dadata_connector.field_res_partner_auto_data_wizard__organization_type
msgid "Type of organization"
msgstr "Тип организации"
#. module: dadata_connector
#. odoo-python
#: code:addons/dadata_connector/models/res_partner.py:0
#: code:addons/local_addons/dadata_connector/models/res_partner.py:0
#, python-format
msgid "Unknown organization type"
msgstr "Неизвестный тип организации"
#. module: dadata_connector
#: model:ir.model,name:dadata_connector.model_res_partner_auto_data_wizard
msgid "Wizard for autofilling partner"
msgstr "Визард для автозаполнения контактов"
#. module: dadata_connector
#: model_terms:ir.ui.view,arch_db:dadata_connector.res_partner_auto_data_wizard_view_form
msgid "Yes"
msgstr "Да"

2
models/__init__.py Normal file
View File

@ -0,0 +1,2 @@
from . import res_config_settings
from . import res_partner

View File

@ -0,0 +1,10 @@
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
dadata_token = fields.Char(
string="DaData token",
config_parameter="dadata_connector.dadata_token",
)

162
models/res_partner.py Normal file
View File

@ -0,0 +1,162 @@
from dadata import Dadata
from httpx import HTTPStatusError
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
okopf = {
"50102": "sp",
"11000": "pshp",
"11051": "pshp",
"11064": "pshp",
"20700": "pshp",
"20701": "pshp",
"20716": "pshp",
"30006": "pshp",
# "": "coop", # todo Cooperative
"12300": "plc",
"12200": "jsc",
"12247": "pc",
"12267": "сjsc",
# "": "ga", # todo Government agency
}
class ResPartner(models.Model):
_inherit = "res.partner"
def get_legal_entity_data(self, vat, widget=True):
token = self.get_dadata_token()
dadata = Dadata(token)
try:
result = dadata.find_by_id("party", vat, branch_type="MAIN")
except HTTPStatusError:
raise ValidationError(
_(
"Failed to connect to DaData server. The token in the settings may be incorrect."
)
)
if result:
wizard_data, new_data = self._parse_dadata_response(result)
if widget:
wizard = self.env["res.partner.auto_data.wizard"].create(wizard_data)
return {
"type": "ir.actions.act_window",
"target": "new",
"name": _("Set these details for the current contact?"),
"views": [(False, "form")],
"view_mode": "form",
"res_model": wizard._name,
"res_id": wizard.id,
"context": new_data,
}
else:
return new_data
else:
raise ValidationError(_("No data found for the organization"))
@api.model
def get_dadata_token(self):
token = (
self.env["ir.config_parameter"]
.sudo()
.get_param("dadata_connector.dadata_token")
)
if token:
return token
else:
raise ValidationError(
_(
"The token for DaData is not specified in the settings. (Settings - General settings - Integrations - DaData token)"
)
)
def _parse_dadata_response(self, data):
result = {}
wizard_data = {}
data = data[0]["data"]
# Data for widget
organization_type = data["type"].lower()
wizard_data["partner_id"] = self.id
wizard_data["status"] = data["state"]["status"].lower()
wizard_data["organization_type"] = organization_type
wizard_data["full_address"] = data["address"]["unrestricted_value"]
# Data for partner
result["vat"] = data["inn"]
result["okpo"] = data["okpo"]
result["arceat"] = data["okved"]
result["company_form"] = okopf.get(data["opf"]["code"])
if result["company_form"] == okopf["50102"]:
result["psrn_sp"] = data["ogrn"]
result["ogrn"] = ""
else:
result["psrn_sp"] = ""
result["ogrn"] = data["ogrn"]
if data["documents"] and data["documents"]["fts_registration"]:
result[
"sp_register_number"
] = f'{data["documents"]["fts_registration"]["series"]} {data["documents"]["fts_registration"]["number"]}'
result["sp_register_date"] = data["documents"]["fts_registration"][
"issue_date"
]
if organization_type == "legal":
result["kpp"] = data["kpp"]
# Name
if organization_type == "legal":
result["name"] = data["name"]["short_with_opf"]
wizard_data["name"] = data["name"]["short_with_opf"]
elif organization_type == "individual":
result[
"name"
] = f'{data["fio"]["surname"]} {data["fio"]["name"]} {data["fio"]["patronymic"]}'
wizard_data[
"name"
] = f'{data["fio"]["surname"]} {data["fio"]["name"]} {data["fio"]["patronymic"]}'
else:
raise ValidationError(_("Unknown organization type"))
# Address
address = data["address"]["data"]
country = self.env["res.country"].search(
[("code", "=", address["country_iso_code"])]
)
if country:
result["country_id"] = (country.id, country.name)
region = self.env["res.country.state"].search(
[
("code", "=", address["region_iso_code"].split("-")[-1]),
("country_id", "=", country.id),
]
)
if region:
result["state_id"] = (region.id, region.name)
result["city"] = address["city"]
street = []
for el in [
address["street_with_type"],
address["house_type_full"],
address["house"],
address["flat_type_full"],
address["flat"],
]:
if el:
street.append(el)
result["street"] = ", ".join(street)
result["zip"] = address["postal_code"]
if data.get("management"):
result["management"] = {
"manager_name": data["management"]["name"],
"manager_position": data["management"]["post"],
}
return wizard_data, result

View File

@ -0,0 +1,2 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_res_partner_auto_data_wizard","res_partner_auto_data_wizard user","model_res_partner_auto_data_wizard",,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_res_partner_auto_data_wizard res_partner_auto_data_wizard user model_res_partner_auto_data_wizard 1 1 1 1

View File

@ -0,0 +1,121 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { _lt } from "@web/core/l10n/translation";
import { useInputField } from "@web/views/fields/input_field_hook";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
import { Component } from "@odoo/owl";
export class SearchField extends Component {
setup() {
useInputField({ getValue: () => this.props.record.data[this.props.name] || "" });
this.action = null;
}
async search() {
this.action = await this.env.services.orm.call(
"res.partner",
"get_legal_entity_data",
[this.env.model.root.data.id],
{
vat: this.props.record.data[this.props.name],
}
);
await this.env.services.action.doAction(this.action, {
onClose: async (closeInfo) => {
if (closeInfo && closeInfo.update) {
// Creates record
const record = this.props.record;
const { management, ...newRecordData } = this.action.context;
await record.update({
...newRecordData,
company_type: "company",
});
await record.save();
const recordChildren = record.data.child_ids.records;
if (
management &&
!this._checkManagerExists(recordChildren, management)
) {
await this._createManager(management);
}
await this.env.model.load({
resId: record._config.resId,
mode: record.mode,
});
this.env.services.notification.add(_lt("Data updated."), {
type: "info",
});
}
},
});
}
_checkManagerExists(recordChildren, management) {
const managerName = management.manager_name;
const managerFunction = management.manager_position;
for (let record of recordChildren) {
if (
record.data.name.toUpperCase() === managerName.toUpperCase() &&
record.data.function.toUpperCase() === managerFunction.toUpperCase()
)
return true;
}
return null;
}
async _createManager(management) {
const record = this.props.record;
const point = this.env.model;
const paren_id = record._config.resId
const params = {
resModel: "res.partner",
resIds: [],
fields: record.data.child_ids.fields,
activeFields: record.data.child_ids.activeFields,
context: {
default_name: management.manager_name,
default_function: management.manager_position,
default_parent_id: paren_id,
default_type: "contact",
},
mode: "edit",
viewType: "form",
isMonoRecord: true,
groupBy: [],
};
const newRecordData = await point._loadNewRecord(params);
const newRecord = await point._createRoot(params, newRecordData);
await newRecord.save();
}
}
SearchField.template = "dadata_connector.SearchField";
SearchField.props = {
...standardFieldProps,
placeholder: { type: String, optional: true },
};
SearchField.displayName = _lt("Search");
SearchField.supportedTypes = ["char"];
SearchField.extractProps = ({ attrs }) => {
return {
placeholder: attrs.placeholder,
};
};
class FormSearchField extends SearchField { }
FormSearchField.template = "dadata_connector.FormSearchField";
registry.category("fields").add("search", { component: SearchField });
registry.category("fields").add("form.search", { component: FormSearchField });

View File

@ -0,0 +1,4 @@
.o_search_content small {
overflow-wrap: normal;
word-break: normal;
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="dadata_connector.SearchField" owl="1">
<div class="o_search_content d-inline-flex w-100">
<t t-if="props.readonly">
<a t-if="props.record.data[props.name]" class="o_form_uri" t-att-href="searchHref" t-esc="props.record.data[props.name]" />
</t>
<t t-else="">
<input class="o_input"
t-att-id="props.id"
type="text"
autocomplete="off"
t-att-placeholder="props.placeholder"
t-ref="input" />
</t>
</div>
</t>
<t t-name="dadata_connector.FormSearchField" t-inherit="dadata_connector.SearchField" t-inherit-mode="primary">
<xpath expr="//input" position="after">
<button
t-if="props.record.data[props.name]"
class="btn btn-secondary fa fa-search o_select_file_button"
data-tooltip="Search"
aria-label="Search"
t-on-click="() => this.search()"/>
</xpath>
</t>
</templates>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="dadata_res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.dadata</field>
<field name="model">res.config.settings</field>
<field name="priority" eval="15" />
<field name="inherit_id" ref="base.res_config_settings_view_form" />
<field name="arch" type="xml">
<xpath expr="//setting[@id='recaptcha']" position="after">
<setting id="dadata_token" help="Dadata token value">
<field name="dadata_token" />
</setting>
</xpath>
</field>
</record>
</odoo>

View File

@ -0,0 +1,30 @@
<?xml version='1.0' encoding='utf-8'?>
<odoo>
<record id="partner_with_auto_data_view_form" model="ir.ui.view">
<field name="name">Partner with auto data view form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="l10n_ru_doc.view_partner_ru_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='ogrn']" position="attributes">
<attribute name="widget">search</attribute>
</xpath>
<xpath expr="//field[@name='psrn_sp']" position="attributes">
<attribute name="widget">search</attribute>
</xpath>
</field>
</record>
<record id="partner_with_auto_data_view_form2" model="ir.ui.view">
<field name="name">Partner with auto data view form 2</field>
<field name="model">res.partner</field>
<field name="priority">2</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='vat']" position="attributes">
<attribute name="widget">search</attribute>
</xpath>
</field>
</record>
</odoo>

1
wizard/__init__.py Normal file
View File

@ -0,0 +1 @@
from . import res_partner_auto_data_wizard

View File

@ -0,0 +1,40 @@
from odoo import fields, models
class ResPartnerAutoDataWizard(models.TransientModel):
_name = "res.partner.auto_data.wizard"
_description = "Wizard for autofilling partner"
partner_id = fields.Many2one(
string="Partner",
comodel_name="res.partner",
)
vat = fields.Char(
string="Identification Number", help="Identification Number for selected type"
)
status = fields.Selection(
string="Status",
selection=[
("active", "Active"),
("liquidating", "Liquidating"),
("liquidated", "Liquidated"),
("bankrupt", "Bankrupt"),
("reorganizing", "Reorganizing"),
],
)
organization_type = fields.Selection(
string="Type of organization",
selection=[
("legal", "Legal entity"),
("individual", "Individual entrepreneur"),
],
help="Legal entity or individual entrepreneur",
)
name = fields.Char(string="Full name")
full_address = fields.Text(string="Full legal address")
def button_yes(self):
return {"type": "ir.actions.act_window_close", "infos": {"update": True}}

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_partner_auto_data_wizard_view_form" model="ir.ui.view">
<field name="name">Partner with auto data wizard view form</field>
<field name="model">res.partner.auto_data.wizard</field>
<field name="arch" type="xml">
<form create="0" delete="0" edit="0">
<group>
<field name="status"
decoration-success="status == 'active'"
decoration-danger="status != 'active'"/>
<field name="organization_type"/>
<field name="name"/>
<field name="full_address"/>
</group>
<footer>
<button string="Yes" class="oe_highlight" name="button_yes" type="object"/>
<button string="No" class="btn btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
</odoo>