From 5845467e766c91b6624b1f93bdb548a4cb984384 Mon Sep 17 00:00:00 2001 From: staticdev Date: Thu, 21 Apr 2022 20:32:09 +0200 Subject: [PATCH 1/2] Fix bug novas regras 2-2-2021 --- src/irpf_investidor/b3.py | 42 ++++++++++++++++++++-------- src/irpf_investidor/report_reader.py | 9 +++--- tests/test_b3.py | 31 ++++++++++++++------ tests/test_report_reader.py | 4 +-- 4 files changed, 59 insertions(+), 27 deletions(-) diff --git a/src/irpf_investidor/b3.py b/src/irpf_investidor/b3.py index a501c38..ed853c4 100644 --- a/src/irpf_investidor/b3.py +++ b/src/irpf_investidor/b3.py @@ -68,14 +68,17 @@ datetime.datetime(2020, 10, 1), datetime.datetime(2020, 11, 1), 0.00003219 ), RatePeriod( - datetime.datetime(2020, 11, 1), datetime.datetime(2020, 12, 1), 0.00003247 + datetime.datetime(2020, 11, 1), datetime.datetime(2021, 2, 2), 0.00003247 ), RatePeriod( - datetime.datetime(2020, 12, 1), datetime.datetime(2022, 1, 1), 0.00003020 + datetime.datetime(2021, 2, 2), datetime.datetime(2022, 1, 1), 0.00005 ), ] EMOLUMENTOS_AUCTION_RATE = 0.00007 -LIQUIDACAO_RATE = 0.000275 +LIQUIDACAO_PERIODS = [ + RatePeriod(datetime.datetime(2019, 1, 3), datetime.datetime(2021, 2, 2), 0.000275), + RatePeriod(datetime.datetime(2021, 2, 2), datetime.datetime(2022, 1, 1), 0.00025), +] AssetInfo = collections.namedtuple("AssetInfo", ["category", "cnpj"]) @@ -716,26 +719,41 @@ def get_asset_info(code: str) -> AssetInfo: return AssetInfo("NOT_FOUND", "") -def get_trading_rate() -> float: - """Return fixes trading rate. +def get_liquidacao_rates(dates: list[datetime.datetime]) -> list[float]: + """Get the list of liquidação rates. + + Args: + dates: list of trade days. Returns: - float: constant float. + list of rates. """ - return LIQUIDACAO_RATE + rates = [] + last_period = 0 + for date in dates: + for idx_period, period in enumerate( + LIQUIDACAO_PERIODS[last_period:], start=last_period + ): + if period.start_date <= date <= period.end_date: + last_period = idx_period + rates.append(period.rate) + break + else: + sys.exit(f"Nenhum período de liquidação encontrado para a data: {date}") + return rates -def get_emoluments_rates( +def get_emolumentos_rates( dates: list[datetime.datetime], auction_trades: list[int] ) -> list[float]: - """Get the list of emuluments rates. + """Get the list of emolumentos rates. Args: - dates (List[datetime.datetime]): list of trade days. - auction_trades (List[int]): list of indexes of trades in auction. + dates: list of trade days. + auction_trades: list of indexes of trades in auction. Returns: - List[float]: list of rates. + list of rates. """ rates = [] last_period = 0 diff --git a/src/irpf_investidor/report_reader.py b/src/irpf_investidor/report_reader.py index f16157e..e3f7be3 100644 --- a/src/irpf_investidor/report_reader.py +++ b/src/irpf_investidor/report_reader.py @@ -182,18 +182,19 @@ def calculate_taxes(df: pd.DataFrame, auction_trades: list[int]) -> pd.DataFrame """Calculate emolumentos and liquidação taxes based on reference year. Args: - df (pd.DataFrame): grouped trades. - auction_trades (List[int]): list of auction trades. + df: grouped trades. + auction_trades: list of auction trades. Returns: pd.DataFrame: trades with two new columns of calculated taxes. """ df["Liquidação (R$)"] = ( - df["Valor Total (R$)"] * irpf_investidor.b3.get_trading_rate() + df["Valor Total (R$)"] + * irpf_investidor.b3.get_liquidacao_rates(df["Data Negócio"].array) ).apply(round_down_money) df["Emolumentos (R$)"] = ( df["Valor Total (R$)"] - * irpf_investidor.b3.get_emoluments_rates( + * irpf_investidor.b3.get_emolumentos_rates( df["Data Negócio"].array, auction_trades ) ).apply(round_down_money) diff --git a/tests/test_b3.py b/tests/test_b3.py index aa32823..570721c 100644 --- a/tests/test_b3.py +++ b/tests/test_b3.py @@ -40,19 +40,32 @@ def test_get_asset_info_not_found() -> None: assert asset_info.category == "NOT_FOUND" -def test_get_trading_rate() -> None: - """Return fixed float value.""" - assert b3.get_trading_rate() == 0.000275 +def test_get_liquidacao_rates_error() -> None: + """Raise `SystemExit` when date is not found.""" + series = [datetime.datetime(1930, 2, 20)] + with pytest.raises(SystemExit): + assert b3.get_liquidacao_rates(series) + + +def test_get_liquidacao_rates_success() -> None: + """Return date rates.""" + series = [ + datetime.datetime(2019, 2, 20), + datetime.datetime(2021, 12, 31), + ] + expected = [0.000275, 0.00025] + result = b3.get_liquidacao_rates(series) + assert result == expected -def test_get_emoluments_rates_error() -> None: +def test_get_emolumentos_rates_error() -> None: """Raise `SystemExit` when date is not found.""" series = [datetime.datetime(1930, 2, 20)] with pytest.raises(SystemExit): - assert b3.get_emoluments_rates(series, []) + assert b3.get_emolumentos_rates(series, []) -def test_get_emoluments_rates_sucess_no_auction() -> None: +def test_get_emolumentos_rates_sucess_no_auction() -> None: """Return date rates.""" series = [ datetime.datetime(2019, 2, 20), @@ -61,11 +74,11 @@ def test_get_emoluments_rates_sucess_no_auction() -> None: datetime.datetime(2019, 12, 31), ] expected = [0.00004032, 0.00004157, 0.00004408, 0.00003802] - result = b3.get_emoluments_rates(series, []) + result = b3.get_emolumentos_rates(series, []) assert result == expected -def test_get_emoluments_rates_sucess_with_auction() -> None: +def test_get_emolumentos_rates_sucess_with_auction() -> None: """Return date rates and auction rates.""" series = [ datetime.datetime(2019, 2, 20), @@ -74,7 +87,7 @@ def test_get_emoluments_rates_sucess_with_auction() -> None: datetime.datetime(2019, 12, 31), ] expected = [0.00004032, 0.00007, 0.00007, 0.00003802] - result = b3.get_emoluments_rates(series, [1, 2]) + result = b3.get_emolumentos_rates(series, [1, 2]) assert result == expected diff --git a/tests/test_report_reader.py b/tests/test_report_reader.py index 237c6a2..074ee6f 100644 --- a/tests/test_report_reader.py +++ b/tests/test_report_reader.py @@ -208,9 +208,9 @@ def test_group_trades() -> None: def test_calculate_taxes_2019(mocker: MockerFixture) -> None: """Return calculated taxes.""" - mocker.patch("irpf_investidor.b3.get_trading_rate", return_value=0.000275) + mocker.patch("irpf_investidor.b3.get_liquidacao_rates", return_value=0.000275) mocker.patch( - "irpf_investidor.b3.get_emoluments_rates", + "irpf_investidor.b3.get_emolumentos_rates", return_value=[0.00004105, 0.00004105, 0.00004105], ) df = pd.DataFrame( From b7a9fe4023ab3546628a27bdf51f003aa8f69d2a Mon Sep 17 00:00:00 2001 From: staticdev Date: Thu, 21 Apr 2022 21:22:54 +0200 Subject: [PATCH 2/2] Fix black formatting --- src/irpf_investidor/b3.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/irpf_investidor/b3.py b/src/irpf_investidor/b3.py index ed853c4..03590db 100644 --- a/src/irpf_investidor/b3.py +++ b/src/irpf_investidor/b3.py @@ -70,9 +70,7 @@ RatePeriod( datetime.datetime(2020, 11, 1), datetime.datetime(2021, 2, 2), 0.00003247 ), - RatePeriod( - datetime.datetime(2021, 2, 2), datetime.datetime(2022, 1, 1), 0.00005 - ), + RatePeriod(datetime.datetime(2021, 2, 2), datetime.datetime(2022, 1, 1), 0.00005), ] EMOLUMENTOS_AUCTION_RATE = 0.00007 LIQUIDACAO_PERIODS = [