@ -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> |