def parse_account_transaction(bank_config, account_config, transaction): amount = transaction['amount']['amount'] transaction_code = get_nested_item(transaction, 'scheme.subCategory.id') if transaction_code == '0054': # "Otros ..." transaction_code = get_nested_item(transaction, 'concept.id') transation_direction = TransactionDirection.CHARGE if amount < 0 else TransactionDirection.INCOME transaction_type = get_type(transaction_code, transation_direction) details = get_account_transaction_details(transaction, transaction_type) details['account'] = Account.from_config(account_config) details['bank'] = Bank.from_config(bank_config) card_number = details.pop('card_number', None) used_card = get_card(account_config, card_number) keywords = extract_keywords( chain(extract_literals(transaction, KEYWORD_FIELDS), filter(lambda value: isinstance(value, str), details.values()))) comment = get_comment(details, transaction_type) source = get_source(details, transaction_type) destination = get_destination(details, transaction_type) del details['bank'] return ParsedBankAccountTransaction( transaction_id=transaction['id'], type=transaction_type, currency=transaction['amount']['currency']['code'], amount=amount, balance=transaction['balance']['availableBalance']['amount'], value_date=decode_date(transaction['valueDate']), transaction_date=decode_date(transaction['transactionDate']), source=source, destination=destination, account=details.pop('account'), card=used_card, details=details, keywords=keywords, comment=comment if comment is not None else '', )
def set_detail(fieldname, xpath_string_or_list, fmt=None, default=None): nonlocal details xpath_list = xpath_string_or_list if isinstance(xpath_string_or_list, list) else [xpath_string_or_list] for xpath in xpath_list: value = get_nested_item(transaction, xpath) formatted_value = None if value is None else (value if fmt is None else fmt(value)) if formatted_value is not None: details[fieldname] = formatted_value return details[fieldname] = default
def _check_MatchCondition(condition, transaction): field = get_nested_item(transaction, condition.fieldname) if isinstance(field, datatypes.TransactionSubject): field_value = field.name elif isinstance(field, datatypes.UnknownSubject): return False else: field_value = field def included(ok, value): return condition.operator( ok, value in field_value ) def equals(ok, value): return condition.operator( ok, value == field_value ) def match(ok, value): return condition.operator( ok, bool(re.match(value, field_value, re.IGNORECASE)) ) def search(ok, value): return condition.operator( ok, bool(re.search(value, field_value, re.IGNORECASE)) ) if isinstance(field_value, list): value_checker = included elif not condition.regex: value_checker = equals # Cannot do a regex on a None elif field_value is None: return False if condition.regex == 'search': value_checker = search elif condition.regex == 'match': value_checker = match return reduce( value_checker, condition.values, initial_value(condition.operator) )
def capture_value(source, regex, transaction): field = get_nested_item(transaction, source) if isinstance(field, datatypes.TransactionSubject): source_value = field.name elif isinstance(field, datatypes.UnknownSubject): return False else: source_value = field match = re.search(regex, source_value, re.IGNORECASE) if match: try: return match.groups()[capture_group] except IndexError: return source_value else: return source_value
def get_last_update_time(metadata, bank, account_type, identifier): return get_nested_item( metadata, '{}.{}.{}.updated'.format(bank, account_type, identifier))
def _check_MatchNumericCondition(condition, transaction): field_value = get_nested_item(transaction, condition.fieldname) field_value = abs(field_value) if condition.absolute else field_value return condition.operator(field_value, condition.value)
def parse_credit_card_transaction(bank_config, account_config, card_config, transaction): amount = transaction['amount']['amount'] transaction_code = get_nested_item(transaction, 'concept.id') if transaction_code == '0000': # code 0000 seems like an error, as it's really a regular purcharse, # so we fake the code transaction_code = '0005' transation_direction = TransactionDirection.CHARGE if amount < 0 else TransactionDirection.INCOME transaction_type = get_type(transaction_code, transation_direction) # Transactions have a _PT or _TT termination, that changes once over time and makes id unusable # this is an attempt to fix this and still being able to use the id as an unique id transaction_id = re.sub(r'_[PT]T$', '', transaction['id']) details = get_card_transaction_details(transaction, transaction_type) details['account'] = Account.from_config(account_config) details['bank'] = Bank.from_config(bank_config) # As we are processing a concrete card, and transaction doesn't have this # information, we set it to be able to process all transactions equally card_used = Card.from_config(card_config) keywords = extract_keywords( chain(extract_literals(transaction, KEYWORD_FIELDS), filter(lambda value: isinstance(value, str), details.values()))) comment = get_comment(details, transaction_type) source = get_source(details, transaction_type) destination = get_destination(details, transaction_type) del details['bank'] del details['account'] is_debit_operation = transaction.get('operationTypeIndicator') == 'D' is_consolidated = transaction.get('status', {}).get('id') == '7' notify_not_added = False status_flags = datatypes.StatusFlags() if is_debit_operation: if notify_not_added: from common.notifications import get_notifier import bank banking_configuration = bank.load_config( bank.env()['main_config_file']) notifier = get_notifier(banking_configuration.notifications) notifier( 'Debit transaction found, not adding {bank.name} card transaction: {date} {amount}, {source}->{destination}' .format(bank=bank_config, amount=amount, date=transaction['valueDate'], source=str(source), destination=str(destination))) status_flags.invalid = True if not is_consolidated and notify_not_added: if notify_not_added: from common.notifications import get_notifier import bank banking_configuration = bank.load_config( bank.env()['main_config_file']) notifier = get_notifier(banking_configuration.notifications) notifier( 'Non consolidated transaction found, not adding {bank.name} card transaction: {date} {amount}, {source}->{destination}' .format(bank=bank_config, amount=amount, date=transaction['valueDate'], source=str(source), destination=str(destination))) return None return ParsedCreditCardTransaction( transaction_id=transaction_id, type=transaction_type, currency=transaction['amount']['currency']['code'], amount=amount, value_date=decode_date(transaction['valueDate']), transaction_date=decode_date(transaction['transactionDate']), source=source, destination=destination, card=card_used, details=details, keywords=keywords, comment=comment if comment is not None else '', status_flags=status_flags)
def transaction_string(transaction): return ' '.join( map(lambda field: get_nested_item(transaction, field).__repr__(), transaction_key_fields))
def test_nested_item_with_dict(obj, path, value): assert get_nested_item(obj, path) == value