You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							336 lines
						
					
					
						
							16 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							336 lines
						
					
					
						
							16 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ############################################################################### | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |
| #    Author: Akhil Ashok (odoo@cybrosys.com) | |
| # | |
| #    You can modify it under the terms of the GNU LESSER | |
| #    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | |
| # | |
| #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | |
| #    (LGPL v3) along with this program. | |
| #    If not, see <http://www.gnu.org/licenses/>. | |
| # | |
| ############################################################################### | |
| import base64 | |
| import codecs | |
| import openpyxl | |
| import os | |
| from datetime import datetime | |
| from io import BytesIO | |
| from odoo import fields, models, _ | |
| from odoo.exceptions import ValidationError | |
| from ofxparse import OfxParser | |
| from qifparse.parser import QifParser | |
| 
 | |
| 
 | |
| class ImportBankStatement(models.TransientModel): | |
|     """ A class to import files as bank statement """ | |
|     _name = "import.bank.statement" | |
|     _description = "Import button" | |
|     _rec_name = "file_name" | |
| 
 | |
|     attachment = fields.Binary(string="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 in which the file importing") | |
| 
 | |
|     def action_statement_import(self): | |
|         """Function to import csv, xlsx, ofx and qif file format""" | |
|         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: | |
|                     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]: | |
|                             date_obj = str(fields.date.today()) if not \ | |
|                                 file_item.split(',')[3] else \ | |
|                                 file_item.split(',')[ | |
|                                     3] | |
|                             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 | |
|                             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: | |
|                             if not file_item.split(',')[0]: | |
|                                 raise ValidationError( | |
|                                     _("Account name is not set")) | |
|                             elif not file_item.split(',')[1]: | |
|                                 raise ValidationError( | |
|                                     _("Amount is not set")) | |
|                             elif not file_item.split(',')[4]: | |
|                                 date_obj = str(fields.date.today()) if not \ | |
|                                     file_item.split(',')[3] else \ | |
|                                     file_item.split(',')[ | |
|                                         3] | |
|                                 transaction_date = datetime.strptime(date_obj, | |
|                                                                      "%Y-%m-%d") | |
|                                 # Creating a record in account.bank.statement model | |
|                                 statement = self.env[ | |
|                                     'account.bank.statement'].create({ | |
|                                     'name': file_item.split(',')[0], | |
|                                     'line_ids': [ | |
|                                         (0, 0, { | |
|                                             'date': transaction_date, | |
|                                             'payment_ref': 'csv file', | |
|                                             'journal_id': self.journal_id.id, | |
|                                             'amount': file_item.split(',')[ | |
|                                                 1], | |
|                                             'amount_currency': | |
|                                                 file_item.split(',')[2], | |
|                                         }), | |
|                                     ], | |
|                                 }) | |
|                 return { | |
|                     'type': 'ir.actions.act_window', | |
|                     'name': 'Statements', | |
|                     'view_mode': 'list', | |
|                     '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: | |
|                     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])]) | |
|                         date_obj = fields.date.today() if not line[2] else \ | |
|                             line[2].date() | |
|                         # 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: | |
|                         if not line[0]: | |
|                             raise ValidationError( | |
|                                 _("Account name is not set")) | |
|                         elif not line[1]: | |
|                             raise ValidationError( | |
|                                 _("Amount is not set")) | |
|                         elif not line[3]: | |
|                             date_obj = fields.date.today() if not line[2] else \ | |
|                                 line[2].date() | |
|                             # Creating record | |
|                             statement = self.env[ | |
|                                 'account.bank.statement'].create({ | |
|                                 'name': line[0], | |
|                                 'line_ids': [ | |
|                                     (0, 0, { | |
|                                         'date': date_obj, | |
|                                         'payment_ref': 'xlsx file', | |
|                                         'journal_id': self.journal_id.id, | |
|                                         'amount': line[1], | |
|                                     }), | |
|                                 ], | |
|                             }) | |
|                 return { | |
|                     'type': 'ir.actions.act_window', | |
|                     'name': 'Statements', | |
|                     'view_mode': 'list', | |
|                     '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: | |
|                     raise ValidationError(_("Wrong file format")) | |
|                 if not ofx_file.account: | |
|                     raise ValidationError( | |
|                         _("No account information found in OFX file.")) | |
|                 if not ofx_file.account.statement: | |
|                     raise ValidationError( | |
|                         _("No statement information found in OFX file.")) | |
|                 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() | |
|                         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() | |
|                         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 = 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': 'list', | |
|                         '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: | |
|                     raise ValidationError(_("Wrong file format")) | |
|                 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()) | |
|                         date_object = datetime.strptime(date_entry, '%d/%m/%Y') | |
|                         date = date_object.strftime('%Y-%m-%d') | |
|                         statement_list.append([payee, amount, date]) | |
|                     else: | |
|                         if not amount: | |
|                             raise ValidationError(_("Amount is not set")) | |
|                         elif not payee: | |
|                             raise ValidationError(_("Payee is not set")) | |
|                 # Creating record | |
|                 if statement_list: | |
|                     for item in statement_list: | |
|                         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': 'list', | |
|                         'res_model': 'account.bank.statement', | |
|                         'res_id': statement.id, | |
|                     } | |
|         else: | |
|             raise ValidationError(_("Choose correct file"))
 | |
| 
 |