def test_same_sign(self): self.assertTrue(number.same_sign(D('135.12345'), D('234.20'))) self.assertFalse(number.same_sign(D('135.12345'), D('-234.20'))) self.assertFalse(number.same_sign(D('-135.12345'), D('234.20'))) self.assertTrue(number.same_sign(D('-135.12345'), D('-234.20'))) self.assertTrue(number.same_sign(D('135.12345'), ZERO)) self.assertTrue(number.same_sign(ZERO, D('135.12345'))) self.assertTrue(number.same_sign(ZERO, ZERO)) self.assertFalse(number.same_sign(D('-135.12345'), ZERO)) self.assertFalse(number.same_sign(ZERO, D('-135.12345')))
def score_model(self, model_txn, txn): """Score an existing transaction for its ability to provide a model for an incomplete transaction. Args: model_txn: The transaction to be scored. txn: The incomplete transaction. Returns: A float number representing the score, normalized in [0,1]. """ def get_description(txn): return ('{} {}'.format(txn.payee or '', txn.narration or '')).strip() # If the target transaction does not have a description, there is # nothing we can do txn_description = get_description(txn) n_max = len(txn_description) if n_max > 1: # Only consider model transactions whose posting to the target # account has the same sign as the transaction to be completed posting = [p for p in model_txn.postings if p.account == self.account][0] if number.same_sign(posting.units.number, txn.postings[0].units.number): model_txn_description = get_description(model_txn) n_match = len(path.commonprefix( [model_txn_description, txn_description])) score = float(n_match) / float(n_max) return score return 0
def score_model(self, model_txn, txn): """Score an existing transaction for its ability to provide a model for an incomplete transaction. Args: model_txn: The transaction to be scored. txn: The incomplete transaction. Returns: A float number representing the score, normalized in [0,1]. """ def get_description(txn): return ('{} {}'.format(txn.payee or '', txn.narration or '')).strip() # If the target transaction does not have a description, there is # nothing we can do txn_description = get_description(txn) n_max = len(txn_description) if n_max > 1: # Only consider model transactions whose posting to the target # account has the same sign as the transaction to be completed posting = [ p for p in model_txn.postings if p.account == self.account ][0] if number.same_sign(posting.units.number, txn.postings[0].units.number): model_txn_description = get_description(model_txn) n_match = len( path.commonprefix([model_txn_description, txn_description])) score = float(n_match) / float(n_max) return score return 0
def add_amount(self, units, cost=None): """Add to this inventory using amount and cost. This adds with strict lot matching, that is, no partial matches are done on the arguments to the keys of the inventory. Args: units: An Amount instance to add. cost: An instance of Cost or None, as a key to the inventory. Returns: A pair of (position, booking) where 'position' is the position that that was modified BEFORE it was modified, and where 'booking' is a Booking enum that hints at how the lot was booked to this inventory. Position may be None if there is no corresponding Position object, e.g. the position was deleted. """ if ASSERTS_TYPES: assert isinstance( units, Amount), ("Internal error: {!r} (type: {})".format( units, type(units).__name__)) assert cost is None or isinstance( cost, Cost), ("Internal error: {!r} (type: {})".format( cost, type(cost).__name__)) # Find the position. key = (units.currency, cost) pos = self.get(key, None) if pos is not None: # Note: In order to augment or reduce, all the fields have to match. # Check if reducing. booking = (Booking.REDUCED if not same_sign(pos.units.number, units.number) else Booking.AUGMENTED) # Compute the new number of units. number = pos.units.number + units.number if number == ZERO: # If empty, delete the position. del self[key] else: # Otherwise update it. self[key] = Position(Amount(number, units.currency), cost) else: # If not found, create a new one. if units.number == ZERO: booking = Booking.IGNORED else: self[key] = Position(units, cost) booking = Booking.CREATED return pos, booking
def is_reduced_by(self, ramount): """Return true if the amount could reduce this inventory. Args: ramount: An instance of Amount. Returns: A boolean. """ if ramount.number == ZERO: return False for position in self: units = position.units if (ramount.currency == units.currency and not same_sign(ramount.number, units.number)): return True return False