meta_receipt: Use check-id as fallback metadata for outgoing checks.
When we send checks, we don't have a check document anywhere (for security reasons), we just note the check number. Update the validation to match. RT#10507.
This commit is contained in:
		
							parent
							
								
									c712105bed
								
							
						
					
					
						commit
						6658696d06
					
				
					 2 changed files with 123 additions and 13 deletions
				
			
		| 
						 | 
					@ -14,14 +14,23 @@
 | 
				
			||||||
# You should have received a copy of the GNU Affero General Public License
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
					# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from decimal import Decimal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import core
 | 
					from . import core
 | 
				
			||||||
from .. import config as configmod
 | 
					from .. import config as configmod
 | 
				
			||||||
from .. import data
 | 
					from .. import data
 | 
				
			||||||
from .. import errors as errormod
 | 
					from .. import errors as errormod
 | 
				
			||||||
from ..beancount_types import (
 | 
					from ..beancount_types import (
 | 
				
			||||||
 | 
					    MetaKey,
 | 
				
			||||||
    Transaction,
 | 
					    Transaction,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from typing import (
 | 
				
			||||||
 | 
					    Callable,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_CheckMethod = Callable[[Transaction, data.Posting, MetaKey], None]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MetaReceipt(core._RequireLinksPostingMetadataHook):
 | 
					class MetaReceipt(core._RequireLinksPostingMetadataHook):
 | 
				
			||||||
    METADATA_KEY = 'receipt'
 | 
					    METADATA_KEY = 'receipt'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +44,13 @@ class MetaReceipt(core._RequireLinksPostingMetadataHook):
 | 
				
			||||||
            and abs(post.units.number) >= self.payment_threshold
 | 
					            and abs(post.units.number) >= self.payment_threshold
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_check_id(self, txn: Transaction, post: data.Posting, key: MetaKey) -> None:
 | 
				
			||||||
 | 
					        value = post.meta.get(key)
 | 
				
			||||||
 | 
					        if (not isinstance(value, Decimal)
 | 
				
			||||||
 | 
					            or value < 1
 | 
				
			||||||
 | 
					            or value % 1):
 | 
				
			||||||
 | 
					            raise errormod.InvalidMetadataError(txn, key, value, post, Decimal)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post_run(self, txn: Transaction, post: data.Posting) -> errormod.Iter:
 | 
					    def post_run(self, txn: Transaction, post: data.Posting) -> errormod.Iter:
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self._check_links(txn, post, self.METADATA_KEY)
 | 
					            self._check_links(txn, post, self.METADATA_KEY)
 | 
				
			||||||
| 
						 | 
					@ -50,7 +66,12 @@ class MetaReceipt(core._RequireLinksPostingMetadataHook):
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            post_amount = -1
 | 
					            post_amount = -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check_method: _CheckMethod = self._check_links
 | 
				
			||||||
        if post.account.is_checking():
 | 
					        if post.account.is_checking():
 | 
				
			||||||
 | 
					            if post_amount == -1:
 | 
				
			||||||
 | 
					                check_method = self._check_check_id
 | 
				
			||||||
 | 
					                fallback_key = 'check-id'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
                fallback_key = 'check'
 | 
					                fallback_key = 'check'
 | 
				
			||||||
        elif post.account.is_credit_card() and post_amount == -1:
 | 
					        elif post.account.is_credit_card() and post_amount == -1:
 | 
				
			||||||
            fallback_key = 'invoice'
 | 
					            fallback_key = 'invoice'
 | 
				
			||||||
| 
						 | 
					@ -61,7 +82,7 @@ class MetaReceipt(core._RequireLinksPostingMetadataHook):
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self._check_links(txn, post, fallback_key)
 | 
					            check_method(txn, post, fallback_key)
 | 
				
			||||||
        except errormod.InvalidMetadataError as fallback_error:
 | 
					        except errormod.InvalidMetadataError as fallback_error:
 | 
				
			||||||
            if receipt_error.value is None and fallback_error.value is None:
 | 
					            if receipt_error.value is None and fallback_error.value is None:
 | 
				
			||||||
                yield errormod.InvalidMetadataError(
 | 
					                yield errormod.InvalidMetadataError(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,17 +48,21 @@ class AccountForTesting(typing.NamedTuple):
 | 
				
			||||||
        return f"{self.name} missing {TEST_KEY}{rest}"
 | 
					        return f"{self.name} missing {TEST_KEY}{rest}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def wrong_type_message(self, wrong_value, key=TEST_KEY):
 | 
					    def wrong_type_message(self, wrong_value, key=TEST_KEY):
 | 
				
			||||||
        return  "{} has wrong type of {}: expected str but is a {}".format(
 | 
					        expect_type = 'Decimal' if key == 'check-id' else 'str'
 | 
				
			||||||
 | 
					        return  "{} has wrong type of {}: expected {} but is a {}".format(
 | 
				
			||||||
            self.name,
 | 
					            self.name,
 | 
				
			||||||
            key,
 | 
					            key,
 | 
				
			||||||
 | 
					            expect_type,
 | 
				
			||||||
            type(wrong_value).__name__,
 | 
					            type(wrong_value).__name__,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ACCOUNTS = [AccountForTesting._make(t) for t in [
 | 
					ACCOUNTS = [AccountForTesting._make(t) for t in [
 | 
				
			||||||
    ('Assets:Bank:CheckCard', PostType.BOTH, 'check'),
 | 
					    ('Assets:Bank:CheckCard', PostType.CREDIT, 'check'),
 | 
				
			||||||
 | 
					    ('Assets:Bank:CheckCard', PostType.DEBIT, 'check-id'),
 | 
				
			||||||
    ('Assets:Cash', PostType.BOTH, None),
 | 
					    ('Assets:Cash', PostType.BOTH, None),
 | 
				
			||||||
    ('Assets:Checking', PostType.BOTH, 'check'),
 | 
					    ('Assets:Checking', PostType.CREDIT, 'check'),
 | 
				
			||||||
 | 
					    ('Assets:Checking', PostType.DEBIT, 'check-id'),
 | 
				
			||||||
    ('Assets:PayPal', PostType.CREDIT, 'paypal-id'),
 | 
					    ('Assets:PayPal', PostType.CREDIT, 'paypal-id'),
 | 
				
			||||||
    ('Assets:PayPal', PostType.DEBIT, None),
 | 
					    ('Assets:PayPal', PostType.DEBIT, None),
 | 
				
			||||||
    ('Assets:Savings', PostType.BOTH, None),
 | 
					    ('Assets:Savings', PostType.BOTH, None),
 | 
				
			||||||
| 
						 | 
					@ -66,9 +70,12 @@ ACCOUNTS = [AccountForTesting._make(t) for t in [
 | 
				
			||||||
    ('Liabilities:CreditCard', PostType.DEBIT, 'invoice'),
 | 
					    ('Liabilities:CreditCard', PostType.DEBIT, 'invoice'),
 | 
				
			||||||
]]
 | 
					]]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ACCOUNTS_WITH_FALLBACKS = [acct for acct in ACCOUNTS if acct.fallback_meta]
 | 
					ACCOUNTS_WITH_LINK_FALLBACK = [acct for acct in ACCOUNTS
 | 
				
			||||||
 | 
					                               if acct.fallback_meta and acct.fallback_meta != 'check-id']
 | 
				
			||||||
 | 
					ACCOUNTS_WITH_CHECK_ID_FALLBACK = [acct for acct in ACCOUNTS
 | 
				
			||||||
 | 
					                                   if acct.fallback_meta == 'check-id']
 | 
				
			||||||
ACCOUNTS_WITHOUT_FALLBACKS = [acct for acct in ACCOUNTS if not acct.fallback_meta]
 | 
					ACCOUNTS_WITHOUT_FALLBACKS = [acct for acct in ACCOUNTS if not acct.fallback_meta]
 | 
				
			||||||
KNOWN_FALLBACKS = {acct.fallback_meta for acct in ACCOUNTS_WITH_FALLBACKS}
 | 
					KNOWN_FALLBACKS = {acct.fallback_meta for acct in ACCOUNTS if acct.fallback_meta}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# These are mostly fill-in values.
 | 
					# These are mostly fill-in values.
 | 
				
			||||||
# We don't need to run every test on every value for these, just enough to
 | 
					# We don't need to run every test on every value for these, just enough to
 | 
				
			||||||
| 
						 | 
					@ -86,6 +93,14 @@ NOT_REQUIRED_ACCOUNTS = itertools.cycle([
 | 
				
			||||||
    'Liabilities:UnearnedIncome:Donations',
 | 
					    'Liabilities:UnearnedIncome:Donations',
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CHECK_IDS = (decimal.Decimal(n) for n in itertools.count(1))
 | 
				
			||||||
 | 
					def BAD_CHECK_IDS():
 | 
				
			||||||
 | 
					    # Valid check-id values are positive integers
 | 
				
			||||||
 | 
					    yield decimal.Decimal(0)
 | 
				
			||||||
 | 
					    yield -next(CHECK_IDS)
 | 
				
			||||||
 | 
					    yield next(CHECK_IDS) * decimal.Decimal('1.1')
 | 
				
			||||||
 | 
					BAD_CHECK_IDS = BAD_CHECK_IDS()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check(hook, test_acct, other_acct, expected, *,
 | 
					def check(hook, test_acct, other_acct, expected, *,
 | 
				
			||||||
          txn_meta={}, post_meta={}, check_type=PostType.BOTH, min_amt=0):
 | 
					          txn_meta={}, post_meta={}, check_type=PostType.BOTH, min_amt=0):
 | 
				
			||||||
    check_type &= test_acct.required_types
 | 
					    check_type &= test_acct.required_types
 | 
				
			||||||
| 
						 | 
					@ -167,7 +182,7 @@ def test_bad_type_receipt_on_txn(hook, test_acct, other_acct, value):
 | 
				
			||||||
          txn_meta={TEST_KEY: value})
 | 
					          txn_meta={TEST_KEY: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
    ACCOUNTS_WITH_FALLBACKS,
 | 
					    ACCOUNTS_WITH_LINK_FALLBACK,
 | 
				
			||||||
    NOT_REQUIRED_ACCOUNTS,
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
    testutil.LINK_METADATA_STRINGS,
 | 
					    testutil.LINK_METADATA_STRINGS,
 | 
				
			||||||
))
 | 
					))
 | 
				
			||||||
| 
						 | 
					@ -176,7 +191,7 @@ def test_valid_fallback_on_post(hook, test_acct, other_acct, value):
 | 
				
			||||||
          post_meta={test_acct.fallback_meta: value})
 | 
					          post_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
    ACCOUNTS_WITH_FALLBACKS,
 | 
					    ACCOUNTS_WITH_LINK_FALLBACK,
 | 
				
			||||||
    NOT_REQUIRED_ACCOUNTS,
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
    testutil.NON_LINK_METADATA_STRINGS,
 | 
					    testutil.NON_LINK_METADATA_STRINGS,
 | 
				
			||||||
))
 | 
					))
 | 
				
			||||||
| 
						 | 
					@ -185,7 +200,7 @@ def test_invalid_fallback_on_post(hook, test_acct, other_acct, value):
 | 
				
			||||||
          post_meta={test_acct.fallback_meta: value})
 | 
					          post_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
    ACCOUNTS_WITH_FALLBACKS,
 | 
					    ACCOUNTS_WITH_LINK_FALLBACK,
 | 
				
			||||||
    NOT_REQUIRED_ACCOUNTS,
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
    testutil.NON_STRING_METADATA_VALUES,
 | 
					    testutil.NON_STRING_METADATA_VALUES,
 | 
				
			||||||
))
 | 
					))
 | 
				
			||||||
| 
						 | 
					@ -198,7 +213,7 @@ def test_bad_type_fallback_on_post(hook, test_acct, other_acct, value):
 | 
				
			||||||
          post_meta={test_acct.fallback_meta: value})
 | 
					          post_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
    ACCOUNTS_WITH_FALLBACKS,
 | 
					    ACCOUNTS_WITH_LINK_FALLBACK,
 | 
				
			||||||
    NOT_REQUIRED_ACCOUNTS,
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
    testutil.LINK_METADATA_STRINGS,
 | 
					    testutil.LINK_METADATA_STRINGS,
 | 
				
			||||||
))
 | 
					))
 | 
				
			||||||
| 
						 | 
					@ -207,7 +222,7 @@ def test_valid_fallback_on_txn(hook, test_acct, other_acct, value):
 | 
				
			||||||
          txn_meta={test_acct.fallback_meta: value})
 | 
					          txn_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
    ACCOUNTS_WITH_FALLBACKS,
 | 
					    ACCOUNTS_WITH_LINK_FALLBACK,
 | 
				
			||||||
    NOT_REQUIRED_ACCOUNTS,
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
    testutil.NON_LINK_METADATA_STRINGS,
 | 
					    testutil.NON_LINK_METADATA_STRINGS,
 | 
				
			||||||
))
 | 
					))
 | 
				
			||||||
| 
						 | 
					@ -216,7 +231,7 @@ def test_invalid_fallback_on_txn(hook, test_acct, other_acct, value):
 | 
				
			||||||
          txn_meta={test_acct.fallback_meta: value})
 | 
					          txn_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
    ACCOUNTS_WITH_FALLBACKS,
 | 
					    ACCOUNTS_WITH_LINK_FALLBACK,
 | 
				
			||||||
    NOT_REQUIRED_ACCOUNTS,
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
    testutil.NON_STRING_METADATA_VALUES,
 | 
					    testutil.NON_STRING_METADATA_VALUES,
 | 
				
			||||||
))
 | 
					))
 | 
				
			||||||
| 
						 | 
					@ -228,6 +243,80 @@ def test_bad_type_fallback_on_txn(hook, test_acct, other_acct, value):
 | 
				
			||||||
    check(hook, test_acct, other_acct, expected,
 | 
					    check(hook, test_acct, other_acct, expected,
 | 
				
			||||||
          txn_meta={test_acct.fallback_meta: value})
 | 
					          txn_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
 | 
					    ACCOUNTS_WITH_CHECK_ID_FALLBACK,
 | 
				
			||||||
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
 | 
					    CHECK_IDS,
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					def test_valid_check_id_on_post(hook, test_acct, other_acct, value):
 | 
				
			||||||
 | 
					    check(hook, test_acct, other_acct, None,
 | 
				
			||||||
 | 
					          post_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
 | 
					    ACCOUNTS_WITH_CHECK_ID_FALLBACK,
 | 
				
			||||||
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
 | 
					    BAD_CHECK_IDS,
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					def test_invalid_check_id_on_post(hook, test_acct, other_acct, value):
 | 
				
			||||||
 | 
					    expected = {
 | 
				
			||||||
 | 
					        test_acct.missing_message(False),
 | 
				
			||||||
 | 
					        f"{test_acct.name} has invalid {test_acct.fallback_meta}: {value}",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    check(hook, test_acct, other_acct, expected,
 | 
				
			||||||
 | 
					          post_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
 | 
					    ACCOUNTS_WITH_CHECK_ID_FALLBACK,
 | 
				
			||||||
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
 | 
					    testutil.NON_STRING_METADATA_VALUES,
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					def test_bad_type_check_id_on_post(hook, test_acct, other_acct, value):
 | 
				
			||||||
 | 
					    if isinstance(value, decimal.Decimal):
 | 
				
			||||||
 | 
					        value = ''
 | 
				
			||||||
 | 
					    expected = {
 | 
				
			||||||
 | 
					        test_acct.missing_message(False),
 | 
				
			||||||
 | 
					        test_acct.wrong_type_message(value, test_acct.fallback_meta),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    check(hook, test_acct, other_acct, expected,
 | 
				
			||||||
 | 
					          post_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
 | 
					    ACCOUNTS_WITH_CHECK_ID_FALLBACK,
 | 
				
			||||||
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
 | 
					    CHECK_IDS,
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					def test_valid_check_id_on_txn(hook, test_acct, other_acct, value):
 | 
				
			||||||
 | 
					    check(hook, test_acct, other_acct, None,
 | 
				
			||||||
 | 
					          txn_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
 | 
					    ACCOUNTS_WITH_CHECK_ID_FALLBACK,
 | 
				
			||||||
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
 | 
					    BAD_CHECK_IDS,
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					def test_invalid_check_id_on_txn(hook, test_acct, other_acct, value):
 | 
				
			||||||
 | 
					    expected = {
 | 
				
			||||||
 | 
					        test_acct.missing_message(False),
 | 
				
			||||||
 | 
					        f"{test_acct.name} has invalid {test_acct.fallback_meta}: {value}",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    check(hook, test_acct, other_acct, expected,
 | 
				
			||||||
 | 
					          txn_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.parametrize('test_acct,other_acct,value', testutil.combine_values(
 | 
				
			||||||
 | 
					    ACCOUNTS_WITH_CHECK_ID_FALLBACK,
 | 
				
			||||||
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
 | 
					    testutil.NON_STRING_METADATA_VALUES,
 | 
				
			||||||
 | 
					))
 | 
				
			||||||
 | 
					def test_bad_type_check_id_on_txn(hook, test_acct, other_acct, value):
 | 
				
			||||||
 | 
					    if isinstance(value, decimal.Decimal):
 | 
				
			||||||
 | 
					        value = ''
 | 
				
			||||||
 | 
					    expected = {
 | 
				
			||||||
 | 
					        test_acct.missing_message(False),
 | 
				
			||||||
 | 
					        test_acct.wrong_type_message(value, test_acct.fallback_meta),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    check(hook, test_acct, other_acct, expected,
 | 
				
			||||||
 | 
					          txn_meta={test_acct.fallback_meta: value})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.mark.parametrize('test_acct,other_acct,key,value', testutil.combine_values(
 | 
					@pytest.mark.parametrize('test_acct,other_acct,key,value', testutil.combine_values(
 | 
				
			||||||
    ACCOUNTS_WITHOUT_FALLBACKS,
 | 
					    ACCOUNTS_WITHOUT_FALLBACKS,
 | 
				
			||||||
    NOT_REQUIRED_ACCOUNTS,
 | 
					    NOT_REQUIRED_ACCOUNTS,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue