From 352520a2bd4ac066e90587e44d8b818043407917 Mon Sep 17 00:00:00 2001 From: stuppie Date: Fri, 21 Aug 2026 16:19:25 -0600 Subject: Use a BusinessPayoutEventCreate model so we dont have all of these optional int warnings. cleaner --- generalresearch/managers/thl/payout.py | 118 +++++++++++++++------------------ generalresearch/models/thl/payout.py | 26 +++----- pyproject.toml | 3 + tests/managers/thl/test_payout.py | 96 +++++++++++++-------------- 4 files changed, 111 insertions(+), 132 deletions(-) diff --git a/generalresearch/managers/thl/payout.py b/generalresearch/managers/thl/payout.py index 0efbf99..8bc6843 100644 --- a/generalresearch/managers/thl/payout.py +++ b/generalresearch/managers/thl/payout.py @@ -1,10 +1,7 @@ from __future__ import annotations -from collections import defaultdict from collections.abc import Collection -from datetime import datetime, timezone -from random import choice as rand_choice -from random import randint +from datetime import UTC, datetime from typing import Any from uuid import uuid4 @@ -17,7 +14,6 @@ from pydantic import AwareDatetime, NonNegativeInt, PositiveInt from generalresearch.currency import USDCent from generalresearch.decorators import LOG from generalresearch.managers.base import ( - Permission, PostgresManagerWithRedis, ) from generalresearch.managers.thl.ledger_manager.exceptions import ( @@ -38,6 +34,7 @@ from generalresearch.models.thl.ledger import ( from generalresearch.models.thl.payout import ( BrokerageProductPayoutEvent, BusinessPayoutEvent, + BusinessPayoutEventCreate, PayoutEvent, UserPayoutEvent, ) @@ -47,8 +44,6 @@ from generalresearch.models.thl.wallet.cashout_method import ( CashMailOrderData, CashoutRequestInfo, ) -from generalresearch.pg_helper import PostgresConfig -from generalresearch.redis_helper import RedisConfig class PayoutEventManager(PostgresManagerWithRedis): @@ -100,14 +95,13 @@ class PayoutEventManager(PostgresManagerWithRedis): with self.pg_config.make_connection() as conn: with conn.cursor() as c: c.execute(query=query, params=d) - assert ( - c.rowcount == 1 - ), "Nothing was updated! Are you sure this payout_event exists?" + assert c.rowcount == 1, ( + "Nothing was updated! Are you sure this payout_event exists?" + ) conn.commit() class UserPayoutEventManager(PayoutEventManager): - def get_by_uuid(self, pe_uuid: UUIDStr) -> UserPayoutEvent: res = self.pg_config.execute_sql_query( @@ -293,7 +287,7 @@ class UserPayoutEventManager(PayoutEventManager): account_reference_uuid=account_reference_uuid, cashout_method_uuid=cashout_method_uuid, description=description, - created=created or datetime.now(tz=timezone.utc), + created=created or datetime.now(tz=UTC), amount=amount, status=status or PayoutStatus.PENDING, ext_ref_id=ext_ref_id, @@ -391,7 +385,7 @@ class BrokerageProductPayoutEventManager(PayoutEventManager): bp_wallet_account = thl_ledger_manager.get_account_or_create_bp_wallet_by_uuid( product_uuid=product_id ) - entry = [x for x in tx.entries if x.direction == Direction.DEBIT][0] + entry = next(x for x in tx.entries if x.direction == Direction.DEBIT) if entry.account_uuid != bp_wallet_account.uuid: raise ValueError( f"Found existing tx with tag: {tag}, but for a different account!" @@ -571,7 +565,7 @@ class BrokerageProductPayoutEventManager(PayoutEventManager): """) from e self.update(payout_event=bp_pe, status=PayoutStatus.FAILED) raise - except Exception as e: + except Exception: self.update(payout_event=bp_pe, status=PayoutStatus.FAILED) raise @@ -603,7 +597,6 @@ class BrokerageProductPayoutEventManager(PayoutEventManager): class BusinessPayoutEventManager(PostgresManagerWithRedis): - def __init__(self, *arg, **kwargs): super().__init__(*arg, **kwargs) self.bp_pe_manager = BrokerageProductPayoutEventManager(*arg, **kwargs) @@ -637,9 +630,9 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): for bp_payout in d["bp_payouts"]: bp_payout["created"] = datetime.fromisoformat(bp_payout["created"]) bpe = BusinessPayoutEvent.model_validate(d) - assert ( - bpe.bp_payouts is not None and len(bpe.bp_payouts) > 0 - ), "No BP payouts found for this Business Payout Event. This shouldn't happen!" + assert bpe.bp_payouts is not None and len(bpe.bp_payouts) > 0, ( + "No BP payouts found for this Business Payout Event. This shouldn't happen!" + ) return bpe def filter_by( @@ -647,7 +640,7 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): business_uuids: Collection[UUIDStr] | None = None, ) -> list[BusinessPayoutEvent]: - params = dict() + params = {} filters = [] if business_uuids is not None: filters.append("business_id = ANY(%(business_uuids)s)") @@ -684,9 +677,9 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): for bp_payout in row["bp_payouts"]: bp_payout["created"] = datetime.fromisoformat(bp_payout["created"]) bpe = BusinessPayoutEvent.model_validate(row) - assert ( - bpe.bp_payouts is not None and len(bpe.bp_payouts) > 0 - ), "No BP payouts found for this Business Payout Event. This shouldn't happen!" + assert bpe.bp_payouts is not None and len(bpe.bp_payouts) > 0, ( + "No BP payouts found for this Business Payout Event. This shouldn't happen!" + ) bpes.append(bpe) return bpes @@ -703,9 +696,9 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): for bp_pe in bpe.bp_payouts ] txs = thl_lm.get_tx_ids_by_tags(tags=tags) - assert len(txs) == len( - bpe.bp_payouts - ), f"Expected {len(bpe.bp_payouts)} BP payouts but found {len(txs)}!" + assert len(txs) == len(bpe.bp_payouts), ( + f"Expected {len(bpe.bp_payouts)} BP payouts but found {len(txs)}!" + ) return True def resume_failed_business_payout( @@ -743,7 +736,7 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): LOG.warning( "Nothing to do! Business Payout is COMPLETE and all Brokerage Product payouts are also COMPLETE!" ) - return None + return for bp_pe in bpe.bp_payouts: if bp_pe.status in {PayoutStatus.PENDING, PayoutStatus.FAILED}: @@ -760,7 +753,7 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): self.validate_business_payout_in_ledger(ext_ref_id=ext_ref_id, thl_lm=thl_lm) self.update_business_payout_event(pk=bpe.id, status=PayoutStatus.COMPLETE) - return None + return def get_business_payout_events_for_business( self, @@ -831,9 +824,9 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): shortfall: int = int(target_amount) - w_df["deduction"].sum() w_df["remaining_balance"] = w_df["available_balance"] - w_df["deduction"] - assert w_df[ - w_df["deduction"] > w_df["available_balance"] - ].empty, "Trying to deduct more from an Product than what is available" + assert w_df[w_df["deduction"] > w_df["available_balance"]].empty, ( + "Trying to deduct more from an Product than what is available" + ) return w_df @@ -882,7 +875,6 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): shortage = int(amount) - allocation.sum() if shortage > 0: - assert shortage < len(remainders), ( "The shortage cent amount must be less than or equal to the " "length of the remainders if we intend of taking a penny " @@ -902,13 +894,13 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): def create_business_payout_event( self, - bpe: BusinessPayoutEvent, - ): + bpe: BusinessPayoutEventCreate, + ) -> BusinessPayoutEvent: + assert isinstance(bpe, BusinessPayoutEventCreate) assert bpe.bp_payouts, "Must provide at least one BP Payout" - assert {bp_pe.status for bp_pe in bpe.bp_payouts} == { - PayoutStatus.PENDING - }, "All BP Payouts must be PENDING" - assert bpe.id is None, "Cannot create a BusinessPayoutEvent with an existing ID" + assert {bp_pe.status for bp_pe in bpe.bp_payouts} == {PayoutStatus.PENDING}, ( + "All BP Payouts must be PENDING" + ) INSERT_SUPPLIER_PAYOUT = """ INSERT INTO supplier_payout ( business_id, created, amount, @@ -945,7 +937,6 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): ) raise supplier_payout_pk = c.fetchone()["id"] - bpe.id = supplier_payout_pk for bp_pe in bpe.bp_payouts: c.execute( INSERT_BP_PAYOUT, @@ -953,6 +944,7 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): | {"supplier_payout_id": supplier_payout_pk}, ) conn.commit() + return BusinessPayoutEvent(id=supplier_payout_pk, **bpe.model_dump()) def create_from_ach_or_wire( self, @@ -978,12 +970,10 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): if created: LOG.warning("Payouts in the past, require the parquet files to be rebuilt.") - assert created.tzinfo == timezone.utc, "created must be UTC" - assert created < datetime.now( - tz=timezone.utc - ), "created must be in the past" + assert created.tzinfo == UTC, "created must be UTC" + assert created < datetime.now(tz=UTC), "created must be in the past" else: - created = datetime.now(tz=timezone.utc) + created = datetime.now(tz=UTC) # Gather the total amount available balance from each and put into # a simple DF. We're using the available balance because we need it @@ -1003,9 +993,9 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): # Can't pay any Products that don't have a remaining balance df = df[df["remaining_balance"] > 0].copy() - assert ( - df.deduction.sum() == business.balance.recoup - ), "recoup_proportional failure" + assert df.deduction.sum() == business.balance.recoup, ( + "recoup_proportional failure" + ) df["issue_amount"] = BusinessPayoutEventManager.distribute_amount( df=df, amount=amount @@ -1031,21 +1021,6 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): bp_wallets = thl_lm.get_accounts(qualified_names) wallet_lookup = {bpw.reference_uuid: bpw.uuid for bpw in bp_wallets} - bpe = BusinessPayoutEvent( - id=None, - business_id=business.uuid, - payout_type=PayoutType.ACH, - amount=amount, - created=created, - ext_ref_id=transaction_id, - # The ACH payment was sent! We haven't yet recorded it - # in the ledger, but it was sent by the bank. This - # is kind of ambiguous the meaning, we'll say it - # is not yet COMPLETE b/c the bp payouts - # haven't all been created yet. - status=PayoutStatus.APPROVED, - ) - bp_payouts: list[BrokerageProductPayoutEvent] = [] for product_id, item in amounts.items(): product = product_lookup[product_id] @@ -1062,10 +1037,24 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): debit_account_uuid=wallet_lookup[product_id], ) ) - bpe.bp_payouts = bp_payouts + + bpe_create = BusinessPayoutEventCreate( + business_id=business.uuid, + payout_type=PayoutType.ACH, + amount=amount, + created=created, + ext_ref_id=transaction_id, + # The ACH payment was sent! We haven't yet recorded it + # in the ledger, but it was sent by the bank. This + # is kind of ambiguous the meaning, we'll say it + # is not yet COMPLETE b/c the bp payouts + # haven't all been created yet. + status=PayoutStatus.APPROVED, + bp_payouts=bp_payouts, + ) # The supplier_payout db row and all event_payout (BP rows) are all # created in the same DB transaction. - self.create_business_payout_event(bpe=bpe) + bpe = self.create_business_payout_event(bpe=bpe_create) assert bpe.id is not None, "Something failed creating BusinessPayoutEvent" # Now, go through each and create ledger txs. This is resumable @@ -1094,7 +1083,6 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): ) assert c.rowcount == 1, f"{id=} not found" conn.commit() - return None def create_bp_payout_event( self, @@ -1109,7 +1097,7 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): for tests. However, instead of just making a naked BP payout, it created the business payout also, but with just one BP Payout """ - created = created or datetime.now(tz=timezone.utc) + created = created or datetime.now(tz=UTC) account = thl_ledger_manager.get_account( f"{thl_ledger_manager.currency.value}:bp_wallet:{product.uuid}" ) diff --git a/generalresearch/models/thl/payout.py b/generalresearch/models/thl/payout.py index 835c3b9..ce8a809 100644 --- a/generalresearch/models/thl/payout.py +++ b/generalresearch/models/thl/payout.py @@ -1,31 +1,28 @@ from __future__ import annotations import json -from datetime import datetime, timezone -from typing import Collection +from datetime import UTC, datetime +from typing import Self from uuid import uuid4 from pydantic import ( BaseModel, + ConfigDict, Field, PositiveInt, computed_field, field_validator, model_validator, - ConfigDict, ) from pydantic.json_schema import SkipJsonSchema -from typing_extensions import Self from generalresearch.currency import USDCent from generalresearch.models.custom_types import AwareDatetimeISO, UUIDStr, UUIDStrCoerce from generalresearch.models.thl.definitions import PayoutStatus -from generalresearch.models.thl.ledger import OrderBy from generalresearch.models.thl.wallet import PayoutType from generalresearch.models.thl.wallet.cashout_method import ( CashMailOrderData, ) -from generalresearch.redis_helper import RedisConfig class PayoutEvent(BaseModel): @@ -63,7 +60,7 @@ class PayoutEvent(BaseModel): ) created: AwareDatetimeISO = Field( - default_factory=lambda: datetime.now(tz=timezone.utc) + default_factory=lambda: datetime.now(tz=UTC) ) # In the smallest unit of the currency being transacted. For USD, this @@ -223,13 +220,11 @@ class BrokerageProductPayoutEvent(PayoutEvent): return self.amount_usd.to_usd_str() -class BusinessPayoutEvent(BaseModel): +class BusinessPayoutEventCreate(BaseModel): """A single payout event to a supplier Business.""" model_config = ConfigDict(validate_assignment=True) - id: SkipJsonSchema[PositiveInt | None] = Field(exclude=True, default=None) - # Used for holding a *unique*, external, payout-type-specific identifier. ext_ref_id: str = Field(title="Unique external reference ID") @@ -239,7 +234,7 @@ class BusinessPayoutEvent(BaseModel): ) created: AwareDatetimeISO = Field( - default_factory=lambda: datetime.now(tz=timezone.utc) + default_factory=lambda: datetime.now(tz=UTC) ) # In the smallest unit of the currency being transacted. For USD, this @@ -274,8 +269,7 @@ class BusinessPayoutEvent(BaseModel): "returned from the external payout provider.", ) - bp_payouts: list[BrokerageProductPayoutEvent] | None = Field( - default=None, + bp_payouts: list[BrokerageProductPayoutEvent] = Field( description="The list of Brokerage Product Payouts that this Business Payout includes", min_length=1, ) @@ -317,9 +311,6 @@ class BusinessPayoutEvent(BaseModel): @model_validator(mode="after") def validate_bp_payouts(self) -> Self: - if not self.bp_payouts: - return self - bp_payout_amount = sum([p.amount for p in self.bp_payouts]) if bp_payout_amount != self.amount: raise ValueError( @@ -359,3 +350,6 @@ class BusinessPayoutEvent(BaseModel): json.dumps(self.order_data) if self.order_data is not None else None ) return d + +class BusinessPayoutEvent(BusinessPayoutEventCreate): + id: SkipJsonSchema[PositiveInt] = Field(exclude=True) diff --git a/pyproject.toml b/pyproject.toml index 183e271..dbdf3b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,3 +54,6 @@ include = ["generalresearch", "generalresearch.*", "test_utils", "test_utils.*"] [tool.pytest.ini_options] testpaths = ["tests"] addopts = "-v --tb=short" + +[tool.ruff] +target-version = "py314" \ No newline at end of file diff --git a/tests/managers/thl/test_payout.py b/tests/managers/thl/test_payout.py index b79a209..c4f20cd 100644 --- a/tests/managers/thl/test_payout.py +++ b/tests/managers/thl/test_payout.py @@ -1,33 +1,28 @@ +import io import logging import os -from datetime import datetime, timezone, timedelta +from datetime import UTC, datetime, timedelta from decimal import Decimal -from random import choice as rand_choice, randint -from typing import Optional +from random import choice as rand_choice +from random import randint from uuid import uuid4 -import io import pandas as pd import pytest -from generalresearch import pg_helper -from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager -from generalresearch.models.thl.product import Product -from generalresearch.models.thl.user import User from generalresearch.currency import USDCent -from generalresearch.managers.thl.ledger_manager.exceptions import ( - LedgerTransactionConditionFailedError, -) +from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager from generalresearch.managers.thl.payout import UserPayoutEventManager from generalresearch.models.thl.definitions import PayoutStatus -from generalresearch.models.thl.ledger import LedgerEntry, Direction +from generalresearch.models.thl.ledger import LedgerAccount from generalresearch.models.thl.payout import ( - BusinessPayoutEvent, BrokerageProductPayoutEvent, + BusinessPayoutEvent, + UserPayoutEvent, ) -from generalresearch.models.thl.payout import UserPayoutEvent +from generalresearch.models.thl.product import Product +from generalresearch.models.thl.user import User from generalresearch.models.thl.wallet import PayoutType -from generalresearch.models.thl.ledger import LedgerAccount logger = logging.getLogger() @@ -35,7 +30,6 @@ cashout_method_uuid = uuid4().hex class TestPayout: - def test_get_by_uuid_and_create( self, user, @@ -43,7 +37,6 @@ class TestPayout: thl_lm, utc_now, ): - user_account: LedgerAccount = thl_lm.get_account_or_create_user_wallet( user=user ) @@ -118,7 +111,7 @@ class TestPayout: product, thl_lm: ThlLedgerManager, brokerage_product_payout_event_manager, - utc_now + utc_now, ) -> BrokerageProductPayoutEvent: account = thl_lm.get_account_or_create_bp_wallet(product=product) bp_pe = BrokerageProductPayoutEvent( @@ -127,22 +120,22 @@ class TestPayout: payout_type=PayoutType.ACH, debit_account_uuid=account.uuid, cashout_method_uuid=brokerage_product_payout_event_manager.CASHOUT_METHOD_UUID, - created=utc_now + created=utc_now, ) params = bp_pe.model_dump_postgres() # This shouldn't exist. For testing only, so no supplier_payout - params['supplier_payout_id'] = None - thl_web_rw.execute_write(""" - INSERT INTO event_payout ( - uuid, debit_account_uuid, created, cashout_method_uuid, - amount, status, ext_ref_id, payout_type, order_data, - request_data, supplier_payout_id - ) VALUES ( - %(uuid)s, %(debit_account_uuid)s, %(created)s, %(cashout_method_uuid)s, - %(amount)s, %(status)s, %(ext_ref_id)s, %(payout_type)s, %(order_data)s, - %(request_data)s, %(supplier_payout_id)s - ); - """, params) + params["supplier_payout_id"] = None + thl_web_rw.execute_write( + """ + INSERT INTO event_payout (uuid, debit_account_uuid, created, cashout_method_uuid, + amount, status, ext_ref_id, payout_type, order_data, + request_data, supplier_payout_id) + VALUES (%(uuid)s, %(debit_account_uuid)s, %(created)s, %(cashout_method_uuid)s, + %(amount)s, %(status)s, %(ext_ref_id)s, %(payout_type)s, %(order_data)s, + %(request_data)s, %(supplier_payout_id)s); + """, + params, + ) return bp_pe def test_create_bp_payout_quick_dupe( @@ -254,22 +247,20 @@ class TestPayout: class TestPayoutEventManager: - pass class TestBusinessPayoutEventManager: - @pytest.fixture - def start(self) -> "datetime": - return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc) + def start(self) -> datetime: + return datetime(year=2018, month=3, day=14, hour=0, tzinfo=UTC) @pytest.fixture def offset(self) -> str: return "5d" @pytest.fixture - def duration(self) -> Optional["timedelta"]: + def duration(self) -> timedelta | None: return timedelta(days=10) def test_base( @@ -294,13 +285,16 @@ class TestBusinessPayoutEventManager: ach_id2 = uuid4().hex # ext_ref_id is required now - bp_payout_factory(product=p1,amount=USDCent(1),ext_ref_id="none") + bp_payout_factory(product=p1, amount=USDCent(1), ext_ref_id="none") - bp_payout_factory(product=p1,amount=USDCent(1),ext_ref_id=ach_id1) - with pytest.raises(expected_exception=ValueError, match="Cannot create a BusinessPayoutEvent with an existing transaction_id"): - bp_payout_factory(product=p1,amount=USDCent(25),ext_ref_id=ach_id1) + bp_payout_factory(product=p1, amount=USDCent(1), ext_ref_id=ach_id1) + with pytest.raises( + expected_exception=ValueError, + match="Cannot create a BusinessPayoutEvent with an existing transaction_id", + ): + bp_payout_factory(product=p1, amount=USDCent(25), ext_ref_id=ach_id1) - bp_payout_factory(product=p1,amount=USDCent(50),ext_ref_id=ach_id2) + bp_payout_factory(product=p1, amount=USDCent(50), ext_ref_id=ach_id2) business.prebuild_payouts( bpem=business_payout_event_manager, @@ -325,7 +319,7 @@ class TestBusinessPayoutEventManager: business_payout_event_manager, delete_ledger_db, create_main_accounts, - thl_lm, + thl_ledger_manager, thl_web_rr, product_factory, bp_payout_factory, @@ -336,7 +330,6 @@ class TestBusinessPayoutEventManager: pop_ledger_merge, client_no_amm, mnt_filepath, - lm, product_manager, start, business, @@ -347,7 +340,7 @@ class TestBusinessPayoutEventManager: p1: Product = product_factory(business=business) u1: User = user_factory(product=p1) - thl_lm.get_account_or_create_bp_wallet(product=p1) + thl_ledger_manager.get_account_or_create_bp_wallet(product=p1) # $250.00 to work with for idx in range(1, 10): @@ -360,7 +353,9 @@ class TestBusinessPayoutEventManager: ach_id1 = uuid4().hex ach_id2 = uuid4().hex - with pytest.raises(expected_exception=AssertionError, match="No Business Payout found"): + with pytest.raises( + expected_exception=AssertionError, match="No Business Payout found" + ): business_payout_event_manager.update_ext_reference_ids( new_value=ach_id2, current_value=ach_id1, @@ -371,7 +366,7 @@ class TestBusinessPayoutEventManager: pop_ledger_merge.build(client=client_no_amm, ledger_coll=ledger_collection) business.prebuild_balance( thl_pg_config=thl_web_rr, - lm=lm, + lm=thl_ledger_manager, ds=mnt_filepath, client=client_no_amm, pop_ledger=pop_ledger_merge, @@ -381,7 +376,7 @@ class TestBusinessPayoutEventManager: business=business, amount=USDCent(100_01), pm=product_manager, - thl_lm=thl_lm, + thl_lm=thl_ledger_manager, transaction_id=ach_id1, ) assert isinstance(res, BusinessPayoutEvent) @@ -394,7 +389,9 @@ class TestBusinessPayoutEventManager: current_value=ach_id1, ) - with pytest.raises(expected_exception=AssertionError, match="No Business Payout found"): + with pytest.raises( + expected_exception=AssertionError, match="No Business Payout found" + ): business_payout_event_manager.get_by_ext_ref_id(ext_ref_id=ach_id1) assert business_payout_event_manager.get_by_ext_ref_id(ext_ref_id=ach_id2) @@ -718,7 +715,6 @@ class TestBusinessPayoutEventManager: # ) assert 1 == 0 - return None def test_ach_payment( self, @@ -783,8 +779,6 @@ class TestBusinessPayoutEventManager: amount=USDCent(475), # 95% of $5.00 ext_ref_id=ach_id1, created=start + timedelta(days=1, minutes=1), - skip_wallet_balance_check=True, - skip_one_per_day_check=True, ) adj_to_fail_with_tx_factory( session=s1, -- cgit v1.2.3