@ -0,0 +1,48 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
Import Bank Statement |
|||
===================== |
|||
This module import bank statement in CSV, XLSX, OFX and QIF format. |
|||
|
|||
Configuration |
|||
============= |
|||
- www.odoo.com/documentation/15.0/setup/install.html |
|||
- Install our custom addon |
|||
- Install openpyxl, ofxparse, qifparse |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
Credits |
|||
------- |
|||
Developer: (V15) Sruthi Renjith, Contact: odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
License |
|||
------- |
|||
GNU AFFERO GENERAL PUBLIC LICENSE, Version 3 (AGPLv3) |
|||
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
========== |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Sruthi Renjith (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from .import models |
|||
from . import wizard |
@ -0,0 +1,46 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Sruthi Renjith (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
{ |
|||
'name': 'Import Bank Statement', |
|||
'version': '15.0.1.0.0', |
|||
'category': 'Accounting', |
|||
'summary': 'Import Bank Statement in CSV, XLSX, QIF and OFX format', |
|||
'description': """Uploading the data in CSV, XLSX, OFX and QIF format and |
|||
converting it into bank statement""", |
|||
'author': "Cybrosys Techno Solutions", |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': "https://www.cybrosys.com", |
|||
'depends': ['base_accounting_kit'], |
|||
'data': ['security/ir.model.access.csv', |
|||
'views/account_journal_views.xml', |
|||
'wizard/import_bank_statement_views.xml' |
|||
], |
|||
'external_dependencies': { |
|||
'python': ['openpyxl', 'ofxparse'] |
|||
}, |
|||
'images': ['static/description/banner.jpg'], |
|||
'license': 'AGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': False, |
|||
} |
@ -0,0 +1,6 @@ |
|||
## Module <import_bank_statement_odoo> |
|||
|
|||
#### 15.09.2023 |
|||
#### Version 15.0.1.0.0 |
|||
#### ADD |
|||
- Initial commit for Import Bank Statement |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Sruthi Renjith (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from . import account_journal |
@ -0,0 +1,39 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Sruthi Renjith (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import models |
|||
|
|||
|
|||
class AccountJournal(models.Model): |
|||
""" Class to add import button in account_journal model """ |
|||
_inherit = "account.journal" |
|||
|
|||
def action_import_wizard(self): |
|||
"""Function to open wizard""" |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'view_mode': 'form', |
|||
'res_model': 'import.bank.statement', |
|||
'target': 'new', |
|||
'context': { |
|||
'default_journal_id': self.id, |
|||
} |
|||
} |
|
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 219 KiB |
After Width: | Height: | Size: 141 KiB |
|
@ -0,0 +1,65 @@ |
|||
OFXHEADER:100 |
|||
DATA:OFXSGML |
|||
VERSION:102 |
|||
SECURITY:NONE |
|||
ENCODING:USASCII |
|||
CHARSET:1252 |
|||
COMPRESSION:NONE |
|||
OLDFILEUID:NONE |
|||
NEWFILEUID:NONE |
|||
|
|||
<OFX> |
|||
<SIGNONMSGSRSV1> |
|||
<SONRS> |
|||
<STATUS> |
|||
<CODE>0</CODE> |
|||
<SEVERITY>INFO</SEVERITY> |
|||
</STATUS> |
|||
<DTSERVER>20230419</DTSERVER> |
|||
<LANGUAGE>ENG</LANGUAGE> |
|||
<FI> |
|||
<ORG>BANK123</ORG> |
|||
</FI> |
|||
</SONRS> |
|||
</SIGNONMSGSRSV1> |
|||
<BANKMSGSRSV1> |
|||
<STMTTRNRS> |
|||
<TRNUID>1234567890</TRNUID> |
|||
<STATUS> |
|||
<CODE>0</CODE> |
|||
<SEVERITY>INFO</SEVERITY> |
|||
</STATUS> |
|||
<STMTRS> |
|||
<CURDEF>USD</CURDEF> |
|||
<BANKACCTFROM> |
|||
<BANKID>Bank-2023-04-14/1</BANKID> |
|||
<ACCTID>1234567890</ACCTID> |
|||
<ACCTTYPE>CHECKING</ACCTTYPE> |
|||
</BANKACCTFROM> |
|||
<BANKTRANLIST> |
|||
<DTSTART>20220101</DTSTART> |
|||
<DTEND>20220131</DTEND> |
|||
<STMTTRN> |
|||
<TRNTYPE>DEBIT</TRNTYPE> |
|||
<DTPOSTED>20230419</DTPOSTED> |
|||
<TRNAMT>-3000.00</TRNAMT> |
|||
<FITID>1234567890-20220102-1</FITID> |
|||
<NAME>Deco Addict</NAME> |
|||
</STMTTRN> |
|||
<STMTTRN> |
|||
<TRNTYPE>CREDIT</TRNTYPE> |
|||
<DTPOSTED>20220115</DTPOSTED> |
|||
<TRNAMT>1000.00</TRNAMT> |
|||
<FITID>1234567890-20220115-1</FITID> |
|||
<NAME>Ready Mat</NAME> |
|||
</STMTTRN> |
|||
</BANKTRANLIST> |
|||
<LEDGERBAL> |
|||
<BALAMT>10044.87</BALAMT> |
|||
<DTASOF>20220131</DTASOF> |
|||
</LEDGERBAL> |
|||
</STMTRS> |
|||
</STMTTRNRS> |
|||
</BANKMSGSRSV1> |
|||
</OFX> |
|||
|
@ -0,0 +1,15 @@ |
|||
!Type:Bank |
|||
D14/04/2023 |
|||
T2000.00 |
|||
PBank-2023-02-11/1 |
|||
^ |
|||
!Type:Bank |
|||
D09/04/2023 |
|||
T-500.00 |
|||
PBank-2023-04-09/2 |
|||
^ |
|||
!Type:Bank |
|||
D19/06/2022 |
|||
T1000.00 |
|||
PBank-2023-04-21/3 |
|||
^ |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 9.3 KiB |
@ -0,0 +1,21 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
<!-- Adding import button in bank journal of accounting --> |
|||
<record id="account_journal_dashboard_kanban_view" model="ir.ui.view"> |
|||
<field name="name">account.journal.view.kanban.inherit.import.bank.statement.odoo</field> |
|||
<field name="model">account.journal</field> |
|||
<field name="inherit_id" |
|||
ref="account.account_journal_dashboard_kanban_view"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//div[@id='dashboard_bank_cash_left']" |
|||
position="inside"> |
|||
<t t-if="journal_type == 'bank'"> |
|||
<a name="action_import_wizard" type="object" |
|||
class="oe_inline" |
|||
groups="account.group_account_invoice">Import |
|||
</a> |
|||
</t> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Sruthi Renjith (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from . import import_bank_statement |
@ -0,0 +1,372 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Sruthi Renjith (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
import base64 |
|||
import codecs |
|||
import os |
|||
import sys |
|||
from datetime import datetime |
|||
from io import BytesIO |
|||
import openpyxl |
|||
from ofxparse import OfxParser |
|||
from qifparse.parser import QifParser |
|||
from odoo import fields, models, _ |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class ImportBankStatement(models.TransientModel): |
|||
""" Class to create a wizard for importing bank statement in csv, xlsx, |
|||
ofx and qif format """ |
|||
_name = "import.bank.statement" |
|||
_description = "Import Button" |
|||
_rec_name = "file_name" |
|||
|
|||
attachment = fields.Binary(string="Attachment File", required=True, |
|||
help="Choose the file to import") |
|||
file_name = fields.Char(string="File Name", help="Name of the file") |
|||
journal_id = fields.Many2one('account.journal', |
|||
string="Journal ID", |
|||
help="Journal id to identify the journal") |
|||
|
|||
def is_valid_date_format(self, date_string, accepted_formats): |
|||
""" Function to check the date is a valid date """ |
|||
for date_format in accepted_formats: |
|||
try: |
|||
datetime.strptime(date_string, date_format) |
|||
return True |
|||
except ValueError: |
|||
pass |
|||
return False |
|||
|
|||
def action_import(self): |
|||
""" Function to import csv, xlsx, ofx and qif file format """ |
|||
accepted_date_formats = ["%Y-%m-%d", "%y-%m-%d", "%d/%m/%Y", |
|||
"%d/%m/%y"] |
|||
split_tup = os.path.splitext(self.file_name) |
|||
if (split_tup[1] == '.csv' or split_tup[1] == '.xlsx' or |
|||
split_tup[1] == '.ofx' or split_tup[1] == '.qif'): |
|||
if split_tup[1] == '.csv': |
|||
# Reading csv file |
|||
try: |
|||
file = base64.b64decode(self.attachment) |
|||
file_string = file.decode('utf-8') |
|||
file_string = file_string.split('\n') |
|||
except Exception: |
|||
raise ValidationError(_("Choose correct file")) |
|||
# Skipping the first line |
|||
firstline = True |
|||
for file_item in file_string: |
|||
if firstline: |
|||
firstline = False |
|||
continue |
|||
# Reading the content from csv file |
|||
if file_item.split(',') != ['']: |
|||
if (file_item.split(',')[0] and |
|||
file_item.split(',')[1] and |
|||
file_item.split(',')[4]): |
|||
if not file_item.split(',')[3]: |
|||
date_obj = str(fields.date.today()) |
|||
else: |
|||
date_obj = file_item.split(',')[3] |
|||
if not self.is_valid_date_format( |
|||
date_obj, accepted_date_formats): |
|||
raise ValidationError( |
|||
_("Date format should be in " |
|||
"%Y-%m-%d or %y-%m-%d or %d/%m/%Y or" |
|||
" %d/%m/%y format")) |
|||
transaction_date = datetime.strptime( |
|||
date_obj, "%Y-%m-%d") |
|||
partner = self.env['res.partner'].search( |
|||
[('name', '=', file_item.split(',')[4])]) |
|||
# Creating a record in account.bank.statement model |
|||
statement_amount = file_item.split(',')[1] |
|||
statement_amount = statement_amount.replace('.', |
|||
'') |
|||
if not statement_amount.isdigit(): |
|||
raise ValidationError( |
|||
_("Amount should be integer")) |
|||
if partner: |
|||
statement = self.env[ |
|||
'account.bank.statement'].create({ |
|||
'name': file_item.split(',')[0], |
|||
'line_ids': [ |
|||
(0, 0, { |
|||
'date': transaction_date, |
|||
'payment_ref': 'csv file', |
|||
'partner_id': partner.id, |
|||
'journal_id': |
|||
self.journal_id.id, |
|||
'amount': |
|||
file_item.split(',')[1], |
|||
'amount_currency': |
|||
file_item.split(',')[2], |
|||
}), |
|||
], |
|||
}) |
|||
else: |
|||
raise ValidationError(_("Partner not exist")) |
|||
else: |
|||
raise ValidationError( |
|||
_("Mandatory field is not set")) |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': 'Statements', |
|||
'view_mode': 'tree', |
|||
'res_model': 'account.bank.statement', |
|||
'res_id': statement.id, |
|||
} |
|||
elif split_tup[1] == '.xlsx': |
|||
# Reading xlsx file |
|||
try: |
|||
order = openpyxl.load_workbook( |
|||
filename=BytesIO(base64.b64decode(self.attachment))) |
|||
xl_order = order.active |
|||
except Exception: |
|||
raise ValidationError(_("Choose correct file")) |
|||
for record in xl_order.iter_rows(min_row=2, max_row=None, |
|||
min_col=None, |
|||
max_col=None, |
|||
values_only=True): |
|||
line = list(record) |
|||
# Reading the content from file |
|||
if line[0] and line[1] and line[3]: |
|||
partner = self.env['res.partner'].search( |
|||
[('name', '=', line[3])]) |
|||
if not line[2]: |
|||
date_obj = fields.date.today() |
|||
elif type(line[2]) == str: |
|||
raise ValidationError( |
|||
_("Date format should be in" |
|||
" %Y-%m-%d or %y-%m-%d or %d/%m/%Y or " |
|||
"%d/%m/%y format")) |
|||
else: |
|||
date_obj = line[2].date() |
|||
if not self.is_valid_date_format( |
|||
str(date_obj), accepted_date_formats): |
|||
raise ValidationError( |
|||
_("Date format should be in " |
|||
"%Y-%m-%d or %y-%m-%d or " |
|||
"%d/%m/%Y or %d/%m/%y format")) |
|||
statement_amount = str(line[1]) |
|||
statement_amount = statement_amount.replace('.', '') |
|||
if not statement_amount.isdigit(): |
|||
raise ValidationError( |
|||
_("Amount should be integer")) |
|||
# Creating record |
|||
if partner: |
|||
statement = self.env[ |
|||
'account.bank.statement'].create({ |
|||
'name': line[0], |
|||
'line_ids': [ |
|||
(0, 0, { |
|||
'date': date_obj, |
|||
'payment_ref': 'xlsx file', |
|||
'partner_id': partner.id, |
|||
'journal_id': self.journal_id.id, |
|||
'amount': line[1], |
|||
}), |
|||
], |
|||
}) |
|||
else: |
|||
raise ValidationError(_("Partner not exist")) |
|||
else: |
|||
raise ValidationError(_("Mandatory field is not set")) |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': 'Statements', |
|||
'view_mode': 'tree', |
|||
'res_model': 'account.bank.statement', |
|||
'res_id': statement.id, |
|||
} |
|||
elif split_tup[1] == '.ofx': |
|||
# Searching the path of the file |
|||
file_attachment = self.env["ir.attachment"].search( |
|||
['|', ('res_field', '!=', False), |
|||
('res_field', '=', False), |
|||
('res_id', '=', self.id), |
|||
('res_model', '=', 'import.bank.statement')], |
|||
limit=1) |
|||
file_path = file_attachment._full_path( |
|||
file_attachment.store_fname) |
|||
# Parsing the file |
|||
try: |
|||
with codecs.open(file_path) as fileobj: |
|||
ofx_file = OfxParser.parse(fileobj) |
|||
except Exception: |
|||
raise ValidationError(_("Wrong file format")) |
|||
sys.exit() |
|||
if not ofx_file.account: |
|||
raise ValidationError( |
|||
_("No account information found in OFX file.")) |
|||
sys.exit() |
|||
if not ofx_file.account.statement: |
|||
raise ValidationError( |
|||
_("No statement information found in OFX file.")) |
|||
sys.exit() |
|||
statement_list = [] |
|||
# Reading the content from file |
|||
for transaction in ofx_file.account.statement.transactions: |
|||
if transaction.type == "debit" and transaction.amount != 0: |
|||
payee = transaction.payee |
|||
amount = transaction.amount |
|||
date = transaction.date |
|||
if not date: |
|||
date = fields.date.today() |
|||
else: |
|||
date = date.strftime("%Y-%m-%d") |
|||
if not self.is_valid_date_format( |
|||
str(date), accepted_date_formats): |
|||
raise ValidationError( |
|||
_("Date format should be in " |
|||
"%Y-%m-%d or %y-%m-%d or %d/%m/%Y or " |
|||
"%d/%m/%y format")) |
|||
partner = self.env['res.partner'].search( |
|||
[('name', '=', payee)]) |
|||
if partner: |
|||
statement_list.append([partner.id, amount, date]) |
|||
else: |
|||
raise ValidationError(_("Partner not exist")) |
|||
if (transaction.type == "credit" and |
|||
transaction.amount != 0): |
|||
payee = transaction.payee |
|||
amount = transaction.amount |
|||
date = transaction.date |
|||
if not date: |
|||
date = fields.date.today() |
|||
else: |
|||
date = date.strftime("%Y-%m-%d") |
|||
if not self.is_valid_date_format( |
|||
str(date), accepted_date_formats): |
|||
raise ValidationError( |
|||
_("Date format should be in " |
|||
"%Y-%m-%d or %y-%m-%d or " |
|||
"%d/%m/%Y or %d/%m/%y format")) |
|||
partner = self.env['res.partner'].search( |
|||
[('name', '=', payee)]) |
|||
if partner: |
|||
statement_list.append([partner.id, amount, date]) |
|||
else: |
|||
raise ValidationError(_("Partner not exist")) |
|||
# Creating record |
|||
if statement_list: |
|||
for item in statement_list: |
|||
statement_amount = str(abs(item[1])) |
|||
statement_amount = statement_amount.replace('.', '') |
|||
if not statement_amount.isdigit(): |
|||
raise ValidationError( |
|||
_("Amount should be integer")) |
|||
statement = self.env['account.bank.statement'].create({ |
|||
'name': ofx_file.account.routing_number, |
|||
'line_ids': [ |
|||
(0, 0, { |
|||
'date': item[2], |
|||
'payment_ref': 'ofx file', |
|||
'partner_id': item[0], |
|||
'journal_id': self.journal_id.id, |
|||
'amount': item[1], |
|||
}), |
|||
], |
|||
}) |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': 'Statements', |
|||
'view_mode': 'tree', |
|||
'res_model': 'account.bank.statement', |
|||
'res_id': statement.id, |
|||
} |
|||
else: |
|||
raise ValidationError(_("There is no data to import")) |
|||
elif split_tup[1] == '.qif': |
|||
# Searching the path of qif file |
|||
file_attachment = self.env["ir.attachment"].search( |
|||
['|', ('res_field', '!=', False), |
|||
('res_field', '=', False), |
|||
('res_id', '=', self.id), |
|||
('res_model', '=', 'import.bank.statement')], |
|||
limit=1) |
|||
file_path = file_attachment._full_path( |
|||
file_attachment.store_fname) |
|||
# Parsing the qif file |
|||
try: |
|||
parser = QifParser() |
|||
with open(file_path, 'r') as qiffile: |
|||
qif = parser.parse(qiffile) |
|||
except Exception: |
|||
raise ValidationError(_("Wrong file format")) |
|||
sys.exit() |
|||
file_string = str(qif) |
|||
file_item = file_string.split('^') |
|||
file_item[-1] = file_item[-1].rstrip('\n') |
|||
if file_item[-1] == '': |
|||
file_item.pop() |
|||
statement_list = [] |
|||
for item in file_item: |
|||
if not item.startswith('!Type:Bank'): |
|||
item = '!Type:Bank' + item |
|||
data = item.split('\n') |
|||
# Reading the file content |
|||
date_entry = data[1][1:] |
|||
amount = float(data[2][1:]) |
|||
payee = data[3][1:] |
|||
if amount and payee: |
|||
if not date_entry: |
|||
date_entry = str(fields.date.today()) |
|||
else: |
|||
if not self.is_valid_date_format( |
|||
date_entry, accepted_date_formats): |
|||
raise ValidationError( |
|||
_("Date format should be in" |
|||
"%Y-%m-%d or %y-%m-%d or " |
|||
"%d/%m/%Y or %d/%m/%y format")) |
|||
date_object = datetime.strptime(date_entry, |
|||
'%d/%m/%Y') |
|||
date = date_object.strftime('%Y-%m-%d') |
|||
statement_list.append([payee, amount, date]) |
|||
else: |
|||
raise ValidationError(_("Mandatory field is not set")) |
|||
# Creating record |
|||
if statement_list: |
|||
for item in statement_list: |
|||
statement_amount = str(abs(item[1])) |
|||
statement_amount = statement_amount.replace('.', '') |
|||
if not statement_amount.isdigit(): |
|||
raise ValidationError( |
|||
_("Amount should be integer")) |
|||
statement = self.env['account.bank.statement'].create({ |
|||
'name': item[0], |
|||
'line_ids': [ |
|||
(0, 0, { |
|||
'date': item[2], |
|||
'payment_ref': 'qif file', |
|||
'journal_id': self.journal_id.id, |
|||
'amount': item[1], |
|||
}), |
|||
], |
|||
}) |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': 'Statements', |
|||
'view_mode': 'tree', |
|||
'res_model': 'account.bank.statement', |
|||
'res_id': statement.id, |
|||
} |
|||
else: |
|||
raise ValidationError(_("Choose correct file")) |
@ -0,0 +1,43 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Wizard view to upload files --> |
|||
<record id="import_bank_statement_view_form" model="ir.ui.view"> |
|||
<field name="name">import.bank.statement.view.form</field> |
|||
<field name="model">import.bank.statement</field> |
|||
<field name="arch" type="xml"> |
|||
<form> |
|||
<sheet> |
|||
<p> |
|||
<center> |
|||
<i>Upload csv or xlsx or ofx or qif file format</i> |
|||
</center> |
|||
</p> |
|||
<group> |
|||
<group> |
|||
<field name="attachment" filename="file_name"/> |
|||
<field name="file_name" invisible="1"/> |
|||
<field name="journal_id" invisible="1"/> |
|||
</group> |
|||
</group> |
|||
<footer> |
|||
<button name="action_import" class="oe_highlight" |
|||
string="IMPORT" type="object" |
|||
help="Import bank statement in CSV or XLSX format"/> |
|||
<button special="cancel" |
|||
string="CANCEL" help="Cancel the process"/> |
|||
</footer> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
<!-- Wizard action record --> |
|||
<record id="import_bank_statement_action" |
|||
model="ir.actions.act_window"> |
|||
<field name="name">Bank Statement</field> |
|||
<field name="type">ir.actions.act_window</field> |
|||
<field name="res_model">import.bank.statement</field> |
|||
<field name="view_mode">form</field> |
|||
<field name="view_id" ref="import_bank_statement_view_form"/> |
|||
<field name="target">new</field> |
|||
</record> |
|||
</odoo> |