Public release from ruodoo-project: 19.0 - 2026-05-10 21:19:01 UTC
This commit is contained in:
1
account_bank_statement_1c_import/wizard/__init__.py
Normal file
1
account_bank_statement_1c_import/wizard/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from . import invoice_import_wizard
|
||||
202
account_bank_statement_1c_import/wizard/invoice_import_wizard.py
Normal file
202
account_bank_statement_1c_import/wizard/invoice_import_wizard.py
Normal 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)
|
||||
@ -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>
|
||||
Reference in New Issue
Block a user