def transferMoney(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ token = request.get("token") login = microservice("http://auth/auth", {"token": token}, "result") from_base_currency = request.get("from_base_currency") to_login = request.get("to_login") to_base_currency = request.get("to_base_currency") amount = request.get("amount") conversion_rate_uuid_1 = request.get("conversion_rate_uuid_1", None) conversion_rate_uuid_2 = request.get("conversion_rate_uuid_2", None) return microservice( "http://wallets/transfer", { "from_login": login, "from_base_currency": from_base_currency, "to_login": to_login, "to_base_currency": to_base_currency, "amount": amount, "conversion_rate_uuid_1": conversion_rate_uuid_1, "conversion_rate_uuid_2": conversion_rate_uuid_2 }, "result" )
def topUpBalance(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ login = request.get("login") base_currency = request.get("base_currency") amount = request.get("amount") microservice("http://wallets/topup", { "login": login, "base_currency": base_currency, "amount": amount }, "result") return True
def getSupportedCurrencies(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ return microservice("http://wallets/get_currencies", {}, "result")
def createWallet(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ token = request.get("token") login = microservice("http://auth/auth", {"token": token}, "result") base_currency = request.get("base_currency") return microservice( "http://wallets/create", { "login": login, "base_currency": base_currency }, "result" )
def getMe(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ token = request.get("token") login = microservice("http://auth/auth", {"token": token}, "result") wallets = microservice("http://wallets/get_wallets", {"login": login}, "result") user = microservice("http://users/get", {"login": login}, "result") user["country_name"] = microservice( "http://geo/get_country", {"id": user["country_id"]}, "result.name" ) user["city_name"] = microservice( "http://geo/get_city", {"id": user["city_id"], "country_id": user["country_id"]}, "result.name" ) return {**user, "wallets": wallets}
def saveRatesBulk(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ data = request.get("data") return microservice("http://converter/save_bulk", {"data": data}, "result")
def auth(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ login = request.get("login") password = request.get("password") return microservice("http://auth/auth", {"login": login, "password": password}, "result")
def getConvertionRates(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ from_base_currency = request.get("from_base_currency") to_base_currency = request.get("to_base_currency") conversion_rate1 = microservice( "http://converter/get_last_value", {"base_currency": from_base_currency}, "result" ) conversion_rate2 = microservice( "http://converter/get_last_value", {"base_currency": to_base_currency}, "result" ) return { "conversion_rate1": conversion_rate1, "conversion_rate2": conversion_rate2 }
def saveRate(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ base_currency = request.get("base_currency") value = request.get("value") datetime = request.get("datetime") return microservice("http://converter/save", { "base_currency": base_currency, "value": value, "datetime": datetime }, "result")
def getTransactions(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ login = request.get("login") period_starts = request.get("period_starts", None) period_ends = request.get("period_ends", None) return microservice( "http://wallets/get_transactions", { "login": login, "period_starts": period_starts, "period_ends": period_ends }, "result")
def createAccount(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ login = request.get("login") password = request.get("password") name = request.get("name") country = request.get("country_id", request.get("country_name")) city = request.get("city_id", request.get("city_name")) base_currency = request.get("base_currency") microservice("http://auth/create", {"login": login, "password": password}, "result") country_id = microservice( "http://geo/get_country", {"id": country if country.isnumeric() else None, "name": country if not country.isnumeric() else None}, "result.id" ) city_id = microservice( "http://geo/get_city", {"id": city if city.isnumeric() else None, "name": city if not city.isnumeric() else None, "country_id": country_id}, "result.id" ) microservice( "http://users/create", {"login": login, "name": name, "country_id": country_id, "city_id": city_id}, "result" ) microservice( "http://wallets/create", {"login": login, "base_currency": base_currency}, "result" ) return True
def getTransactionsCsvReport(cls, request: Request, **kwargs): """ :param request: :param kwargs: :return: """ login = request.get("login") period_starts = request.get("period_starts", None) period_ends = request.get("period_ends", None) transactions = microservice( "http://wallets/get_transactions", { "login": login, "period_starts": period_starts, "period_ends": period_ends }, "result") all_transactions = [tx + ["+"] for tx in transactions["incoming"]] + \ [tx + ["-"] for tx in transactions["outgoing"]] all_transactions.sort(key=lambda tx: datetime.strptime(tx[5], "%c")) csv_header = [ "tx_uuid", "login", "base_currency", "amount", "convertion_rate_uuid", "tx_datetime", "mode" ] csv_body = [csv_header] for tx in all_transactions: csv_body.append(tx) file = io.StringIO() writer = csv.writer(file, delimiter=",") writer.writerows(csv_body) result = file.getvalue() request.response.add_header("Content-Type", 'application/vnd.ms-excel') request.response.add_header( "Content-disposition", 'attachment; filename=transactions-%s.csv' % login) return result
class Converter: """ Utility class for working with currencies and and convertion rates """ get_last_value = lambda bc: microservice("http://converter/get_last_value", {"base_currency": bc}, "result") get_by_uuid = lambda uuid: microservice("http://converter/get_by_uuid", {"uuid": uuid}, "result") @staticmethod def get_convertion_rate_value(original_currency, convertion_rate_uuid): """ Retrieving and validation convertion rate """ # noinspection PyCallByClass conversion_rate = Currencies.Converter.get_by_uuid(convertion_rate_uuid) conversion_rate_datetime = datetime.strptime(conversion_rate["datetime"], "%c") convertion_rate_expired_datetime = datetime.now() - timedelta( seconds=Currencies.CONVERSION_RATE_TIMEOUT_TOLERANCE ) if conversion_rate_datetime < convertion_rate_expired_datetime: raise ConvertionRateExpired() if conversion_rate["base_currency"] != original_currency: raise InvalidConvertionRate() return conversion_rate["value"] @staticmethod def convert( amount: float, from_base_currency: int, to_base_currency: int, convertion_rate_uuid_1: str=None, convertion_rate_uuid_2: str=None) -> float: """ Converts currencies based on given convertion rates with validation """ # No convertion required: if from_base_currency == to_base_currency: convertion_rate_value_1 = 1 convertion_rate_value_2 = 1 # At least one convertion required: else: # From USD to Other Currency (1 convertion): if from_base_currency == Currencies.USD: convertion_rate_value_1 = 1 if not convertion_rate_uuid_2: raise NoConversionRateProvided() else: convertion_rate_value_2 = Currencies.Converter.get_convertion_rate_value( to_base_currency, convertion_rate_uuid_2 ) # From Some Currency to USD (1 convertion): elif to_base_currency == Currencies.USD: convertion_rate_value_2 = 1 if not convertion_rate_uuid_1: raise NoConversionRateProvided() else: convertion_rate_value_1 = Currencies.Converter.get_convertion_rate_value( from_base_currency, convertion_rate_uuid_1 ) # From Some Currency to Other Currency, not USD (2 convertions): else: if not convertion_rate_uuid_1 or not convertion_rate_uuid_2: raise NoConversionRateProvided() convertion_rate_value_1 = Currencies.Converter.get_convertion_rate_value( from_base_currency, convertion_rate_uuid_1 ) convertion_rate_value_2 = Currencies.Converter.get_convertion_rate_value( to_base_currency, convertion_rate_uuid_2 ) return amount * convertion_rate_value_1 / convertion_rate_value_2
def test_successfull_scenario(self): """ Lets test successfull sceanrio of using the app """ # Registration: registration_result = microservice( "http://public_api/createAccount", { "login": "******", "password": "******", "name": "Andrey", "country_name": "Russia", "city_name": "Moscow", "base_currency": 1 }, "result") self.assertTrue(registration_result) # Authenticatation: token = microservice("http://public_api/auth", { "login": "******", "password": "******" }, "result") # Getting user data back, including list of wallets: user_data = microservice("http://public_api/getMe", {"token": token}, "result") self.assertDictEqual( { "city_id": 1, # Here we can see that our geo-info now have ids, "city_name": "Moscow", # so it could be reused by other users "country_id": 1, # with some help from the front-end "country_name": "Russia", "login": "******", "name": "Andrey", # Also we have our first wallet for USD right after registration: "wallets": [{ "balance": 0.0, "base_currency": 1, "login": "******" }] }, user_data) # Let's try to create another wallet for different currency... # First of all, we need to know what currencies are currently supported by the platform: supported_currencies = microservice( "http://public_api/getSupportedCurrencies", {}, "result") self.assertDictEqual({ "1": "USD", "2": "EUR", "3": "CAD", "4": "CNY" }, supported_currencies) # We already have a USD-wallet, so let's create CNY: new_wallet_creation = microservice("http://public_api/createWallet", { "token": token, "base_currency": 4 }, "result") self.assertTrue(new_wallet_creation) #Let's check our wallets now: user_wallets = microservice("http://public_api/getMe", {"token": token}, "result.wallets") self.assertEqual([{ "balance": 0.0, "base_currency": 1, "login": "******" }, { "balance": 0.0, "base_currency": 4, "login": "******" }], user_wallets) # Ok, so far so good... # But to test further we need to get some money into one of our wallets... # We can do that by using private_api, that should be only accessible for trusted persons: topping_up_result = microservice("http://private_api/topUpBalance", { "login": "******", "base_currency": 1, "amount": 100 }, "result") self.assertTrue(topping_up_result) # Have we become a millionaires already? Lets find out: user_wallets = microservice("http://public_api/getMe", {"token": token}, "result.wallets") self.assertEqual([{ "balance": 100.0, "base_currency": 1, "login": "******" }, { "balance": 0.0, "base_currency": 4, "login": "******" }], user_wallets) # Awesome!!! 100$!!! =) # We need CNY for travelling though... no problem - using public api again we can make a transfer: # But wait the minute... our platform doesn't know anything about current convertion rates yet... # Let's fix this via our private-api too: update_dt = datetime.now().strftime("%c") updating_convertion_rates = microservice( "http://private_api/saveRatesBulk", { "data": [ { "base_currency": 2, "value": 1.24, "datetime": update_dt }, # 1EUR = 1.24USD { "base_currency": 4, "value": 0.25, "datetime": update_dt }, # 1CNY = 0.25USD ] }, "result") self.assertTrue(updating_convertion_rates) # And now, as user, we need to know current convertion rates and see if it works for us: # We are going to transfer USD to CNY, so: convertion_rates = microservice("http://public_api/getConvertionRates", { "token": token, "from_base_currency": 1, "to_base_currency": 4, }, "result") cny_uuid = convertion_rates["conversion_rate2"]["uuid"] self.assertDictEqual( { "conversion_rate1": { "uuid": None, "value": 1, "datetime": None, "base_currency": 1 }, "conversion_rate2": { "uuid": cny_uuid, "value": 0.25, "datetime": update_dt, "base_currency": 4 } }, convertion_rates) # I hope that front-end will represent this information in a more understandable way... =) # But, let's make our transfer already! transfer_result = microservice( "http://public_api/transferMoney", { "token": token, "from_base_currency": 1, "to_login": "******", "to_base_currency": 4, "amount": 100, "conversion_rate_uuid_1": None, "conversion_rate_uuid_2": cny_uuid # this is important, this should not be too old (< 30 seconds) }, "result") tx_uuid = transfer_result["uuid"] tx_datetime = transfer_result["datetime"] # Final checking: user_wallets = microservice("http://public_api/getMe", {"token": token}, "result.wallets") self.assertEqual([{ "balance": 0.0, "base_currency": 1, "login": "******" }, { "balance": 400.0, "base_currency": 4, "login": "******" }], user_wallets) # And last thing to check... getting reports on transactions via private api: transactions_history = microservice( "http://private_api/getTransactions", {"login": "******"}, "result") self.assertDictEqual( { "incoming": [[tx_uuid, "MyLogin", 4, 400.0, cny_uuid, tx_datetime]], "outgoing": [[tx_uuid, "MyLogin", 1, 100.0, '', tx_datetime]], }, transactions_history) # Aaand downloading csv report: import requests res = requests.post("http://private_api/getTransactionsCsvReport", json={"login": "******"}) # Looks like csv and should be downloadable: self.assertEqual("application/vnd.ms-excel", res.headers.get("Content-Type")) self.assertEqual("attachment; filename=transactions-MyLogin.csv", res.headers.get("Content-Disposition")) # What about content: csv_content = res.content.decode() lines = csv_content.split("\r\n") csv_header = lines.pop(0) body = [line.split(",") for line in lines] self.assertEqual([ "tx_uuid", "login", "base_currency", "amount", "convertion_rate_uuid", "tx_datetime", "mode" ], csv_header.split(",")) self.assertIn( [tx_uuid, "MyLogin", "4", "400.0", cny_uuid, tx_datetime, "+"], body) self.assertIn([tx_uuid, "MyLogin", "1", "100.0", "", tx_datetime, "-"], body)