diff --git a/src/currency_quote/__init__.py b/src/currency_quote/__init__.py index 38f537b..910a393 100644 --- a/src/currency_quote/__init__.py +++ b/src/currency_quote/__init__.py @@ -7,43 +7,6 @@ class CurrencyQuote: def __init__(self, currency_list: list): self.currency_code = currency_list - def _validate_currency_code(self) -> list: - client = ClientBuilder( - endpoint=API.ENDPOINT_AVALIABLE_PARITIES, - retry_strategy=RetryStrategies.LinearRetryStrategy - ) - - valid_list = client.get_api_data() - - validated_list = [] - - for currency_code in self.currency_code: - if currency_code in valid_list: - validated_list.append(currency_code) - else: - print(f"Currency code: {currency_code} is not valid") - - if len(validated_list) == 0: - raise ValueError("No valid currency code was provided") - - return validated_list - - @staticmethod - def _get_last_quote(*args): - url = API.ENDPOINT_LAST_COTATION + ','.join(args) - client = ClientBuilder( - endpoint=url, - retry_strategy=RetryStrategies.LinearRetryStrategy - ) - - response = client.get_api_data() - - return response - - def get_last_quote(self): - last_quote = self._get_last_quote(*self._validate_currency_code()) - return last_quote - @staticmethod def _get_history_quote(*args, reference_date: int): diff --git a/src/currency_quote/__init__2.py b/src/currency_quote/__init__2.py new file mode 100644 index 0000000..7a294b4 --- /dev/null +++ b/src/currency_quote/__init__2.py @@ -0,0 +1,16 @@ +from .adapters.outbound.currency_api import CurrencyAPI +from .adapters.inbound.controller import CurrencyController +from .domain.services.get_currency_quote import GetCurrencyQuote +from .domain.services.validate_currency import ValidateCurrency + + + +class CurrencyQuote: + def __init__(self): + currency_api = CurrencyAPI() + validate_currency_service = ValidateCurrency(currency_api) + get_currency_quote_service = GetCurrencyQuote(currency_api, validate_currency_service) + self.controller = CurrencyController(get_currency_quote_service) + + def get_quote(self, currency_code: str): + return self.controller.get_quote(currency_code) diff --git a/src/currency_quote/adapters/inbound/controller.py b/src/currency_quote/adapters/inbound/controller.py index e69de29..ad8a4f3 100644 --- a/src/currency_quote/adapters/inbound/controller.py +++ b/src/currency_quote/adapters/inbound/controller.py @@ -0,0 +1,14 @@ +# src/currency_quote/adapters/inbound/controller.py +from currency_quote.application.ports.inbound.get_currency_quote_use_case import GetCurrencyQuoteUseCase + + +class CurrencyController: + def __init__(self, get_currency_quote_use_case: GetCurrencyQuoteUseCase): + self.get_currency_quote_use_case = get_currency_quote_use_case + + def get_quote(self, currency_code: str): + try: + currency = self.get_currency_quote_use_case.execute(currency_code) + return {"code": currency.code, "name": currency.name, "rate": currency.rate} + except ValueError as e: + return {"error": str(e)} diff --git a/src/currency_quote/adapters/outbound/currency_api.py b/src/currency_quote/adapters/outbound/currency_api.py index e69de29..88a196a 100644 --- a/src/currency_quote/adapters/outbound/currency_api.py +++ b/src/currency_quote/adapters/outbound/currency_api.py @@ -0,0 +1,17 @@ +# src/currency_quote/adapters/outbound/currency_api.py +from api_to_dataframe import ClientBuilder, RetryStrategies +from currency_quote.application.ports.outbound.currency_repository import CurrencyRepository +from currency_quote.config.endpoints import API + + +class CurrencyAPI(CurrencyRepository): + def _get_last_quote(*args): + url = API.ENDPOINT_LAST_COTATION + ','.join(args) + client = ClientBuilder( + endpoint=url, + retry_strategy=RetryStrategies.LinearRetryStrategy + ) + + response = client.get_api_data() + + return response \ No newline at end of file diff --git a/src/currency_quote/adapters/outbound/currency_validator_api.py b/src/currency_quote/adapters/outbound/currency_validator_api.py new file mode 100644 index 0000000..398d359 --- /dev/null +++ b/src/currency_quote/adapters/outbound/currency_validator_api.py @@ -0,0 +1,22 @@ +# src/currency_quote/adapters/outbound/currency_validator_api.py +from api_to_dataframe import ClientBuilder, RetryStrategies +from currency_quote.config.endpoints import API + + +class CurrencyValidator: + @staticmethod + def validate_currency_code(currency_list: list) -> list: + client = ClientBuilder( + endpoint=API.ENDPOINT_AVALIABLE_PARITIES, + retry_strategy=RetryStrategies.LinearRetryStrategy + ) + + valid_list = client.get_api_data() + + validated_list = [] + + for currency_code in currency_list: + if currency_code in valid_list: + validated_list.append(currency_code) + + return validated_list diff --git a/src/currency_quote/application/ports/inbound/__init__.py b/src/currency_quote/application/ports/inbound/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/currency_quote/application/ports/inbound/get_currency_quote_use_case.py b/src/currency_quote/application/ports/inbound/get_currency_quote_use_case.py index e69de29..f8f78b2 100644 --- a/src/currency_quote/application/ports/inbound/get_currency_quote_use_case.py +++ b/src/currency_quote/application/ports/inbound/get_currency_quote_use_case.py @@ -0,0 +1,8 @@ +from abc import ABC, abstractmethod +from currency_quote.domain.entities.currency import Currency + + +class GetCurrencyQuoteUseCase(ABC): + @abstractmethod + def execute(self, currency_code: list) -> Currency: + pass diff --git a/src/currency_quote/application/ports/outbound/currency_repository.py b/src/currency_quote/application/ports/outbound/currency_repository.py index e69de29..1aa68c0 100644 --- a/src/currency_quote/application/ports/outbound/currency_repository.py +++ b/src/currency_quote/application/ports/outbound/currency_repository.py @@ -0,0 +1,8 @@ +# src/currency_quote/application/ports/outbound/currency_repository.py +from abc import ABC, abstractmethod + + +class CurrencyRepository(ABC): + @abstractmethod + def get_currency_quote(self, currency_code: list): + pass diff --git a/src/currency_quote/application/ports/outbound/currency_validator_repository.py b/src/currency_quote/application/ports/outbound/currency_validator_repository.py new file mode 100644 index 0000000..53a3a86 --- /dev/null +++ b/src/currency_quote/application/ports/outbound/currency_validator_repository.py @@ -0,0 +1,8 @@ +# src/currency_quote/application/ports/outbound/currency_validator_port.py +from abc import ABC, abstractmethod + + +class CurrencyValidatorPort(ABC): + @abstractmethod + def validate_currency_code(self, currency_list: list) -> list: + pass diff --git a/src/currency_quote/application/use_cases/test_validate_currency.py b/src/currency_quote/application/use_cases/test_validate_currency.py new file mode 100644 index 0000000..3d9d52e --- /dev/null +++ b/src/currency_quote/application/use_cases/test_validate_currency.py @@ -0,0 +1,29 @@ +import pytest +from currency_quote.domain.services.validate_currency import CurrencyValidatorService +from currency_quote.application.use_cases.validate_currency import ValidateCurrencyUseCase + + +def test_valid_currency(): + validator_service = CurrencyValidatorService() + currency_list = ["USD-BRL", "USD-BRLT"] + validate_currency = ValidateCurrencyUseCase(currency_validator_service=validator_service) + result = validate_currency.execute(currency_list=currency_list) + assert result == currency_list + + +def test_partial_valid_currency(): + validator_service = CurrencyValidatorService() + currency_list = ["USD-BRL", "USD-BRLT", "param1"] + expected_result = ["USD-BRL", "USD-BRLT"] + validate_currency = ValidateCurrencyUseCase(currency_validator_service=validator_service) + result = validate_currency.execute(currency_list=currency_list) + assert result == expected_result + + +def test_invalid_currency(): + validator_service = CurrencyValidatorService() + currency_list = ["param1", "param2"] + validate_currency = ValidateCurrencyUseCase(currency_validator_service=validator_service) + with pytest.raises(ValueError): + validate_currency.execute(currency_list=currency_list) + diff --git a/src/currency_quote/application/use_cases/validate_currency.py b/src/currency_quote/application/use_cases/validate_currency.py new file mode 100644 index 0000000..4a56c52 --- /dev/null +++ b/src/currency_quote/application/use_cases/validate_currency.py @@ -0,0 +1,10 @@ +# src/currency_quote/application/use_cases/validate_currency.py +from currency_quote.domain.services.validate_currency import CurrencyValidatorService + + +class ValidateCurrencyUseCase: + def __init__(self, currency_validator_service: CurrencyValidatorService): + self.currency_validator_service = currency_validator_service + + def execute(self, currency_list: list) -> list: + return self.currency_validator_service.validate_currency_code(currency_list) diff --git a/src/currency_quote/config/endpoints.py b/src/currency_quote/config/endpoints.py index d38a050..cbade23 100644 --- a/src/currency_quote/config/endpoints.py +++ b/src/currency_quote/config/endpoints.py @@ -4,4 +4,4 @@ class API: ENDPOINT_LAST_COTATION = __URL__ + "/last/" ENDPOINT_HISTORY_COTATION = __URL__ + "/json/daily/" RETRY_TIME_SECONDS = 2 - RETRY_ATTEMPTS = 3 + RETRY_ATTEMPTS = 3 \ No newline at end of file diff --git a/src/currency_quote/domain/entities/currency.py b/src/currency_quote/domain/entities/currency.py new file mode 100644 index 0000000..4b77004 --- /dev/null +++ b/src/currency_quote/domain/entities/currency.py @@ -0,0 +1,3 @@ +class Currency: + def __init__(self, currency: list): + self.currency_list = currency diff --git a/src/currency_quote/domain/models/currency.py b/src/currency_quote/domain/models/currency.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/currency_quote/domain/services/get_currency_quote.py b/src/currency_quote/domain/services/get_currency_quote.py index e69de29..9285914 100644 --- a/src/currency_quote/domain/services/get_currency_quote.py +++ b/src/currency_quote/domain/services/get_currency_quote.py @@ -0,0 +1,20 @@ +# src/currency_quote/domain/services/get_currency_quote.py +from currency_quote.application.ports.inbound.get_currency_quote_use_case import GetCurrencyQuoteUseCase +from currency_quote.application.ports.outbound.currency_repository import CurrencyRepository +from currency_quote.domain.entities.currency import Currency +from currency_quote.domain.services.validate_currency import ValidateCurrency + + +class GetCurrencyQuote(GetCurrencyQuoteUseCase): + def __init__(self, currency_repository: CurrencyRepository, validate_currency_service: ValidateCurrency): + self.currency_repository = currency_repository + self.validate_currency_service = validate_currency_service + + def execute(self, currency_code: str) -> Currency: + if not self.validate_currency_service.execute(currency_code): + raise ValueError(f"Código de moeda {currency_code} é inválido.") + + currency = self.currency_repository.get_currency_quote(currency_code) + if not currency: + raise ValueError(f"Cotação para a moeda {currency_code} não encontrada.") + return currency diff --git a/src/currency_quote/domain/services/validate_currency.py b/src/currency_quote/domain/services/validate_currency.py index e69de29..20138f5 100644 --- a/src/currency_quote/domain/services/validate_currency.py +++ b/src/currency_quote/domain/services/validate_currency.py @@ -0,0 +1,19 @@ +# src/currency_quote/application/services/currency_validator_service.py +from currency_quote.application.ports.outbound.currency_validator_repository import CurrencyValidatorPort +from currency_quote.adapters.outbound.currency_validator_api import CurrencyValidator + + +class CurrencyValidatorService(CurrencyValidatorPort): + def __init__(self): + self.currency_validator = CurrencyValidator() + + def validate_currency_code(self, currency_list: list) -> list: + validated_list = self.currency_validator.validate_currency_code(currency_list) + + if len(validated_list) == 0: + raise ValueError(f"All params: {currency_list} are invalid.") + + if len(validated_list) < len(currency_list): + print(f"Invalid currency params: {set(currency_list) - set(validated_list)}") + + return validated_list diff --git a/src/currency_quote/application/ports/inbound/common.py b/src/currency_quote/utils/common.py similarity index 100% rename from src/currency_quote/application/ports/inbound/common.py rename to src/currency_quote/utils/common.py diff --git a/src/currency_quote/adapters/outbound/logs.py b/src/currency_quote/utils/logs.py similarity index 100% rename from src/currency_quote/adapters/outbound/logs.py rename to src/currency_quote/utils/logs.py diff --git a/tests/test_hist_currency_quote.py b/tests/test_hist_currency_quote.py deleted file mode 100644 index ebf2b51..0000000 --- a/tests/test_hist_currency_quote.py +++ /dev/null @@ -1,56 +0,0 @@ -import pytest -import datetime -from currency_quote import CurrencyQuote - - - -def test_one_valid_param(): - client = CurrencyQuote(['USD-BRL']) - - data = client.get_history_quote(reference_date=20240526) - - assert len(data) == 1 - assert isinstance(data, list) - - -def test_two_valid_params(): - client = CurrencyQuote(['USD-BRL', "EUR-BRL"]) - - data = client.get_history_quote(reference_date=20240526) - - assert len(data) == 2 - assert isinstance(data, list) - - -def test_one_invalid_param(): - client = CurrencyQuote(['USD-BRL', "param1"]) - - data = client.get_history_quote(reference_date=20240526) - - assert isinstance(data, list) - assert len(data) == 1 - - -def test_all_invalid_params(): - client = CurrencyQuote(['param2', "param1"]) - - with pytest.raises(ValueError): - client.get_history_quote(reference_date=20240526) - - -def test_invalid_date(): - client = CurrencyQuote(['USD-BRL']) - - invalid_date = int(datetime.datetime.now().strftime("%Y%m%d")) + 1 - - with pytest.raises(ValueError): - client.get_history_quote(reference_date=invalid_date) - - -def test_indisponible_data(): - client = CurrencyQuote(['USD-BRL']) - - invalid_date = 20160110 - - with pytest.raises(ValueError): - client.get_history_quote(reference_date=invalid_date) diff --git a/tests/test_last_currency_quote.py b/tests/test_last_currency_quote.py deleted file mode 100644 index 630b7ba..0000000 --- a/tests/test_last_currency_quote.py +++ /dev/null @@ -1,36 +0,0 @@ -import pytest -from currency_quote import CurrencyQuote - - -def test_one_valid_param(): - client = CurrencyQuote(['USD-BRL']) - - data = client.get_last_quote() - - assert len(data) == 1 - assert isinstance(data, dict) - - -def test_two_valid_params(): - client = CurrencyQuote(['USD-BRL', "EUR-BRL"]) - - data = client.get_last_quote() - - assert len(data) == 2 - assert isinstance(data, dict) - - -def test_one_invalid_param(): - client = CurrencyQuote(['USD-BRL', "param1"]) - - data = client.get_last_quote() - - assert isinstance(data, dict) - assert len(data) == 1 - - -def test_all_invalid_params(): - client = CurrencyQuote(['param2', "param1"]) - - with pytest.raises(ValueError): - client.get_last_quote()