Public release from ruodoo-project: 19.0 - 2026-05-31 21:19:12 UTC

This commit is contained in:
CI Publish Bot
2026-05-31 21:19:21 +00:00
commit aa4214c195
1213 changed files with 183945 additions and 0 deletions

View File

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

View File

@ -0,0 +1,202 @@
from odoo import models, fields, _
from odoo.exceptions import UserError
import base64
import dateutil.parser
# import logging
# _logger = logging.getLogger(__name__)
class InvoiceImportWizard(models.TransientModel):
_name = 'invoice.import.wizard'
_description = 'Import Invoice'
file = fields.Binary(string='File', required=True)
file_name = fields.Char(string='File Name')
def action_import_invoice(self):
# _logger.info("Начало импорта файла выписки")
if not self.file:
# _logger.error("Файл не загружен")
raise UserError(_("Please upload the file."))
if not self.file_name.endswith('.txt'):
# _logger.error("Неподдерживаемый формат файла: %s", self.file_name)
raise UserError(_("Only TXT files are allowed."))
file_content = base64.b64decode(self.file).decode('cp1251')
journal = self.env['account.journal'].search([('type', '=', 'bank'), ('use_in_bank_statement', '=', True)],
limit=1)
if not journal:
raise UserError(_("Suitable journal not found."))
try:
sections = file_content.split('СекцияДокумент')
invoice_sections = sections[0]
transaction_sections = sections[1:]
invoices = invoice_sections.split('СекцияРасчСчет')[1:]
for invoice in invoices:
statement_data = self.parse_statement_data(invoice)
existing_statement = self.env['account.bank.statement'].search([
('date_from', '=', dateutil.parser.parse(statement_data.get('ДатаНачала', '').strip(), dayfirst=True).date()),
('name', '=', statement_data.get('РасчСчет', '').strip()),
], limit=1)
if not existing_statement:
statement = self.create_statement(journal, statement_data)
# _logger.info("Выписка создана успешно: %s", statement.name)
self.create_statement_lines(journal, transaction_sections)
except Exception as e:
# _logger.error("Ошибка при импорте файла: %s", e)
raise UserError(_("Error Import: %s" % str(e)))
message_title = _("Импорт завершен")
message_content = _("Выписка успешно импортирована.")
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': message_title,
'message': message_content,
},
}
def parse_statement_data(self, section):
lines = section.strip().split('\n')
statement_data = {}
for line in lines:
if '=' in line:
key, value = line.split('=', 1)
statement_data[key] = value
return statement_data
def create_statement(self, journal, statement_data):
statement_vals = {
'journal_id': journal.id,
'name': statement_data.get('РасчСчет', '').strip(),
'balance_start': float(statement_data.get('НачальныйОстаток', '0.0').strip()),
'balance_end_real': float(statement_data.get('КонечныйОстаток', '0.0').strip()),
'date_from': dateutil.parser.parse(statement_data.get('ДатаНачала', '').strip(), dayfirst=True).date(),
}
return self.env['account.bank.statement'].sudo().create(statement_vals)
def create_statement_lines(self, journal, sections):
for section in sections:
if section.strip():
lines = section.strip().split('\n')
transaction = self.parse_transaction_data(lines)
if transaction:
# _logger.info("<==================================>")
# _logger.info("Создание строки выписки для транзакции №%s", transaction.get('Номер').strip())
self.create_line(journal, transaction)
# _logger.info("Строка выписки для транзакции №%s создана успешно", transaction.get('Номер').strip())
def parse_transaction_data(self, lines):
transaction = {}
for line in lines:
if '=' in line:
key, value = line.split('=', 1)
transaction[key] = value
return transaction
def create_line(self, journal, transaction):
my_company_inn = journal.company_id.vat
transaction_date = dateutil.parser.parse(transaction.get('Дата', '').strip(), dayfirst=True).date()
statement = self.env['account.bank.statement'].search([
('date_from', '=', transaction_date),
], limit=1)
if not statement:
raise UserError(_("Statement not found for journal {} on date {}.").format(journal.name, transaction_date))
amount = float(transaction.get('Сумма', '0.0').strip())
if transaction.get('ПлательщикИНН').strip() == my_company_inn:
amount = -amount
partner_inn = transaction.get('ПолучательИНН').strip()
partner_kpp = transaction.get('ПолучательКПП').strip()
partner_name = transaction.get('Получатель').strip()
partner_account = transaction.get('ПолучательСчет').strip()
bank_bik = transaction.get('ПолучательБИК').strip()
bank_account = transaction.get('ПолучательКорсчет').strip()
bank_name = transaction.get('ПолучательБанк1').strip()
elif transaction.get('ПолучательИНН').strip() == my_company_inn:
# Если наша компания - получатель, значит это доход
partner_inn = transaction.get('ПлательщикИНН').strip()
partner_kpp = transaction.get('ПлательщикКПП').strip()
partner_name = transaction.get('Плательщик').strip()
partner_account = transaction.get('ПлательщикСчет').strip()
bank_bik = transaction.get('ПлательщикБИК').strip()
bank_account = transaction.get('ПлательщикКорсчет').strip()
bank_name = transaction.get('ПлательщикБанк1').strip()
else:
error_message = "ИНН вашей компании не найден в транзакции. Запись не создана."
error_message += "Журнал: {}, Дата транзакции: {}. ".format(journal.name, transaction_date)
error_message += "Плательщик: {}, ИНН плательщика: {}. ".format(transaction.get('Плательщик1', 'не указан').strip(),
transaction.get('ПлательщикИНН',
'не указан').strip())
error_message += "Получатель: {}, ИНН получателя: {}. ".format(transaction.get('Получатель1', 'не указан').strip(),
transaction.get('ПолучательИНН',
'не указан').strip())
raise UserError(_(f"{error_message}"))
existing_line = self.env['account.bank.statement.line'].search([
('date', '=', transaction_date),
('amount', '=', amount),
('narration', '=', transaction.get('НазначениеПлатежа', '').strip()),
('payment_ref', '=', transaction.get('Номер').strip()),
], limit=1)
if existing_line:
# _logger.info("Строка выписки уже существует: %s", existing_line.id)
return None
partner = self.env['res.partner'].search([('vat', '=', partner_inn), ('kpp', '=', partner_kpp)], limit=1)
if not partner:
# _logger.info("Создание нового партнера: ИНН %s, КПП %s", partner_inn, partner_kpp)
partner = self.env['res.partner'].create({
'name': partner_name,
'vat': partner_inn,
'kpp': partner_kpp,
'company_type': 'company',
})
bank = self.env['res.bank'].search([('bic', '=', bank_bik), ('corr_acc', '=', bank_account)], limit=1)
if not bank:
# _logger.info("Создание нового банка: БИК %s", bank_bik)
bank = self.env['res.bank'].create({
'name': bank_name,
'bic': bank_bik,
'corr_acc': bank_account,
})
partner_bank_account = self.env['res.partner.bank'].search(
[('acc_number', '=', partner_account), ('partner_id', '=', partner.id)], limit=1)
if not partner_bank_account:
# _logger.info("Создание нового банковского счета для партнера %s", partner.name)
partner_bank_account = self.env['res.partner.bank'].create({
'acc_number': partner_account,
'bank_id': bank.id,
'partner_id': partner.id,
})
line_vals = {
'journal_id': journal.id,
'partner_bank_id': partner_bank_account.id,
'partner_id': partner.id,
'statement_id': statement.id,
'company_id': journal.company_id.id,
'date': transaction_date,
'amount': amount,
'narration': transaction.get('НазначениеПлатежа', '').strip(),
'payment_ref': transaction.get('Номер').strip(),
}
self.env['account.bank.statement.line'].sudo().create(line_vals)

View File

@ -0,0 +1,25 @@
<odoo>
<record id="view_invoice_import_wizard_form" model="ir.ui.view">
<field name="name">invoice.import.wizard.form</field>
<field name="model">invoice.import.wizard</field>
<field name="arch" type="xml">
<form string="Import Invoice">
<group>
<field name="file" filename="file_name"/>
<field name="file_name" invisible="1"/>
</group>
<footer>
<button string="Import" name="action_import_invoice" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_invoice_import_wizard" model="ir.actions.act_window">
<field name="name">Import Invoice</field>
<field name="res_model">invoice.import.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>