1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/account_bank_statement_import_camt/lib/camt.py
2024-12-10 09:04:09 +07:00

802 lines
38 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import math
import re
from functools import partial
from odoo import _lt
from odoo.exceptions import ValidationError
from odoo.tools import float_compare
# Codes from the updated document of 30 june 2017
# pylint: disable=duplicate-key
codes = {
# ExternalBankTransactionDomain1Code #######################################
'PMNT': _lt('Payments'),
'CAMT': _lt('Cash Management'),
'DERV': _lt('Derivatives'),
'LDAS': _lt('Loans, Deposits & Syndications'),
'FORX': _lt('Foreign Exchange'),
'PMET': _lt('Precious Metal'),
'CMDT': _lt('Commodities'),
'TRAD': _lt('Trade Services'),
'SECU': _lt('Securities'),
'ACMT': _lt('Account Management'),
'XTND': _lt('Extended Domain'),
# ExternalBankTransactionFamily1Code #######################################
'RCDT': _lt('Received Credit Transfers'), # Payments
'ICDT': _lt('Issued Credit Transfers'),
'RCCN': _lt('Received Cash Concentration Transactions'),
'ICCN': _lt('Issued Cash Concentration Transactions'),
'RDDT': _lt('Received Direct Debits'),
'IDDT': _lt('Issued Direct Debits'),
'RCHQ': _lt('Received Cheques'),
'ICHQ': _lt('Issued Cheques'),
'CCRD': _lt('Customer Card Transactions'),
'MCRD': _lt('Merchant Card Transactions'),
'LBOX': _lt('Lockbox Transactions'),
'CNTR': _lt('Counter Transactions'),
'DRFT': _lt('Drafts/BillOfOrders'),
'RRCT': _lt('Received Real Time Credit Transfer'),
'IRCT': _lt('Issued Real Time Credit Transfer'),
'CAPL': _lt('Cash Pooling'), # Cash Management
'ACCB': _lt('Account Balancing'),
'OCRD': _lt('OTC Derivatives Credit Derivatives'), # Derivatives
'OIRT': _lt('OTC Derivatives Interest Rates'),
'OEQT': _lt('OTC Derivatives Equity'),
'OBND': _lt('OTC Derivatives Bonds'),
'OSED': _lt('OTC Derivatives Structured Exotic Derivatives'),
'OSWP': _lt('OTC Derivatives Swaps'),
'LFUT': _lt('Listed Derivatives Futures'),
'LOPT': _lt('Listed Derivatives Options'),
'FTLN': _lt('Fixed Term Loans'), # Loans, Deposits & Syndications
'NTLN': _lt('Notice Loans'),
'FTDP': _lt('Fixed Term Deposits'),
'NTDP': _lt('Notice Deposits'),
'MGLN': _lt('Mortgage Loans'),
'CSLN': _lt('Consumer Loans'),
'SYDN': _lt('Syndications'),
'SPOT': _lt('Spots'), # Foreign Exchange
'FWRD': _lt('Forwards'),
'SWAP': _lt('Swaps'),
'FTUR': _lt('Futures'),
'NDFX': _lt('Non Deliverable'),
'SPOT': _lt('Spots'), # Precious Metal
'FTUR': _lt('Futures'),
'OPTN': _lt('Options'),
'DLVR': _lt('Delivery'),
'SPOT': _lt('Spots'), # Commodities
'FTUR': _lt('Futures'),
'OPTN': _lt('Options'),
'DLVR': _lt('Delivery'),
'LOCT': _lt('Stand-By Letter Of Credit'), # Trade Services
'DCCT': _lt('Documentary Credit'),
'CLNC': _lt('Clean Collection'),
'DOCC': _lt('Documentary Collection'),
'GUAR': _lt('Guarantees'),
'SETT': _lt('Trade, Clearing and Settlement'), # Securities
'NSET': _lt('Non Settled'),
'BLOC': _lt('Blocked Transactions'),
'OTHB': _lt('CSD Blocked Transactions'),
'COLL': _lt('Collateral Management'),
'CORP': _lt('Corporate Action'),
'CUST': _lt('Custody'),
'COLC': _lt('Custody Collection'),
'LACK': _lt('Lack'),
'CASH': _lt('Miscellaneous Securities Operations'),
'OPCL': _lt('Opening & Closing'), # Account Management
'ACOP': _lt('Additional Miscellaneous Credit Operations'),
'ADOP': _lt('Additional Miscellaneous Debit Operations'),
# ExternalBankTransactionSubFamily1Code ####################################
# Generic Sub-Families
'FEES': _lt('Fees'), # Miscellaneous Credit Operations
'COMM': _lt('Commission'),
'COME': _lt('Commission excluding taxes'),
'COMI': _lt('Commission including taxes'),
'COMT': _lt('Non Taxable commissions'),
'TAXE': _lt('Taxes'),
'CHRG': _lt('Charges'),
'INTR': _lt('Interest'),
'RIMB': _lt('Reimbursements'),
'ADJT': _lt('Adjustments'),
'FEES': _lt('Fees'), # Miscellaneous Debit Operations
'COMM': _lt('Commission'),
'COME': _lt('Commission excluding taxes'),
'COMI': _lt('Commission including taxes'),
'COMT': _lt('Non Taxable commissions'),
'TAXE': _lt('Taxes'),
'CHRG': _lt('Charges'),
'INTR': _lt('Interest'),
'RIMB': _lt('Reimbursements'),
'ADJT': _lt('Adjustments'),
'IADD': _lt('Invoice Accepted with Differed Due Date'),
'FEES': _lt('Fees'), # Generic Sub-Families
'COMM': _lt('Commission'),
'COME': _lt('Commission excluding taxes'),
'COMI': _lt('Commission including taxes'),
'COMT': _lt('Non Taxable commissions'),
'TAXE': _lt('Taxes'),
'CHRG': _lt('Charges'),
'INTR': _lt('Interest'),
'RIMB': _lt('Reimbursements'),
'DAJT': _lt('Credit Adjustments'),
'CAJT': _lt('Debit Adjustments'),
# Payments Sub-Families
'BOOK': _lt('Internal Book Transfer'), # Received Credit Transfer
'STDO': _lt('Standing Order'),
'XBST': _lt('Cross-Border Standing Order'),
'ESCT': _lt('SEPA Credit Transfer'),
'DMCT': _lt('Domestic Credit Transfer'),
'XBCT': _lt('Cross-Border Credit Transfer'),
'VCOM': _lt('Credit Transfer with agreed Commercial Information'),
'FICT': _lt('Financial Institution Credit Transfer'),
'PRCT': _lt('Priority Credit Transfer'),
'SALA': _lt('Payroll/Salary Payment'),
'XBSA': _lt('Cross-Border Payroll/Salary Payment'),
'SDVA': _lt('Same Day Value Credit Transfer'),
'RPCR': _lt('Reversal due to Payment Cancellation Request'),
'RRTN': _lt('Reversal due to Payment Return/reimbursement of a Credit Transfer'),
'AUTT': _lt('Automatic Transfer'),
'ATXN': _lt('ACH Transaction'),
'ACOR': _lt('ACH Corporate Trade'),
'APAC': _lt('ACH Pre-Authorised'),
'ASET': _lt('ACH Settlement'),
'ARET': _lt('ACH Return'),
'AREV': _lt('ACH Reversal'),
'ACDT': _lt('ACH Credit'),
'ADBT': _lt('ACH Debit'),
'TTLS': _lt('Treasury Tax And Loan Service'),
'BOOK': _lt('Internal Book Transfer'), # Issued Credit Transfer
'STDO': _lt('Standing Order'),
'XBST': _lt('Cross-Border Standing Order'),
'ESCT': _lt('SEPA Credit Transfer'),
'DMCT': _lt('Domestic Credit Transfer'),
'XBCT': _lt('Cross-Border Credit Transfer'),
'FICT': _lt('Financial Institution Credit Transfer'),
'PRCT': _lt('Priority Credit Transfer'),
'VCOM': _lt('Credit Transfer with agreed Commercial Information'),
'SALA': _lt('Payroll/Salary Payment'),
'XBSA': _lt('Cross-Border Payroll/Salary Payment'),
'RPCR': _lt('Reversal due to Payment Cancellation Request'),
'RRTN': _lt('Reversal due to Payment Return/reimbursement of a Credit Transfer'),
'SDVA': _lt('Same Day Value Credit Transfer'),
'AUTT': _lt('Automatic Transfer'),
'ATXN': _lt('ACH Transaction'),
'ACOR': _lt('ACH Corporate Trade'),
'APAC': _lt('ACH Pre-Authorised'),
'ASET': _lt('ACH Settlement'),
'ARET': _lt('ACH Return'),
'AREV': _lt('ACH Reversal'),
'ACDT': _lt('ACH Credit'),
'ADBT': _lt('ACH Debit'),
'TTLS': _lt('Treasury Tax And Loan Service'),
'COAT': _lt('Corporate Own Account Transfer'), # Received Cash Concentration
'ICCT': _lt('Intra Company Transfer'),
'XICT': _lt('Cross-Border Intra Company Transfer'),
'FIOA': _lt('Financial Institution Own Account Transfer'),
'BACT': _lt('Branch Account Transfer'),
'ACON': _lt('ACH Concentration'),
'COAT': _lt('Corporate Own Account Transfer'), # Issued Cash Concentration
'ICCT': _lt('Intra Company Transfer'),
'XICT': _lt('Cross-Border Intra Company Transfer'),
'FIOA': _lt('Financial Institution Own Account Transfer'),
'BACT': _lt('Branch Account Transfer'),
'ACON': _lt('ACH Concentration'),
'PMDD': _lt('Direct Debit'), # Received Direct Debit
'URDD': _lt('Direct Debit under reserve'),
'ESDD': _lt('SEPA Core Direct Debit'),
'BBDD': _lt('SEPA B2B Direct Debit'),
'XBDD': _lt('Cross-Border Direct Debit'),
'OODD': _lt('One-Off Direct Debit'),
'PADD': _lt('Pre-Authorised Direct Debit'),
'FIDD': _lt('Financial Institution Direct Debit Payment'),
'RCDD': _lt('Reversal due to a Payment Cancellation Request'),
'UPDD': _lt('Reversal due to Return/Unpaid Direct Debit'),
'PRDD': _lt('Reversal due to Payment Reversal'),
'PMDD': _lt('Direct Debit Payment'), # Issued Direct Debit
'URDD': _lt('Direct Debit under reserve'),
'ESDD': _lt('SEPA Core Direct Debit'),
'BBDD': _lt('SEPA B2B Direct Debit'),
'OODD': _lt('One-Off Direct Debit'),
'XBDD': _lt('Cross-Border Direct Debit'),
'PADD': _lt('Pre-Authorised Direct Debit'),
'FIDD': _lt('Financial Institution Direct Debit Payment'),
'RCDD': _lt('Reversal due to a Payment Cancellation Request'),
'UPDD': _lt('Reversal due to Return/Unpaid Direct Debit'),
'PRDD': _lt('Reversal due to Payment Reversal'),
'CCHQ': _lt('Cheque'), # Received Cheque
'URCQ': _lt('Cheque Under Reserve'),
'UPCQ': _lt('Unpaid Cheque'),
'CQRV': _lt('Cheque Reversal'),
'CCCH': _lt('Certified Customer Cheque'),
'CLCQ': _lt('Circular Cheque'),
'NPCC': _lt('Non-Presented Circular Cheque'),
'CRCQ': _lt('Crossed Cheque'),
'ORCQ': _lt('Order Cheque'),
'OPCQ': _lt('Open Cheque'),
'BCHQ': _lt('Bank Cheque'),
'XBCQ': _lt('Foreign Cheque'),
'XRCQ': _lt('Foreign Cheque Under Reserve'),
'XPCQ': _lt('Unpaid Foreign Cheque'),
'CDIS': _lt('Controlled Disbursement'),
'ARPD': _lt('ARP Debit'),
'CASH': _lt('Cash Letter'),
'CSHA': _lt('Cash Letter Adjustment'),
'CCHQ': _lt('Cheque'), # Issued Cheque
'URCQ': _lt('Cheque Under Reserve'),
'UPCQ': _lt('Unpaid Cheque'),
'CQRV': _lt('Cheque Reversal'),
'CCCH': _lt('Certified Customer Cheque'),
'CLCQ': _lt('Circular Cheque'),
'NPCC': _lt('Non-Presented Circular Cheque'),
'CRCQ': _lt('Crossed Cheque'),
'ORCQ': _lt('Order Cheque'),
'OPCQ': _lt('Open Cheque'),
'BCHQ': _lt('Bank Cheque'),
'XBCQ': _lt('Foreign Cheque'),
'XRCQ': _lt('Foreign Cheque Under Reserve'),
'XPCQ': _lt('Unpaid Foreign Cheque'),
'CDIS': _lt('Controlled Disbursement'),
'ARPD': _lt('ARP Debit'),
'CASH': _lt('Cash Letter'),
'CSHA': _lt('Cash Letter Adjustment'),
'CWDL': _lt('Cash Withdrawal'), # Customer Card Transaction
'CDPT': _lt('Cash Deposit'),
'XBCW': _lt('Cross-Border Cash Withdrawal'),
'POSD': _lt('Point-of-Sale (POS) Payment - Debit Card'),
'POSC': _lt('Credit Card Payment'),
'XBCP': _lt('Cross-Border Credit Card Payment'),
'SMRT': _lt('Smart-Card Payment'),
'POSP': _lt('Point-of-Sale (POS) Payment'), # Merchant Card Transaction
'POSC': _lt('Credit Card Payment'),
'SMCD': _lt('Smart-Card Payment'),
'UPCT': _lt('Unpaid Card Transaction'),
'CDPT': _lt('Cash Deposit'), # Counter Transaction
'CWDL': _lt('Cash Withdrawal'),
'BCDP': _lt('Branch Deposit'),
'BCWD': _lt('Branch Withdrawal'),
'CHKD': _lt('Cheque Deposit'),
'MIXD': _lt('Mixed Deposit'),
'MSCD': _lt('Miscellaneous Deposit'),
'FCDP': _lt('Foreign Currency Deposit'),
'FCWD': _lt('Foreign Currency Withdrawal'),
'TCDP': _lt('Travellers Cheques Deposit'),
'TCWD': _lt('Travellers Cheques Withdrawal'),
'LBCA': _lt('Credit Adjustment'), # Lockbox
'LBDB': _lt('Debit'),
'LBDP': _lt('Deposit'),
'STAM': _lt('Settlement at Maturity'), # Drafts / Bill to Order
'STLR': _lt('Settlement under reserve'),
'DDFT': _lt('Discounted Draft'),
'UDFT': _lt('Dishonoured/Unpaid Draft'),
'DMCG': _lt('Draft Maturity Change'),
'BOOK': _lt('Internal Book Transfer'), # Received Real-Time Credit Transfer
'STDO': _lt('Standing Order'),
'XBST': _lt('Cross-Border Standing Order'),
'ESCT': _lt('SEPA Credit Transfer'),
'DMCT': _lt('Domestic Credit Transfer'),
'XBCT': _lt('Cross-Border Credit Transfer'),
'VCOM': _lt('Credit Transfer with agreed Commercial Information'),
'FICT': _lt('Financial Institution Credit Transfer'),
'PRCT': _lt('Priority Credit Transfer'),
'SALA': _lt('Payroll/Salary Payment'),
'XBSA': _lt('Cross-Border Payroll/Salary Payment'),
'SDVA': _lt('Same Day Value Credit Transfer'),
'RPCR': _lt('Reversal due to Payment Cancellation Request'),
'RRTN': _lt('Reversal due to Payment Return/reimbursement of a Credit Transfer'),
'AUTT': _lt('Automatic Transfer'),
'ATXN': _lt('ACH Transaction'),
'ACOR': _lt('ACH Corporate Trade'),
'APAC': _lt('ACH Pre-Authorised'),
'ASET': _lt('ACH Settlement'),
'ARET': _lt('ACH Return'),
'AREV': _lt('ACH Reversal'),
'ACDT': _lt('ACH Credit'),
'ADBT': _lt('ACH Debit'),
'TTLS': _lt('Treasury Tax And Loan Service'),
'BOOK': _lt('Internal Book Transfer'), # Issued Real-Time Credit Transfer
'STDO': _lt('Standing Order'),
'XBST': _lt('Cross-Border Standing Order'),
'ESCT': _lt('SEPA Credit Transfer'),
'DMCT': _lt('Domestic Credit Transfer'),
'XBCT': _lt('Cross-Border Credit Transfer'),
'FICT': _lt('Financial Institution Credit Transfer'),
'PRCT': _lt('Priority Credit Transfer'),
'VCOM': _lt('Credit Transfer with agreed Commercial Information'),
'SALA': _lt('Payroll/Salary Payment'),
'XBSA': _lt('Cross-Border Payroll/Salary Payment'),
'RPCR': _lt('Reversal due to Payment Cancellation Request'),
'RRTN': _lt('Reversal due to Payment Return/reimbursement of a Credit Transfer'),
'SDVA': _lt('Same Day Value Credit Transfer'),
'AUTT': _lt('Automatic Transfer'),
'ATXN': _lt('ACH Transaction'),
'ACOR': _lt('ACH Corporate Trade'),
'APAC': _lt('ACH Pre-Authorised'),
'ASET': _lt('ACH Settlement'),
'ARET': _lt('ACH Return'),
'AREV': _lt('ACH Reversal'),
'ACDT': _lt('ACH Credit'),
'ADBT': _lt('ACH Debit'),
'TTLS': _lt('Treasury Tax And Loan Service'),
# Cash Management Sub-Families
'XBRD': _lt('Cross-Border'), # Cash Pooling
'ZABA': _lt('Zero Balancing'), # Account Balancing
'SWEP': _lt('Sweeping'),
'TOPG': _lt('Topping'),
'DSBR': _lt('Controlled Disbursement'),
'ODFT': _lt('Overdraft'),
'XBRD': _lt('Cross-Border'),
# Derivatives Sub-Families
'SWUF': _lt('Upfront Payment'),
'SWRS': _lt('Reset Payment'),
'SWPP': _lt('Partial Payment'),
'SWFP': _lt('Final Payment'),
'SWCC': _lt('Client Owned Collateral'),
# Loans, Deposits & Syndications Sub-Families
'DDWN': _lt('Drawdown'),
'RNEW': _lt('Renewal'),
'PPAY': _lt('Principal Payment'),
'DPST': _lt('Deposit'),
'RPMT': _lt('Repayment'),
# Trade Services Sub-Families
'FRZF': _lt('Freeze of funds'),
'SOSI': _lt('Settlement of Sight Import document'),
'SOSE': _lt('Settlement of Sight Export document'),
'SABG': _lt('Settlement against bank guarantee'),
'STLR': _lt('Settlement under reserve'),
'STLR': _lt('Settlement under reserve'),
'STAC': _lt('Settlement after collection'),
'STLM': _lt('Settlement'),
# Securities Sub-Families
'PAIR': _lt('Pair-Off'), # Trade, Clearing and Settlement & Non Settled
'TRAD': _lt('Trade'),
'NETT': _lt('Netting'),
'TRPO': _lt('Triparty Repo'),
'TRVO': _lt('Triparty Reverse Repo'),
'RVPO': _lt('Reverse Repo'),
'REPU': _lt('Repo'),
'SECB': _lt('Securities Borrowing'),
'SECL': _lt('Securities Lending'),
'BSBO': _lt('Buy Sell Back'),
'BSBC': _lt('Sell Buy Back'),
'FCTA': _lt('Factor Update'),
'ISSU': _lt('Depositary Receipt Issue'),
'INSP': _lt('Inspeci/Share Exchange'),
'OWNE': _lt('External Account Transfer'),
'OWNI': _lt('Internal Account Transfer'),
'NSYN': _lt('Non Syndicated'),
'PLAC': _lt('Placement'),
'PORT': _lt('Portfolio Move'),
'SYND': _lt('Syndicated'),
'TBAC': _lt('TBA closing'),
'TURN': _lt('Turnaround'),
'REDM': _lt('Redemption'),
'SUBS': _lt('Subscription'),
'CROS': _lt('Cross Trade'),
'SWIC': _lt('Switch'),
'REAA': _lt('Redemption Asset Allocation'),
'SUAA': _lt('Subscription Asset Allocation'),
'PRUD': _lt('Principal Pay-down/pay-up'),
'TOUT': _lt('Transfer Out'),
'TRIN': _lt('Transfer In'),
'XCHC': _lt('Exchange Traded CCP'),
'XCHG': _lt('Exchange Traded'),
'XCHN': _lt('Exchange Traded Non-CCP'),
'OTCC': _lt('OTC CCP'),
'OTCG': _lt('OTC'),
'OTCN': _lt('OTC Non-CCP'),
'XCHC': _lt('Exchange Traded CCP'), # Blocked Transactions & CSD Blocked Transactions
'XCHG': _lt('Exchange Traded'),
'XCHN': _lt('Exchange Traded Non-CCP'),
'OTCC': _lt('OTC CCP'),
'OTCG': _lt('OTC'),
'OTCN': _lt('OTC Non-CCP'),
'MARG': _lt('Margin Payments'), # Collateral Management
'TRPO': _lt('Triparty Repo'),
'REPU': _lt('Repo'),
'SECB': _lt('Securities Borrowing'),
'SECL': _lt('Securities Lending'),
'OPBC': _lt('Option broker owned collateral'),
'OPCC': _lt('Option client owned collateral'),
'FWBC': _lt('Forwards broker owned collateral'),
'FWCC': _lt('Forwards client owned collateral'),
'MGCC': _lt('Margin client owned cash collateral'),
'SWBC': _lt('Swap broker owned collateral'),
'EQCO': _lt('Equity mark client owned'),
'EQBO': _lt('Equity mark broker owned'),
'CMCO': _lt('Corporate mark client owned'),
'CMBO': _lt('Corporate mark broker owned'),
'SLBC': _lt('Lending Broker Owned Cash Collateral'),
'SLCC': _lt('Lending Client Owned Cash Collateral'),
'CPRB': _lt('Corporate Rebate'),
'BIDS': _lt('Repurchase offer/Issuer Bid/Reverse Rights.'), # Corporate Action & Custody
'BONU': _lt('Bonus Issue/Capitalisation Issue'),
'BPUT': _lt('Put Redemption'),
'CAPG': _lt('Capital Gains Distribution'),
'CONV': _lt('Conversion'),
'DECR': _lt('Decrease in Value'),
'DRAW': _lt('Drawing'),
'DRIP': _lt('Dividend Reinvestment'),
'DTCH': _lt('Dutch Auction'),
'DVCA': _lt('Cash Dividend'),
'DVOP': _lt('Dividend Option'),
'EXOF': _lt('Exchange'),
'EXRI': _lt('Call on intermediate securities'),
'EXWA': _lt('Warrant Exercise/Warrant Conversion'),
'INTR': _lt('Interest Payment'),
'LIQU': _lt('Liquidation Dividend / Liquidation Payment'),
'MCAL': _lt('Full Call / Early Redemption'),
'MRGR': _lt('Merger'),
'ODLT': _lt('Odd Lot Sale/Purchase'),
'PCAL': _lt('Partial Redemption with reduction of nominal value'),
'PRED': _lt('Partial Redemption Without Reduction of Nominal Value'),
'PRII': _lt('Interest Payment with Principle'),
'PRIO': _lt('Priority Issue'),
'REDM': _lt('Final Maturity'),
'RHTS': _lt('Rights Issue/Subscription Rights/Rights Offer'),
'SHPR': _lt('Equity Premium Reserve'),
'TEND': _lt('Tender'),
'TREC': _lt('Tax Reclaim'),
'RWPL': _lt('Redemption Withdrawing Plan'),
'SSPL': _lt('Subscription Savings Plan'),
'CSLI': _lt('Cash in lieu'),
'CHAR': _lt('Charge/fees'), # Miscellaneous Securities Operations
'BKFE': _lt('Bank Fees'),
'CLAI': _lt('Compensation/Claims'),
'MNFE': _lt('Management Fees'),
'OVCH': _lt('Overdraft Charge'),
'TRFE': _lt('Transaction Fees'),
'UNCO': _lt('Underwriting Commission'),
'STAM': _lt('Stamp duty'),
'WITH': _lt('Withholding Tax'),
'BROK': _lt('Brokerage fee'),
'PRIN': _lt('Interest Payment with Principle'),
'TREC': _lt('Tax Reclaim'),
'GEN1': _lt('Withdrawal/distribution'),
'GEN2': _lt('Deposit/Contribution'),
'ERWI': _lt('Borrowing fee'),
'ERWA': _lt('Lending income'),
'SWEP': _lt('Sweep'),
'SWAP': _lt('Swap Payment'),
'FUTU': _lt('Future Variation Margin'),
'RESI': _lt('Futures Residual Amount'),
'FUCO': _lt('Futures Commission'),
'INFD': _lt('Fixed Deposit Interest Amount'),
# Account Management Sub-Families
'ACCO': _lt('Account Opening'),
'ACCC': _lt('Account Closing'),
'ACCT': _lt('Account Transfer'),
'VALD': _lt('Value Date'),
'BCKV': _lt('Back Value'),
'YTDA': _lt('YTD Adjustment'),
'FLTA': _lt('Float adjustment'),
'ERTA': _lt('Exchange Rate Adjustment'),
'PSTE': _lt('Posting Error'),
# General
'NTAV': _lt('Not available'),
'OTHR': _lt('Other'),
'MCOP': _lt('Miscellaneous Credit Operations'),
'MDOP': _lt('Miscellaneous Debit Operations'),
'FCTI': _lt('Fees, Commission , Taxes, Charges and Interest'),
}
def _generic_get(*nodes, xpath, namespaces, placeholder=None):
if placeholder is not None:
xpath = xpath.format(placeholder=placeholder)
for node in nodes:
item = node.xpath(xpath, namespaces=namespaces)
if item:
return item[0]
return False
class CAMT:
# These are pair of getters: (getter for the amount, getter for the amount's currency)
_amount_getters = [
(partial(_generic_get, xpath='ns:AmtDtls/ns:TxAmt/ns:Amt/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:TxAmt/ns:Amt/@Ccy')),
(partial(_generic_get, xpath='ns:AmtDtls/ns:CntrValAmt/ns:Amt/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:CntrValAmt/ns:Amt/@Ccy')),
(partial(_generic_get, xpath='ns:AmtDtls/ns:InstdAmt/ns:Amt/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:InstdAmt/ns:Amt/@Ccy')),
(partial(_generic_get, xpath='ns:Amt/text()'), partial(_generic_get, xpath='ns:Amt/@Ccy')),
]
_charges_getters = [
(partial(_generic_get, xpath='ns:Chrgs/ns:Rcrd/ns:Amt/text()'), partial(_generic_get, xpath='ns:Chrgs/ns:Rcrd/ns:Amt/@Ccy')),
(partial(_generic_get, xpath='ns:Chrgs/ns:Amt/text()'), partial(_generic_get, xpath='ns:Chrgs/ns:Amt/@Ccy')),
]
_amount_charges_getters = [
(partial(_generic_get, xpath='ns:Amt/text()'), partial(_generic_get, xpath='ns:Amt/@Ccy')),
]
# These are pair of getters: (getter for the exchange rate, getter for the target currency)
_target_rate_getters = [
(partial(_generic_get, xpath='ns:AmtDtls/ns:CntrValAmt/ns:CcyXchg/ns:XchgRate/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:CntrValAmt/ns:CcyXchg/ns:TrgtCcy/text()')),
(partial(_generic_get, xpath='ns:AmtDtls/ns:CntrValAmt/ns:CcyXchg/ns:XchgRate/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:CntrValAmt/ns:CcyXchg/ns:SrcCcy/text()')),
]
# These are pair of getters: (getter for the exchange rate, getter for the source currency)
_source_rate_getters = [
(partial(_generic_get, xpath='ns:AmtDtls/ns:TxAmt/ns:CcyXchg/ns:XchgRate/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:TxAmt/ns:CcyXchg/ns:SrcCcy/text()')),
(partial(_generic_get, xpath='ns:AmtDtls/ns:InstdAmt/ns:CcyXchg/ns:XchgRate/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:InstdAmt/ns:CcyXchg/ns:SrcCcy/text()')),
(partial(_generic_get, xpath='ns:AmtDtls/ns:TxAmt/ns:CcyXchg/ns:XchgRate/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:TxAmt/ns:CcyXchg/ns:TrgtCcy/text()')),
(partial(_generic_get, xpath='ns:AmtDtls/ns:InstdAmt/ns:CcyXchg/ns:XchgRate/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:InstdAmt/ns:CcyXchg/ns:TrgtCcy/text()')),
]
# These are pair of getters: (getter for the amount, getter for the amount's currency)
_currency_amount_getters = [
(partial(_generic_get, xpath='ns:AmtDtls/ns:InstdAmt/ns:Amt/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:InstdAmt/ns:Amt/@Ccy')),
(partial(_generic_get, xpath='ns:NtryDtls/ns:TxDtls/ns:AmtDtls/ns:InstdAmt/ns:Amt/text()'), partial(_generic_get, xpath='ns:NtryDtls/ns:TxDtls/ns:AmtDtls/ns:InstdAmt/ns:Amt/@Ccy')),
(partial(_generic_get, xpath='ns:AmtDtls/ns:TxAmt/ns:Amt/text()'), partial(_generic_get, xpath='ns:AmtDtls/ns:TxAmt/ns:Amt/@Ccy')),
(partial(_generic_get, xpath='ns:NtryDtls/ns:TxDtls/ns:AmtDtls/ns:TxAmt/ns:Amt/text()'), partial(_generic_get, xpath='ns:NtryDtls/ns:TxDtls/ns:AmtDtls/ns:TxAmt/ns:Amt/@Ccy')),
(partial(_generic_get, xpath='ns:Amt/text()'), partial(_generic_get, xpath='ns:Amt/@Ccy')),
]
_total_amount_getters = [
(partial(_generic_get, xpath='ns:NtryDtls/ns:Btch/ns:TtlAmt/text()'), partial(_generic_get, xpath='ns:NtryDtls/ns:Btch/ns:TtlAmt/@Ccy'))
]
# Start Balance
# OPBD : Opening Booked
# PRCD : Previous Closing Balance
# OPAV : Opening Available
# ITBD : Interim Booked (in the case of preceeding pagination)
# These are pair of getters: (getter for the amount, getter for the sign)
_start_balance_getters = [
(partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='OPBD']/../../ns:Amt/text()"),
partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='OPBD']/../../ns:CdtDbtInd/text()")),
(partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='PRCD']/../../ns:Amt/text()"),
partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='PRCD']/../../ns:CdtDbtInd/text()")),
(partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='OPAV']/../../ns:Amt/text()"),
partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='OPAV']/../../ns:CdtDbtInd/text()")),
(partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='ITBD']/../../ns:Amt/text()"),
partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='ITBD']/../../ns:CdtDbtInd/text()")),
]
# Ending Balance
# CLBD : Closing Booked
# CLAV : Closing Available
# ITBD : Interim Booked
# These are pair of getters: (getter for the amount, getter for the sign)
_end_balance_getters = [
(partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='CLBD']/../../ns:Amt/text()"),
partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='CLBD']/../../ns:CdtDbtInd/text()")),
(partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='CLAV']/../../ns:Amt/text()"),
partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='CLAV']/../../ns:CdtDbtInd/text()")),
(partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='ITBD']/../../ns:Amt/text()"),
partial(_generic_get, xpath="ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='ITBD']/../../ns:CdtDbtInd/text()")),
]
_get_credit_debit_indicator = partial(_generic_get,
xpath='ns:CdtDbtInd/text()')
_get_transaction_date = partial(_generic_get,
xpath=('ns:ValDt/ns:Dt/text()'
'| ns:BookgDt/ns:Dt/text()'
'| ns:BookgDt/ns:DtTm/text()'))
_get_statement_date = partial(_generic_get,
xpath=("ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='CLBD']/../../ns:Dt/ns:Dt/text()"
" | ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='CLBD']/../../ns:Dt/ns:DtTm/text()"
" | ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='CLAV']/../../ns:Dt/ns:Dt/text()"
" | ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='CLAV']/../../ns:Dt/ns:DtTm/text()"
" | ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='ITBD']/../../ns:Dt/ns:Dt/text()"
" | ns:Bal/ns:Tp/ns:CdOrPrtry[ns:Cd='ITBD']/../../ns:Dt/ns:DtTm/text()"
))
_get_partner_name = partial(_generic_get,
xpath=('.//ns:RltdPties/ns:Ultmt{placeholder}/ns:Nm/text()'
' | .//ns:RltdPties/ns:Ultmt{placeholder}/ns:Pty/ns:Nm/text()'
' | .//ns:RltdPties/ns:{placeholder}/ns:Nm/text()'
' | .//ns:RltdPties/ns:{placeholder}/ns:Pty/ns:Nm/text()'
))
_get_account_number = partial(_generic_get,
xpath=('.//ns:RltdPties/ns:{placeholder}Acct/ns:Id/ns:IBAN/text()'
'| (.//ns:{placeholder}Acct/ns:Id/ns:Othr/ns:Id)[1]/text()'))
_get_main_ref = partial(_generic_get,
xpath='.//ns:RmtInf/ns:Strd/ns:{placeholder}RefInf/ns:Ref/text()')
_get_other_ref = partial(_generic_get,
xpath=('ns:AcctSvcrRef/text()'
'| {placeholder}ns:Refs/ns:TxId/text()'
'| {placeholder}ns:Refs/ns:InstrId/text()'
'| {placeholder}ns:Refs/ns:EndToEndId/text()'
'| {placeholder}ns:Refs/ns:MndtId/text()'
'| {placeholder}ns:Refs/ns:ChqNb/text()'))
_get_additional_entry_info = partial(_generic_get, xpath='ns:AddtlNtryInf/text()')
_get_additional_text_info = partial(_generic_get, xpath='ns:AddtlTxInf/text()')
_get_transaction_id = partial(_generic_get, xpath='ns:Refs/ns:TxId/text()')
_get_instruction_id = partial(_generic_get, xpath='ns:Refs/ns:InstrId/text()')
_get_end_to_end_id = partial(_generic_get, xpath='ns:Refs/ns:EndToEndId/text()')
_get_mandate_id = partial(_generic_get, xpath='ns:Refs/ns:MndtId/text()')
_get_check_number = partial(_generic_get, xpath='ns:Refs/ns:ChqNb/text()')
@staticmethod
def _get_signed_balance(node, namespaces, getters):
for balance_getter, sign_getter in getters:
balance = balance_getter(node, namespaces=namespaces)
sign = sign_getter(node, namespaces=namespaces)
if balance and sign:
return -float(balance) if sign == 'DBIT' else float(balance)
return None
@staticmethod
def _get_signed_amount(*nodes, namespaces, journal_currency=None):
def get_value_and_currency_name(node, getters, target_currency=None):
for value_getter, currency_getter in getters:
value = value_getter(node, namespaces=namespaces)
currency_name = currency_getter(node, namespaces=namespaces)
if value and (target_currency is None or currency_name == target_currency):
return float(value), currency_name
return None, None
def get_rate(*entries, target_currency, amount_currency):
for entry in entries:
source_rate = get_value_and_currency_name(entry, CAMT._source_rate_getters, target_currency=target_currency)[0]
target_rate = get_value_and_currency_name(entry, CAMT._target_rate_getters, target_currency=target_currency)[0]
rate = source_rate or target_rate
# According to the camt.053 Swiss Payment Standards, the exchange rate should be divided by 100 if the
# currency is in YEN, SEK, DKK or NOK.
if amount_currency in ['SEK', 'DKK', 'YEN', 'NOK'] and target_currency == 'CHF':
rate = rate and rate / 100
else:
if not source_rate and target_rate:
rate = 1 / rate
if rate:
return rate
return None
def get_charges(*entries, target_currency=None):
for entry in entries:
charges = get_value_and_currency_name(entry, CAMT._charges_getters, target_currency=target_currency)[0]
if charges:
return charges
return None
entry_details = nodes[0]
entry = nodes[1] if len(nodes) > 1 else nodes[0]
journal_currency_name = journal_currency.name if journal_currency else None
entry_amount = get_value_and_currency_name(entry, CAMT._amount_charges_getters, target_currency=journal_currency_name)[0]
entry_details_amount = get_value_and_currency_name(entry_details, CAMT._amount_charges_getters, target_currency=journal_currency_name)[0]
charges = get_charges(entry_details, entry)
getters = CAMT._amount_charges_getters if charges else CAMT._amount_getters
amount, amount_currency_name = get_value_and_currency_name(entry_details, getters)
if not amount or (charges and journal_currency and journal_currency.compare_amounts(amount + charges, entry_amount) == 0):
amount, amount_currency_name = get_value_and_currency_name(entry, getters)
entry_amount_in_currency = get_value_and_currency_name(entry, getters, target_currency=amount_currency_name)[0]
entry_details_amount_in_currency = get_value_and_currency_name(entry_details, getters, target_currency=amount_currency_name)[0]
if not journal_currency or amount_currency_name == journal_currency_name:
rate = 1.0
else:
rate = get_rate(entry_details, entry, target_currency=journal_currency_name, amount_currency=amount_currency_name)
entry_amount = entry_details_amount or entry_amount
if entry_details_amount:
entry_amount_in_currency = entry_details_amount_in_currency
elif not entry_amount_in_currency:
entry_amount_in_currency = amount
computed_rate = entry_amount / entry_amount_in_currency
if rate:
if float_compare(rate, computed_rate, precision_digits=4) == 0:
rate = computed_rate
elif float_compare(rate, 1 / computed_rate, precision_digits=4) == 0:
rate = 1 / computed_rate
else:
amount, amount_currency_name = get_value_and_currency_name(entry_details, CAMT._amount_getters, target_currency=journal_currency_name)
if not amount:
amount, amount_currency_name = get_value_and_currency_name(entry, CAMT._amount_getters, target_currency=journal_currency_name)
if amount_currency_name == journal_currency_name:
rate = 1.0
if not rate:
raise ValidationError(_lt("No exchange rate was found to convert an amount into the currency of the journal"))
sign = 1 if CAMT._get_credit_debit_indicator(*nodes, namespaces=namespaces) == "CRDT" else -1
total_amount, total_amount_currency = get_value_and_currency_name(entry, CAMT._total_amount_getters)
result_amount = sign * amount * rate
if not total_amount or total_amount_currency != journal_currency_name and journal_currency:
entry_amount = entry_details_amount or entry_amount
total_amount = total_amount or amount
if journal_currency.compare_amounts(total_amount * rate, entry_amount) == 0:
result_amount = sign * amount * rate
elif journal_currency.compare_amounts(total_amount / rate, entry_amount) == 0:
result_amount = sign * amount / rate
if journal_currency:
result_amount = journal_currency.round(result_amount)
return result_amount
@staticmethod
def _get_counter_party(*nodes, namespaces):
ind = CAMT._get_credit_debit_indicator(*nodes, namespaces=namespaces)
return 'Dbtr' if ind == 'CRDT' else 'Cdtr'
@staticmethod
def _set_amount_in_currency(node, getters, entry_vals, currency, curr_cache, has_multi_currency, namespaces):
for value_getter, currency_getter in getters:
instruc_amount = value_getter(node, namespaces=namespaces)
instruc_curr = currency_getter(node, namespaces=namespaces)
if (has_multi_currency and instruc_amount and instruc_curr and
instruc_curr != currency and instruc_curr in curr_cache):
entry_vals['amount_currency'] = math.copysign(abs(float(instruc_amount)), entry_vals['amount'])
entry_vals['foreign_currency_id'] = curr_cache[instruc_curr]
break
@staticmethod
def _get_transaction_name(node, namespaces, entry=None):
xpaths = (
'.//ns:RmtInf/ns:Ustrd/text()',
'.//ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref/text()',
'.//ns:AddtlNtryInf/text()',
'.//ns:RmtInf/ns:Strd/ns:AddtlRmtInf/text()',
)
for xpath in xpaths:
if entry is not None and 'AddtlNtryInf' in xpath:
transaction_name = entry.xpath(xpath, namespaces=namespaces)
else:
transaction_name = node.xpath(xpath, namespaces=namespaces)
if transaction_name:
return ' '.join(transaction_name)
return '/'
@staticmethod
def _get_ref(node, counter_party, prefix, namespaces):
ref = CAMT._get_main_ref(node, placeholder=counter_party, namespaces=namespaces)
if ref is False: # Explicitely match False, not a falsy value
ref = CAMT._get_other_ref(node, placeholder=prefix, namespaces=namespaces)
return ref
@staticmethod
def _get_unique_import_id(entry, sequence, name, date, unique_import_set, namespaces):
unique_import_ref = entry.xpath('ns:AcctSvcrRef/text()', namespaces=namespaces)
if unique_import_ref and not CAMT._is_full_of_zeros(unique_import_ref[0]) and unique_import_ref[0] != 'NOTPROVIDED':
entry_ref = entry.xpath('ns:NtryRef/text()', namespaces=namespaces)
if entry_ref:
return '{}-{}-{}'.format(name, unique_import_ref[0], entry_ref[0])
elif not entry_ref and unique_import_ref[0] not in unique_import_set:
return unique_import_ref[0]
else:
return '{}-{}-{}'.format(name, unique_import_ref[0], sequence)
else:
return '{}-{}-{}'.format(name, date, sequence)
@staticmethod
def _get_transaction_type(node, namespaces):
code = node.xpath('ns:Domn/ns:Cd/text()', namespaces=namespaces)
family = node.xpath('ns:Domn/ns:Fmly/ns:Cd/text()', namespaces=namespaces)
subfamily = node.xpath('ns:Domn/ns:Fmly/ns:SubFmlyCd/text()', namespaces=namespaces)
if code:
return {'transaction_type': "{code}: {family} ({subfamily})".format(
code=codes[code[0].upper()],
family=family and codes[family[0].upper()] or '',
subfamily=subfamily and codes[subfamily[0].upper()] or '',
)}
return {}
@staticmethod
def _get_partner_address(node, ns, ph):
StrtNm = node.xpath('ns:RltdPties/ns:{}/ns:PstlAdr/ns:StrtNm/text()'.format(ph), namespaces=ns)
BldgNb = node.xpath('ns:RltdPties/ns:{}/ns:PstlAdr/ns:BldgNb/text()'.format(ph), namespaces=ns)
PstCd = node.xpath('ns:RltdPties/ns:{}/ns:PstlAdr/ns:PstCd/text()'.format(ph), namespaces=ns)
TwnNm = node.xpath('ns:RltdPties/ns:{}/ns:PstlAdr/ns:TwnNm/text()'.format(ph), namespaces=ns)
Ctry = node.xpath('ns:RltdPties/ns:{}/ns:PstlAdr/ns:Ctry/text()'.format(ph), namespaces=ns)
AdrLine = node.xpath('ns:RltdPties/ns:{}/ns:PstlAdr/ns:AdrLine/text()'.format(ph), namespaces=ns)
address = "\n".join(AdrLine)
if StrtNm:
address = "\n".join([address, ", ".join(StrtNm + BldgNb)])
if PstCd or TwnNm:
address = "\n".join([address, " ".join(PstCd + TwnNm)])
if Ctry:
address = "\n".join([address, Ctry[0]])
return address
@staticmethod
def _is_full_of_zeros(strg):
pattern_zero = re.compile('^0+$')
return bool(pattern_zero.match(strg))