accruals: AccrualPostings only reports inconsistent cost per currency.

Of course if an accrual has multiple currencies, it'll probably have
different costs, and that's fine.
This commit is contained in:
Brett Smith 2020-06-03 21:23:52 -04:00
parent 3d704e2865
commit c88c5ef3b0
3 changed files with 15 additions and 35 deletions

View file

@ -144,7 +144,6 @@ class AccrualPostings(core.RelatedPostings):
_FIELDS: Dict[str, Callable[[data.Posting], MetaValue]] = {
'account': operator.attrgetter('account'),
'contract': _meta_getter('contract'),
'cost': operator.attrgetter('cost'),
'entity': _meta_getter('entity'),
'invoice': _meta_getter('invoice'),
'purchase_order': _meta_getter('purchase-order'),
@ -157,8 +156,6 @@ class AccrualPostings(core.RelatedPostings):
'accounts',
'contract',
'contracts',
'cost',
'costs',
'entity',
'entitys',
'entities',
@ -226,6 +223,17 @@ class AccrualPostings(core.RelatedPostings):
get_func(post),
)
yield Error(post.meta, errmsg, post.meta.txn)
costs = collections.defaultdict(set)
for post in self:
costs[post.units.currency].add(post.cost)
for code, currency_costs in costs.items():
if len(currency_costs) > 1:
for post in self:
if post.units.currency == code:
errmsg = 'inconsistent cost for invoice {}: {}'.format(
self.invoice or "<none>", post.cost,
)
yield Error(post.meta, errmsg, post.meta.txn)
def is_paid(self, default: Optional[bool]=None) -> Optional[bool]:
if self.accrual_type is None:

View file

@ -41,8 +41,8 @@
rt-id: "rt:505"
invoice: "rt:505/5050"
approval: "rt:505/5040"
Income:Donations -1000.00 USD
Assets:Receivable:Accounts 1000.00 USD
Income:Donations -2,500 EUR {1.100 USD}
Assets:Receivable:Accounts 2,500 EUR {1.100 USD}
2020-05-10 * "Lawyer" "April legal services"
rt-id: "rt:510"
@ -60,8 +60,8 @@
2020-05-20 * "DonorA" "Donation made"
rt-id: "rt:505"
invoice: "rt:505/5050"
Assets:Receivable:Accounts -1000.00 USD
Assets:Checking 1000.00 USD
Assets:Receivable:Accounts -2,750.00 USD
Assets:Checking 2,750.00 USD
receipt: "DonorAWire.pdf"
2020-05-25 * "Lawyer" "May payment"

View file

@ -212,20 +212,6 @@ def test_accrual_postings_consistent_account(acct_name):
assert related.account == acct_name
assert related.accounts == {acct_name}
@pytest.mark.parametrize('cost', [
testutil.Cost('1.2', 'USD'),
None,
])
def test_accrual_postings_consistent_cost(cost):
meta = {'invoice': 'FXinvoice.pdf'}
txn = testutil.Transaction(postings=[
(ACCOUNTS[0], 60, 'EUR', cost, meta),
(ACCOUNTS[0], 30, 'EUR', cost, meta),
])
related = accrual.AccrualPostings(data.Posting.from_txn(txn))
assert related.cost == cost
assert related.costs == {cost}
@pytest.mark.parametrize('meta_key,acct_name', testutil.combine_values(
CONSISTENT_METADATA,
ACCOUNTS,
@ -255,20 +241,6 @@ def test_accrual_postings_inconsistent_account():
assert related.account is related.INCONSISTENT
assert related.accounts == set(ACCOUNTS)
def test_accrual_postings_inconsistent_cost():
meta = {'invoice': 'FXinvoice.pdf'}
costs = {
testutil.Cost('1.1', 'USD'),
testutil.Cost('1.2', 'USD'),
}
txn = testutil.Transaction(postings=[
(ACCOUNTS[0], 10, 'EUR', cost, meta)
for cost in costs
])
related = accrual.AccrualPostings(data.Posting.from_txn(txn))
assert related.cost is related.INCONSISTENT
assert related.costs == costs
@pytest.mark.parametrize('meta_key,acct_name', testutil.combine_values(
CONSISTENT_METADATA,
ACCOUNTS,