import base64 import tempfile import hashlib import json import math import os from datetime import datetime, timedelta from odoo import models, fields, api, _ from tbc_bank_integration_service_lib.client import TBCBankClient from odoo.exceptions import UserError BANKS = { "NB": {"name": "National Bank of Georgia", "code": "BNLNGE22"}, "TR": {"name": "State Treasury", "code": "TRESGE22"}, "BG": {"name": 'JSC "Bank of Georgia"', "code": "BAGAGE22"}, "BS": {"name": 'JSC "BasisBank"', "code": "CBASGE22"}, "BT": {"name": 'JSC "Silk Bank"', "code": "DISNGE22"}, "CR": {"name": 'JSC "Cartu Bank"', "code": "CRTUGE22"}, "HB": {"name": 'JSC "Halyk Bank Georgia"', "code": "HABGGE22"}, "KS": {"name": 'JSC "Terabank"', "code": "TEBAGE22"}, "LB": {"name": 'JSC "Liberty Bank"', "code": "LBRTGE22"}, "PC": {"name": 'JSC "ProCredit Bank"', "code": "MIBGGE22"}, "TB": {"name": 'JSC "TBC Bank"', "code": "TBCBGE22"}, "VT": {"name": 'JSC "VTB Bank Georgia "', "code": "UGEBGE22"}, "ZB": {"name": 'JSC "Ziraat Bank Georgia"', "code": "TCZBGE22"}, "PB": {"name": 'JSC “Pasha Bank Georgia”', "code": "PAHAGE22"}, "IS": {"name": 'JSC "Isbank Georgia"', "code": "ISBKGE22"}, "CD": {"name": 'JSC "Credo Bank"', "code": "JSCRGE22"}, "PS": {"name": 'JSC "Paysera Bank Georgia"', "code": "PSRAGE22"}, "HS": {"name": 'JSC "HASH Bank"', "code": "HAJSGE22"}, "PV": {"name": 'JSC "Pave Bank Georgia"', "code": "PAVEGE22"}, } class BankMovements(models.Model): _name = 'bank.raw.movements' _description = 'Bank Movements' json_data = fields.Json(string="Json Data") json_hash_code = fields.Char(string="Hash Code") bid = fields.Char(string="Movement Id") parent_id = fields.Many2one('bank.raw.movements', string="Parent Record") history_ids = fields.One2many(comodel_name="bank.raw.movements", inverse_name='parent_id', string="History") def create_or_update_raw_data(self, data, model, bid): json_data = json.dumps(data, sort_keys=True, indent=4, ensure_ascii=False) hash_object = hashlib.sha256(json_data.encode()) hash_hex = hash_object.hexdigest() find_records = self.env[model].search([('bid', '=', bid)]) if len(find_records) > 1: found_raw_record = find_records.sorted(key=lambda x: x.id, reverse=True)[0] else: found_raw_record = find_records if found_raw_record: if found_raw_record.json_hash_code != hash_hex: # found_raw_record.write({ # 'json_data': json_data, # 'json_hash_code': hash_hex # }) new_created_record = self.env[model].create({ 'json_data': json_data, 'json_hash_code': hash_hex, 'bid': bid, }) for record in find_records: record.parent_id = new_created_record.id else: self.env[model].create({ 'json_data': json_data, 'json_hash_code': hash_hex, 'bid': bid }) def get_movements(self): client = self.env['bank.settings'].get_request_object() found_record = self.env['bank.raw.movements'].search([]) if found_record: latest_record = self.env['bank.raw.movements'].search([], order='write_date desc', limit=1) max_write_date = latest_record.write_date max_modified_id = latest_record.id max_id_to_process = max_modified_id if found_record else 0 start_date = max_write_date.strftime('%Y-%m-%dT00:00:00.000') if found_record else '2024-01-01T00:00:00.000' end_date = datetime.now().strftime('%Y-%m-%dT00:00:00.000') res = client.get_account_movements_by_date_range('111111', start_date, end_date) if not res['data']: raise UserError(_('No data found for movements')) for movement in res['data']['movements']: self.create_or_update_raw_data(movement, 'bank.raw.movements', movement['movementId']) pages = math.ceil(int(res['data']['pager']['totalcount']) / int(res['data']['pager']['pagesize'])) if pages > 1: for page in range(1, pages): res = client.get_account_movements_by_date_range_next_page('111111', page, 700, start_date, end_date) for movement in res['data']['movements']: self.create_or_update_raw_data(movement, 'bank.raw.movements', movement['movementId']) self.process_movements(max_id_to_process) def process_movements(self, to_process_from_id): to_process_movements = self.env['bank.raw.movements'].search([('id', '>', to_process_from_id)]) for rec in to_process_movements: movement = json.loads(rec.json_data) movement_id = movement['movementId'] external_payment_id = movement['externalPaymentId'] debit_credit = movement['debitCredit'] value_date = movement['valueDate'] description = movement['description'] amount = movement['amount']['amount'] currency = movement['amount']['currency'] account_number = movement['accountNumber'] account_name = movement['accountName'] comment = movement['additionalInformation'] document_date = movement['documentDate'] document_number = movement['documentNumber'] partner_name = movement['partnerName'] partner_tax_code = movement['partnerTaxCode'] taxpayer_code = movement['taxpayerCode'] taxpayer_name = movement['taxpayerName'] operation_code = movement['operationCode'] exchange_rate_text = movement['exchangeRate'] partner_personal_number = movement['partnerPersonalNumber'] partner_document_type = movement['partnerDocumentType'] partner_document_number = movement['partnerDocumentNumber'] parent_external_payment_id = movement['parentExternalPaymentId'] status_code = movement['statusCode'] transaction_type = movement['transactionType'] iban_code = account_number[4:6] if movement['debitCredit'] == '0': amount = float(amount) * -1 currency_id = self.env['res.currency'].search([('name', '=', currency)]) found_bank = self.env['brosse.bank'].search([('iban_code', '=', iban_code)]) if found_bank: bank_id = found_bank.id else: bank_id = self.env['brosse.bank'].create({ 'name': BANKS[iban_code]['name'], 'bank_code': BANKS[iban_code]['code'], 'iban_code': iban_code }).id found_bank_account = self.env['brosse.bank.account'].search([ ('account_number', '=', account_number), ('currency_id', '=', currency_id.id)]) if found_bank_account: bank_account_id = found_bank_account.id else: bank_account_id = self.env['brosse.bank.account'].create({ 'bank_ids': [(4, bank_id)], 'holder_name': account_name, 'currency_id': currency_id.id, 'account_number': account_number, }).id self.env['brosse.bank.transactions'].create({ 'bank_account_id': bank_account_id, 'amount': amount, 'currency_id': currency_id.id, 'exchange_rate_text': exchange_rate_text, 'description': description, 'comment': comment, 'partner_name': partner_name, 'taxpayer_name': taxpayer_name, 'movement_id': movement_id, 'external_payment_id': external_payment_id, 'debit_credit': debit_credit, 'value_date': datetime.strptime(value_date, "%Y-%m-%dT%H:%M:%S") - timedelta(hours=4), 'document_date': datetime.strptime(document_date, "%Y-%m-%dT%H:%M:%S") - timedelta(hours=4), 'document_number': document_number, 'partner_tax_code': partner_tax_code, 'taxpayer_code': taxpayer_code, 'operation_code': operation_code, 'partner_personal_number': partner_personal_number, 'partner_document_type': partner_document_type, 'partner_document_number': partner_document_number, 'parent_external_payment_id': parent_external_payment_id, 'status_code_id': self.env['brosse.bank.transactions.status.code'].search([('code', '=', status_code)]).id, 'transaction_type_id': self.env['brosse.bank.transactions.subtype.code'].search([('code', '=', transaction_type)]).id, 'account_number': account_number, 'account_name': account_name }) # movement_id = '013762510743.2' # movements_by_id = client.get_account_movements_by_id('111111', movement_id) # self.create_or_update_raw_data(movements_by_id, 'bank.raw.movements', movements_by_id['data'].get('movementId'))