def parse_credit_card_transaction(bank_config, account_config, card_config, transaction): amount = decode_numeric_value(transaction['importeMovimiento']) transaction_code = transaction['claveMovimiento'] # F**K BANKIA, removed sign from values # transaction_direction = TransactionDirection.CHARGE if amount < 0 else TransactionDirection.INCOME transaction_direction = infer_transaction_direction(transaction_code) if transaction_direction is TransactionDirection.CHARGE: amount = amount * -1 transaction_type = get_type(transaction_code, transaction_direction) 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'] return ParsedCreditCardTransaction( transaction_id=None, currency=transaction['importeMovimiento']['nombreMoneda'], amount=amount, value_date=decode_date(transaction['fechaMovimiento']['valor'], transaction['horaMovimiento']['valor']), transaction_date=decode_date(transaction['fechaMovimiento']['valor'], transaction['horaMovimiento']['valor']), type=transaction_type, source=source, destination=destination, card=card_used, details=details, keywords=keywords, comment=comment if comment is not None else '', )
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 parse_account_transaction(bank_config, account_config, transaction): amount = decode_numeric_value(transaction['importe']) transaction_code = transaction['codigoMovimiento'] transaction['referencias'] = references_by_code(transaction) transaction_direction = TransactionDirection.CHARGE if amount < 0 else TransactionDirection.INCOME transaction_type = get_type(transaction_code, transaction_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) card_used = 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=None, currency=transaction['importe']['moneda']['nombreCorto'], amount=amount, balance=decode_numeric_value(transaction['saldoPosterior']), value_date=decode_date(transaction['fechaValor']['valor'], ), transaction_date=decode_date(transaction['fechaMovimiento']['valor']), type=transaction_type, source=source, destination=destination, account=details.pop('account'), card=card_used, details=details, keywords=keywords, comment=comment if comment is not None else '', )
def accounts_root(): """ --- get: summary: Get all accounts this user has access to tags: - Accounts description: Returns the list of accounts that this user (person or bot) has permission to access. The list is returned in a single array (no pagination). responses: 200: content: application/json: schema: type: object properties: list: type: array items: "$ref": '#/definitions/AccountGET' """ user_id = flask.g.grafolean_data['user_id'] accounts = Account.get_list(user_id) return json.dumps({'list': accounts}), 200
def account_crud(account_id): """ --- get: summary: Get an account tags: - Accounts description: Returns account data. parameters: - name: account_id in: path description: "Account id" required: true schema: type: integer responses: 200: content: application/json: schema: "$ref": '#/definitions/AccountGET' 404: description: No such account put: summary: Update the account tags: - Accounts description: Updates account name. parameters: - name: account_id in: path description: "Account id" required: true schema: type: integer - name: "body" in: body description: "Account data" required: true schema: "$ref": '#/definitions/AccountPOST' responses: 204: description: Update successful 404: description: No such account """ if flask.request.method in ['GET', 'HEAD']: rec = Account.get(account_id) if not rec: return "No such account", 404 return json.dumps(rec), 200 elif flask.request.method == 'PUT': rec = Account.forge_from_input(flask.request.get_json(), force_id=account_id) rowcount = rec.update() if not rowcount: return "No such account", 404 mqtt_publish_changed([ 'accounts/{account_id}'.format(account_id=account_id), ]) return "", 204
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 accounts_crud(): """ --- get: summary: Get accounts tags: - Admin description: Returns a list of accounts that this user has the permission to access. The list is returned in a single array (no pagination). responses: 200: content: application/json: schema: type: object properties: list: type: array items: type: object properties: id: type: integer description: "Account id" name: type: string description: "Account name" post: summary: Create an account tags: - Admin description: Creates an account. parameters: - name: "body" in: body description: "Account data" required: true schema: "$ref": '#/definitions/AccountSchemaInputs' responses: 201: content: application/json: schema: type: object properties: id: type: integer description: "Account id" name: type: string description: "Account name" """ if flask.request.method in ['GET', 'HEAD']: rec = Account.get_list() return json.dumps({'list': rec}), 200 elif flask.request.method == 'POST': account = Account.forge_from_input(flask.request.get_json()) account_id = account.insert() return json.dumps({'name': account.name, 'id': account_id}), 201
def make_test_account(): return Account('TEST_ACCOUNT', '00000000001')