Merge branch 'philip/ussd-demurrage' into 'master'
Philip/ussd demurrage See merge request grassrootseconomics/cic-internal-integration!263
This commit is contained in:
commit
b5f647c4aa
@ -1,10 +1,12 @@
|
|||||||
# standard imports
|
# standard imports
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
# third-party imports
|
# third-party imports
|
||||||
from cic_eth.api import Api
|
from cic_eth.api import Api
|
||||||
|
from cic_eth_aux.erc20_demurrage_token.api import Api as DemurrageApi
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from cic_ussd.account.transaction import from_wei
|
from cic_ussd.account.transaction import from_wei
|
||||||
@ -73,6 +75,24 @@ def calculate_available_balance(balances: dict) -> float:
|
|||||||
return from_wei(value=available_balance)
|
return from_wei(value=available_balance)
|
||||||
|
|
||||||
|
|
||||||
|
def get_adjusted_balance(balance: int, chain_str: str, timestamp: int, token_symbol: str):
|
||||||
|
"""
|
||||||
|
:param balance:
|
||||||
|
:type balance:
|
||||||
|
:param chain_str:
|
||||||
|
:type chain_str:
|
||||||
|
:param timestamp:
|
||||||
|
:type timestamp:
|
||||||
|
:param token_symbol:
|
||||||
|
:type token_symbol:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
logg.debug(f'retrieving adjusted balance on chain: {chain_str}')
|
||||||
|
demurrage_api = DemurrageApi(chain_str=chain_str)
|
||||||
|
return demurrage_api.get_adjusted_balance(token_symbol, balance, timestamp).result
|
||||||
|
|
||||||
|
|
||||||
def get_cached_available_balance(blockchain_address: str) -> float:
|
def get_cached_available_balance(blockchain_address: str) -> float:
|
||||||
"""This function attempts to retrieve balance data from the redis cache.
|
"""This function attempts to retrieve balance data from the redis cache.
|
||||||
:param blockchain_address: Ethereum address of an account.
|
:param blockchain_address: Ethereum address of an account.
|
||||||
@ -88,3 +108,14 @@ def get_cached_available_balance(blockchain_address: str) -> float:
|
|||||||
return calculate_available_balance(json.loads(cached_balances))
|
return calculate_available_balance(json.loads(cached_balances))
|
||||||
else:
|
else:
|
||||||
raise CachedDataNotFoundError(f'No cached available balance for address: {blockchain_address}')
|
raise CachedDataNotFoundError(f'No cached available balance for address: {blockchain_address}')
|
||||||
|
|
||||||
|
|
||||||
|
def get_cached_adjusted_balance(identifier: bytes):
|
||||||
|
"""
|
||||||
|
:param identifier:
|
||||||
|
:type identifier:
|
||||||
|
:return:
|
||||||
|
:rtype:
|
||||||
|
"""
|
||||||
|
key = cache_data_key(identifier, ':cic.adjusted_balance')
|
||||||
|
return get_cached_data(key)
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
# standard imports
|
# standard imports
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
import i18n.config
|
import i18n.config
|
||||||
from sqlalchemy.orm.session import Session
|
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from cic_ussd.account.balance import calculate_available_balance, get_balances, get_cached_available_balance
|
from cic_ussd.account.balance import (calculate_available_balance,
|
||||||
|
get_adjusted_balance,
|
||||||
|
get_balances,
|
||||||
|
get_cached_adjusted_balance,
|
||||||
|
get_cached_available_balance)
|
||||||
from cic_ussd.account.chain import Chain
|
from cic_ussd.account.chain import Chain
|
||||||
from cic_ussd.account.metadata import get_cached_preferred_language
|
from cic_ussd.account.metadata import get_cached_preferred_language
|
||||||
from cic_ussd.account.statement import (
|
from cic_ussd.account.statement import (
|
||||||
@ -16,14 +20,15 @@ from cic_ussd.account.statement import (
|
|||||||
query_statement,
|
query_statement,
|
||||||
statement_transaction_set
|
statement_transaction_set
|
||||||
)
|
)
|
||||||
from cic_ussd.account.transaction import from_wei, to_wei
|
|
||||||
from cic_ussd.account.tokens import get_default_token_symbol
|
from cic_ussd.account.tokens import get_default_token_symbol
|
||||||
|
from cic_ussd.account.transaction import from_wei, to_wei
|
||||||
from cic_ussd.cache import cache_data_key, cache_data
|
from cic_ussd.cache import cache_data_key, cache_data
|
||||||
from cic_ussd.db.models.account import Account
|
from cic_ussd.db.models.account import Account
|
||||||
from cic_ussd.metadata import PersonMetadata
|
from cic_ussd.metadata import PersonMetadata
|
||||||
from cic_ussd.phone_number import Support
|
from cic_ussd.phone_number import Support
|
||||||
from cic_ussd.processor.util import latest_input, parse_person_metadata
|
from cic_ussd.processor.util import parse_person_metadata
|
||||||
from cic_ussd.translation import translation_for
|
from cic_ussd.translation import translation_for
|
||||||
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
logg = logging.getLogger(__name__)
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -43,21 +48,26 @@ class MenuProcessor:
|
|||||||
:rtype:
|
:rtype:
|
||||||
"""
|
"""
|
||||||
available_balance = get_cached_available_balance(self.account.blockchain_address)
|
available_balance = get_cached_available_balance(self.account.blockchain_address)
|
||||||
logg.debug('Requires call to retrieve tax and bonus amounts')
|
adjusted_balance = get_cached_adjusted_balance(self.identifier)
|
||||||
tax = ''
|
|
||||||
bonus = ''
|
|
||||||
token_symbol = get_default_token_symbol()
|
token_symbol = get_default_token_symbol()
|
||||||
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
|
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
|
||||||
if not preferred_language:
|
if not preferred_language:
|
||||||
preferred_language = i18n.config.get('fallback')
|
preferred_language = i18n.config.get('fallback')
|
||||||
return translation_for(
|
with_available_balance = f'{self.display_key}.available_balance'
|
||||||
key=self.display_key,
|
with_fees = f'{self.display_key}.with_fees'
|
||||||
preferred_language=preferred_language,
|
if not adjusted_balance:
|
||||||
available_balance=available_balance,
|
return translation_for(key=with_available_balance,
|
||||||
tax=tax,
|
preferred_language=preferred_language,
|
||||||
bonus=bonus,
|
available_balance=available_balance,
|
||||||
token_symbol=token_symbol
|
token_symbol=token_symbol)
|
||||||
)
|
adjusted_balance = json.loads(adjusted_balance)
|
||||||
|
tax_wei = to_wei(int(available_balance)) - int(adjusted_balance)
|
||||||
|
tax = from_wei(int(tax_wei))
|
||||||
|
return translation_for(key=with_fees,
|
||||||
|
preferred_language=preferred_language,
|
||||||
|
available_balance=available_balance,
|
||||||
|
tax=tax,
|
||||||
|
token_symbol=token_symbol)
|
||||||
|
|
||||||
def account_statement(self) -> str:
|
def account_statement(self) -> str:
|
||||||
"""
|
"""
|
||||||
@ -67,7 +77,7 @@ class MenuProcessor:
|
|||||||
cached_statement = get_cached_statement(self.account.blockchain_address)
|
cached_statement = get_cached_statement(self.account.blockchain_address)
|
||||||
statement = json.loads(cached_statement)
|
statement = json.loads(cached_statement)
|
||||||
statement_transactions = parse_statement_transactions(statement)
|
statement_transactions = parse_statement_transactions(statement)
|
||||||
transaction_sets = [statement_transactions[tx:tx+3] for tx in range(0, len(statement_transactions), 3)]
|
transaction_sets = [statement_transactions[tx:tx + 3] for tx in range(0, len(statement_transactions), 3)]
|
||||||
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
|
preferred_language = get_cached_preferred_language(self.account.blockchain_address)
|
||||||
if not preferred_language:
|
if not preferred_language:
|
||||||
preferred_language = i18n.config.get('fallback')
|
preferred_language = i18n.config.get('fallback')
|
||||||
@ -149,12 +159,22 @@ class MenuProcessor:
|
|||||||
:return:
|
:return:
|
||||||
:rtype:
|
:rtype:
|
||||||
"""
|
"""
|
||||||
|
chain_str = Chain.spec.__str__()
|
||||||
token_symbol = get_default_token_symbol()
|
token_symbol = get_default_token_symbol()
|
||||||
blockchain_address = self.account.blockchain_address
|
blockchain_address = self.account.blockchain_address
|
||||||
balances = get_balances(blockchain_address, Chain.spec.__str__(), token_symbol, False)[0]
|
balances = get_balances(blockchain_address, chain_str, token_symbol, False)[0]
|
||||||
key = cache_data_key(self.identifier, ':cic.balances')
|
key = cache_data_key(self.identifier, ':cic.balances')
|
||||||
cache_data(key, json.dumps(balances))
|
cache_data(key, json.dumps(balances))
|
||||||
available_balance = calculate_available_balance(balances)
|
available_balance = calculate_available_balance(balances)
|
||||||
|
now = datetime.now()
|
||||||
|
if (now - self.account.created).days >= 30:
|
||||||
|
if available_balance <= 0:
|
||||||
|
logg.info(f'Not retrieving adjusted balance, available balance: {available_balance} is insufficient.')
|
||||||
|
else:
|
||||||
|
timestamp = int((now - timedelta(30)).timestamp())
|
||||||
|
adjusted_balance = get_adjusted_balance(to_wei(int(available_balance)), chain_str, timestamp, token_symbol)
|
||||||
|
key = cache_data_key(self.identifier, ':cic.adjusted_balance')
|
||||||
|
cache_data(key, json.dumps(adjusted_balance))
|
||||||
|
|
||||||
query_statement(blockchain_address)
|
query_statement(blockchain_address)
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ elif ssl == 0:
|
|||||||
else:
|
else:
|
||||||
ssl = True
|
ssl = True
|
||||||
|
|
||||||
|
valid_service_codes = config.get('USSD_SERVICE_CODE').split(",")
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
# TODO: improve url building
|
# TODO: improve url building
|
||||||
@ -79,9 +79,9 @@ def main():
|
|||||||
session = uuid.uuid4().hex
|
session = uuid.uuid4().hex
|
||||||
data = {
|
data = {
|
||||||
'sessionId': session,
|
'sessionId': session,
|
||||||
'serviceCode': config.get('APP_SERVICE_CODE'),
|
'serviceCode': valid_service_codes[0],
|
||||||
'phoneNumber': args.phone,
|
'phoneNumber': args.phone,
|
||||||
'text': config.get('APP_SERVICE_CODE'),
|
'text': "",
|
||||||
}
|
}
|
||||||
|
|
||||||
state = "_BEGIN"
|
state = "_BEGIN"
|
||||||
|
@ -10,6 +10,13 @@ RUN mkdir -vp data
|
|||||||
|
|
||||||
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
ARG EXTRA_INDEX_URL="https://pip.grassrootseconomics.net:8433"
|
||||||
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
ARG GITLAB_PYTHON_REGISTRY="https://gitlab.com/api/v4/projects/27624814/packages/pypi/simple"
|
||||||
|
|
||||||
|
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
|
||||||
|
pip install --index-url https://pypi.org/simple \
|
||||||
|
--extra-index-url $GITLAB_PYTHON_REGISTRY \
|
||||||
|
--extra-index-url $EXTRA_INDEX_URL \
|
||||||
|
cic-eth-aux-erc20-demurrage-token~=0.0.2a6
|
||||||
|
|
||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
|
|
||||||
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
|
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip \
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
alembic==1.4.2
|
alembic==1.4.2
|
||||||
|
attrs==21.2.0
|
||||||
|
billiard==3.6.4.0
|
||||||
bcrypt==3.2.0
|
bcrypt==3.2.0
|
||||||
celery==4.4.7
|
celery==4.4.7
|
||||||
|
cffi==1.14.6
|
||||||
cic-eth[services]~=0.12.4a7
|
cic-eth[services]~=0.12.4a7
|
||||||
cic-notify~=0.4.0a10
|
cic-notify~=0.4.0a10
|
||||||
cic-types~=0.1.0a14
|
cic-types~=0.1.0a14
|
||||||
|
@ -43,10 +43,13 @@ def test_sync_get_balances(activated_account,
|
|||||||
(5000000, 89000000, 67000000, 27.00)
|
(5000000, 89000000, 67000000, 27.00)
|
||||||
])
|
])
|
||||||
def test_calculate_available_balance(activated_account,
|
def test_calculate_available_balance(activated_account,
|
||||||
|
available_balance,
|
||||||
balance_incoming,
|
balance_incoming,
|
||||||
balance_network,
|
balance_network,
|
||||||
balance_outgoing,
|
balance_outgoing,
|
||||||
available_balance):
|
cache_balances,
|
||||||
|
cache_default_token_data,
|
||||||
|
load_chain_spec):
|
||||||
balances = {
|
balances = {
|
||||||
'address': activated_account.blockchain_address,
|
'address': activated_account.blockchain_address,
|
||||||
'converters': [],
|
'converters': [],
|
||||||
@ -57,7 +60,11 @@ def test_calculate_available_balance(activated_account,
|
|||||||
assert calculate_available_balance(balances) == available_balance
|
assert calculate_available_balance(balances) == available_balance
|
||||||
|
|
||||||
|
|
||||||
def test_get_cached_available_balance(activated_account, cache_balances, balances):
|
def test_get_cached_available_balance(activated_account,
|
||||||
|
balances,
|
||||||
|
cache_balances,
|
||||||
|
cache_default_token_data,
|
||||||
|
load_chain_spec):
|
||||||
cached_available_balance = get_cached_available_balance(activated_account.blockchain_address)
|
cached_available_balance = get_cached_available_balance(activated_account.blockchain_address)
|
||||||
available_balance = calculate_available_balance(balances[0])
|
available_balance = calculate_available_balance(balances[0])
|
||||||
assert cached_available_balance == available_balance
|
assert cached_available_balance == available_balance
|
||||||
|
@ -27,6 +27,8 @@ def test_filter_statement_transactions(transactions_list):
|
|||||||
|
|
||||||
|
|
||||||
def test_generate(activated_account,
|
def test_generate(activated_account,
|
||||||
|
cache_default_token_data,
|
||||||
|
cache_statement,
|
||||||
cache_preferences,
|
cache_preferences,
|
||||||
celery_session_worker,
|
celery_session_worker,
|
||||||
init_cache,
|
init_cache,
|
||||||
@ -60,7 +62,7 @@ def test_get_cached_statement(activated_account, cache_statement, statement):
|
|||||||
assert cached_statement[0].get('blockchain_address') == statement[0].get('blockchain_address')
|
assert cached_statement[0].get('blockchain_address') == statement[0].get('blockchain_address')
|
||||||
|
|
||||||
|
|
||||||
def test_parse_statement_transactions(statement):
|
def test_parse_statement_transactions(cache_default_token_data, statement):
|
||||||
parsed_transactions = parse_statement_transactions(statement)
|
parsed_transactions = parse_statement_transactions(statement)
|
||||||
parsed_transaction = parsed_transactions[0]
|
parsed_transaction = parsed_transactions[0]
|
||||||
parsed_transaction.startswith('Sent')
|
parsed_transaction.startswith('Sent')
|
||||||
@ -76,7 +78,7 @@ def test_query_statement(blockchain_address, limit, load_chain_spec, activated_a
|
|||||||
assert mock_transaction_list_query.get('limit') == limit
|
assert mock_transaction_list_query.get('limit') == limit
|
||||||
|
|
||||||
|
|
||||||
def test_statement_transaction_set(preferences, set_locale_files, statement):
|
def test_statement_transaction_set(cache_default_token_data, load_chain_spec, preferences, set_locale_files, statement):
|
||||||
parsed_transactions = parse_statement_transactions(statement)
|
parsed_transactions = parse_statement_transactions(statement)
|
||||||
preferred_language = preferences.get('preferred_language')
|
preferred_language = preferences.get('preferred_language')
|
||||||
transaction_set = statement_transaction_set(preferred_language, parsed_transactions)
|
transaction_set = statement_transaction_set(preferred_language, parsed_transactions)
|
||||||
|
@ -36,19 +36,19 @@ def test_aux_transaction_data(preferences, set_locale_files, transactions_list):
|
|||||||
check_aux_data('helpers.sent', 'helpers.to', preferred_language, sender_tx_aux_data)
|
check_aux_data('helpers.sent', 'helpers.to', preferred_language, sender_tx_aux_data)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("wei, expected_result", [
|
@pytest.mark.parametrize("value, expected_result", [
|
||||||
(50000000, Decimal('50.00')),
|
(50000000, Decimal('50.00')),
|
||||||
(100000, Decimal('0.10'))
|
(100000, Decimal('0.10'))
|
||||||
])
|
])
|
||||||
def test_from_wei(wei, expected_result):
|
def test_from_wei(cache_default_token_data, expected_result, value):
|
||||||
assert from_wei(wei) == expected_result
|
assert from_wei(value) == expected_result
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("value, expected_result", [
|
@pytest.mark.parametrize("value, expected_result", [
|
||||||
(50, 50000000),
|
(50, 50000000),
|
||||||
(0.10, 100000)
|
(0.10, 100000)
|
||||||
])
|
])
|
||||||
def test_to_wei(value, expected_result):
|
def test_to_wei(cache_default_token_data, expected_result, value):
|
||||||
assert to_wei(value) == expected_result
|
assert to_wei(value) == expected_result
|
||||||
|
|
||||||
|
|
||||||
@ -96,6 +96,7 @@ def test_validate_transaction_account(activated_account, init_database, transact
|
|||||||
@pytest.mark.parametrize("amount", [50, 0.10])
|
@pytest.mark.parametrize("amount", [50, 0.10])
|
||||||
def test_outgoing_transaction_processor(activated_account,
|
def test_outgoing_transaction_processor(activated_account,
|
||||||
amount,
|
amount,
|
||||||
|
cache_default_token_data,
|
||||||
celery_session_worker,
|
celery_session_worker,
|
||||||
load_config,
|
load_config,
|
||||||
load_chain_spec,
|
load_chain_spec,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# standard imports
|
# standard imports
|
||||||
import json
|
import json
|
||||||
|
import datetime
|
||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
from chainlib.hash import strip_0x
|
from chainlib.hash import strip_0x
|
||||||
@ -14,6 +15,7 @@ from cic_ussd.account.statement import (
|
|||||||
)
|
)
|
||||||
from cic_ussd.account.tokens import get_default_token_symbol
|
from cic_ussd.account.tokens import get_default_token_symbol
|
||||||
from cic_ussd.account.transaction import from_wei, to_wei
|
from cic_ussd.account.transaction import from_wei, to_wei
|
||||||
|
from cic_ussd.cache import cache_data, cache_data_key
|
||||||
from cic_ussd.menu.ussd_menu import UssdMenu
|
from cic_ussd.menu.ussd_menu import UssdMenu
|
||||||
from cic_ussd.metadata import PersonMetadata
|
from cic_ussd.metadata import PersonMetadata
|
||||||
from cic_ussd.phone_number import Support
|
from cic_ussd.phone_number import Support
|
||||||
@ -38,24 +40,34 @@ def test_menu_processor(activated_account,
|
|||||||
load_chain_spec,
|
load_chain_spec,
|
||||||
load_support_phone,
|
load_support_phone,
|
||||||
load_ussd_menu,
|
load_ussd_menu,
|
||||||
|
mock_get_adjusted_balance,
|
||||||
mock_sync_balance_api_query,
|
mock_sync_balance_api_query,
|
||||||
mock_transaction_list_query,
|
mock_transaction_list_query,
|
||||||
valid_recipient):
|
valid_recipient):
|
||||||
preferred_language = get_cached_preferred_language(activated_account.blockchain_address)
|
preferred_language = get_cached_preferred_language(activated_account.blockchain_address)
|
||||||
available_balance = get_cached_available_balance(activated_account.blockchain_address)
|
available_balance = get_cached_available_balance(activated_account.blockchain_address)
|
||||||
token_symbol = get_default_token_symbol()
|
token_symbol = get_default_token_symbol()
|
||||||
|
with_available_balance = 'ussd.kenya.account_balances.available_balance'
|
||||||
tax = ''
|
with_fees = 'ussd.kenya.account_balances.with_fees'
|
||||||
bonus = ''
|
|
||||||
display_key = 'ussd.kenya.account_balances'
|
|
||||||
ussd_menu = UssdMenu.find_by_name('account_balances')
|
ussd_menu = UssdMenu.find_by_name('account_balances')
|
||||||
name = ussd_menu.get('name')
|
name = ussd_menu.get('name')
|
||||||
resp = response(activated_account, display_key, name, init_database, generic_ussd_session)
|
resp = response(activated_account, 'ussd.kenya.account_balances', name, init_database, generic_ussd_session)
|
||||||
assert resp == translation_for(display_key,
|
assert resp == translation_for(with_available_balance,
|
||||||
preferred_language,
|
preferred_language,
|
||||||
available_balance=available_balance,
|
available_balance=available_balance,
|
||||||
|
token_symbol=token_symbol)
|
||||||
|
|
||||||
|
identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
|
||||||
|
key = cache_data_key(identifier, ':cic.adjusted_balance')
|
||||||
|
adjusted_balance = 45931650.64654012
|
||||||
|
cache_data(key, json.dumps(adjusted_balance))
|
||||||
|
resp = response(activated_account, 'ussd.kenya.account_balances', name, init_database, generic_ussd_session)
|
||||||
|
tax_wei = to_wei(int(available_balance)) - int(adjusted_balance)
|
||||||
|
tax = from_wei(int(tax_wei))
|
||||||
|
assert resp == translation_for(key=with_fees,
|
||||||
|
preferred_language=preferred_language,
|
||||||
|
available_balance=available_balance,
|
||||||
tax=tax,
|
tax=tax,
|
||||||
bonus=bonus,
|
|
||||||
token_symbol=token_symbol)
|
token_symbol=token_symbol)
|
||||||
|
|
||||||
cached_statement = get_cached_statement(activated_account.blockchain_address)
|
cached_statement = get_cached_statement(activated_account.blockchain_address)
|
||||||
@ -123,6 +135,15 @@ def test_menu_processor(activated_account,
|
|||||||
account_balance=available_balance,
|
account_balance=available_balance,
|
||||||
account_token_name=token_symbol)
|
account_token_name=token_symbol)
|
||||||
|
|
||||||
|
display_key = 'ussd.kenya.start'
|
||||||
|
ussd_menu = UssdMenu.find_by_name('start')
|
||||||
|
name = ussd_menu.get('name')
|
||||||
|
older_timestamp = (activated_account.created - datetime.timedelta(days=35))
|
||||||
|
activated_account.created = older_timestamp
|
||||||
|
init_database.flush()
|
||||||
|
response(activated_account, display_key, name, init_database, generic_ussd_session)
|
||||||
|
assert mock_get_adjusted_balance['timestamp'] == int((datetime.datetime.now() - datetime.timedelta(days=30)).timestamp())
|
||||||
|
|
||||||
display_key = 'ussd.kenya.transaction_pin_authorization'
|
display_key = 'ussd.kenya.transaction_pin_authorization'
|
||||||
ussd_menu = UssdMenu.find_by_name('transaction_pin_authorization')
|
ussd_menu = UssdMenu.find_by_name('transaction_pin_authorization')
|
||||||
name = ussd_menu.get('name')
|
name = ussd_menu.get('name')
|
||||||
|
@ -49,6 +49,7 @@ def test_is_valid_transaction_amount(activated_account, amount, expected_result,
|
|||||||
])
|
])
|
||||||
def test_has_sufficient_balance(activated_account,
|
def test_has_sufficient_balance(activated_account,
|
||||||
cache_balances,
|
cache_balances,
|
||||||
|
cache_default_token_data,
|
||||||
expected_result,
|
expected_result,
|
||||||
generic_ussd_session,
|
generic_ussd_session,
|
||||||
init_database,
|
init_database,
|
||||||
|
@ -121,6 +121,7 @@ def test_statement_callback(activated_account, mocker, transactions_list):
|
|||||||
def test_transaction_balances_callback(activated_account,
|
def test_transaction_balances_callback(activated_account,
|
||||||
balances,
|
balances,
|
||||||
cache_balances,
|
cache_balances,
|
||||||
|
cache_default_token_data,
|
||||||
cache_person_metadata,
|
cache_person_metadata,
|
||||||
cache_preferences,
|
cache_preferences,
|
||||||
load_chain_spec,
|
load_chain_spec,
|
||||||
|
@ -13,7 +13,8 @@ from cic_ussd.translation import translation_for
|
|||||||
# tests imports
|
# tests imports
|
||||||
|
|
||||||
|
|
||||||
def test_transaction(celery_session_worker,
|
def test_transaction(cache_default_token_data,
|
||||||
|
celery_session_worker,
|
||||||
load_support_phone,
|
load_support_phone,
|
||||||
mock_notifier_api,
|
mock_notifier_api,
|
||||||
notification_data,
|
notification_data,
|
||||||
|
@ -30,10 +30,11 @@ def test_generate_statement(activated_account,
|
|||||||
|
|
||||||
|
|
||||||
def test_cache_statement(activated_account,
|
def test_cache_statement(activated_account,
|
||||||
|
cache_default_token_data,
|
||||||
cache_person_metadata,
|
cache_person_metadata,
|
||||||
|
cache_preferences,
|
||||||
celery_session_worker,
|
celery_session_worker,
|
||||||
init_database,
|
init_database,
|
||||||
preferences,
|
|
||||||
transaction_result):
|
transaction_result):
|
||||||
recipient_transaction, sender_transaction = transaction_actors(transaction_result)
|
recipient_transaction, sender_transaction = transaction_actors(transaction_result)
|
||||||
identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
|
identifier = bytes.fromhex(strip_0x(activated_account.blockchain_address))
|
||||||
@ -41,7 +42,7 @@ def test_cache_statement(activated_account,
|
|||||||
cached_statement = get_cached_data(key)
|
cached_statement = get_cached_data(key)
|
||||||
assert cached_statement is None
|
assert cached_statement is None
|
||||||
s_parse_transaction = celery.signature(
|
s_parse_transaction = celery.signature(
|
||||||
'cic_ussd.tasks.processor.parse_transaction', [preferences, sender_transaction])
|
'cic_ussd.tasks.processor.parse_transaction', [sender_transaction])
|
||||||
result = s_parse_transaction.apply_async().get()
|
result = s_parse_transaction.apply_async().get()
|
||||||
s_cache_statement = celery.signature(
|
s_cache_statement = celery.signature(
|
||||||
'cic_ussd.tasks.processor.cache_statement', [result, activated_account.blockchain_address]
|
'cic_ussd.tasks.processor.cache_statement', [result, activated_account.blockchain_address]
|
||||||
@ -61,15 +62,15 @@ def test_cache_statement(activated_account,
|
|||||||
|
|
||||||
def test_parse_transaction(activated_account,
|
def test_parse_transaction(activated_account,
|
||||||
cache_person_metadata,
|
cache_person_metadata,
|
||||||
|
cache_preferences,
|
||||||
celery_session_worker,
|
celery_session_worker,
|
||||||
init_database,
|
init_database,
|
||||||
preferences,
|
|
||||||
transaction_result):
|
transaction_result):
|
||||||
recipient_transaction, sender_transaction = transaction_actors(transaction_result)
|
recipient_transaction, sender_transaction = transaction_actors(transaction_result)
|
||||||
assert sender_transaction.get('metadata_id') is None
|
assert sender_transaction.get('metadata_id') is None
|
||||||
assert sender_transaction.get('phone_number') is None
|
assert sender_transaction.get('phone_number') is None
|
||||||
s_parse_transaction = celery.signature(
|
s_parse_transaction = celery.signature(
|
||||||
'cic_ussd.tasks.processor.parse_transaction', [preferences, sender_transaction])
|
'cic_ussd.tasks.processor.parse_transaction', [sender_transaction])
|
||||||
result = s_parse_transaction.apply_async().get()
|
result = s_parse_transaction.apply_async().get()
|
||||||
assert result.get('metadata_id') == activated_account.standard_metadata_id()
|
assert result.get('metadata_id') == activated_account.standard_metadata_id()
|
||||||
assert result.get('phone_number') == activated_account.phone_number
|
assert result.get('phone_number') == activated_account.phone_number
|
||||||
|
16
apps/cic-ussd/tests/fixtures/patches/account.py
vendored
16
apps/cic-ussd/tests/fixtures/patches/account.py
vendored
@ -41,6 +41,22 @@ def mock_async_balance_api_query(mocker):
|
|||||||
return query_args
|
return query_args
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function')
|
||||||
|
def mock_get_adjusted_balance(mocker, task_uuid):
|
||||||
|
query_args = {}
|
||||||
|
|
||||||
|
def get_adjusted_balance(self, token_symbol, balance, timestamp):
|
||||||
|
sync_res = mocker.patch('celery.result.AsyncResult')
|
||||||
|
sync_res.id = task_uuid
|
||||||
|
sync_res.result = 45931650.64654012
|
||||||
|
query_args['balance'] = balance
|
||||||
|
query_args['timestamp'] = timestamp
|
||||||
|
query_args['token_symbol'] = token_symbol
|
||||||
|
return sync_res
|
||||||
|
mocker.patch('cic_eth_aux.erc20_demurrage_token.api.Api.get_adjusted_balance', get_adjusted_balance)
|
||||||
|
return query_args
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def mock_notifier_api(mocker):
|
def mock_notifier_api(mocker):
|
||||||
sms = {}
|
sms = {}
|
||||||
|
@ -141,12 +141,22 @@ en:
|
|||||||
0. Back
|
0. Back
|
||||||
retry: |-
|
retry: |-
|
||||||
%{retry_pin_entry}
|
%{retry_pin_entry}
|
||||||
account_balances: |-
|
account_balances:
|
||||||
CON Your balances are as follows:
|
available_balance: |-
|
||||||
balance: %{available_balance} %{token_symbol}
|
CON Your balances are as follows:
|
||||||
fees: %{tax} %{token_symbol}
|
balance: %{available_balance} %{token_symbol}
|
||||||
rewards: %{bonus} %{token_symbol}
|
0. Back
|
||||||
0. Back
|
with_fees: |-
|
||||||
|
CON Your balances are as follows:
|
||||||
|
balances: %{available_balance} %{token_symbol}
|
||||||
|
fees: %{tax} %{token_symbol}
|
||||||
|
0. Back
|
||||||
|
with_rewards: |-
|
||||||
|
CON Your balances are as follows:
|
||||||
|
balance: %{available_balance} %{token_symbol}
|
||||||
|
fees: %{tax} %{token_symbol}
|
||||||
|
rewards: %{bonus} %{token_symbol}
|
||||||
|
0. Back
|
||||||
first_transaction_set: |-
|
first_transaction_set: |-
|
||||||
CON %{first_transaction_set}
|
CON %{first_transaction_set}
|
||||||
1. Next
|
1. Next
|
||||||
|
@ -140,12 +140,22 @@ sw:
|
|||||||
0. Nyuma
|
0. Nyuma
|
||||||
retry: |-
|
retry: |-
|
||||||
%{retry_pin_entry}
|
%{retry_pin_entry}
|
||||||
account_balances: |-
|
account_balances:
|
||||||
CON Salio zako ni zifuatazo:
|
available_balance: |-
|
||||||
salio: %{available_balance} %{token_symbol}
|
CON Salio zako ni zifuatazo:
|
||||||
ushuru: %{tax} %{token_symbol}
|
salio: %{available_balance} %{token_symbol}
|
||||||
tuzo: %{bonus} %{token_symbol}
|
0. Nyuma
|
||||||
0. Nyuma
|
with_fees: |-
|
||||||
|
CON Salio zako ni zifuatazo:
|
||||||
|
salio: %{available_balance} %{token_symbol}
|
||||||
|
ushuru: %{tax} %{token_symbol}
|
||||||
|
0. Nyuma
|
||||||
|
with_rewards: |-
|
||||||
|
CON Salio zako ni zifuatazo:
|
||||||
|
salio: %{available_balance} %{token_symbol}
|
||||||
|
ushuru: %{tax} %{token_symbol}
|
||||||
|
tuzo: %{bonus} %{token_symbol}
|
||||||
|
0. Nyuma
|
||||||
first_transaction_set: |-
|
first_transaction_set: |-
|
||||||
CON %{first_transaction_set}
|
CON %{first_transaction_set}
|
||||||
1. Mbele
|
1. Mbele
|
||||||
|
Loading…
Reference in New Issue
Block a user