Example #1
0
    def context(self, ehash):
        try:
            entry = next(entry for entry in self.all_entries if ehash == compare.hash_entry(entry))
        except StopIteration:
            return

        context_str = context.render_entry_context(self.all_entries, self.options, entry)
        return {"context": context_str.split("\n", 2)[2], "entry": entry}
Example #2
0
    def queries(self, query_hash=None):
        if not query_hash:
            return self._journal(self.all_entries, Query)
        matching_entries = [entry for entry in self.all_entries
                            if query_hash == compare.hash_entry(entry)]

        if not matching_entries:
            return

        assert len(matching_entries) == 1
        return serialize_entry(matching_entries[0])
Example #3
0
def link_statements(entries, options_map):
    errors = []

    if 'documents' not in options_map or len(options_map['documents']) == 0:
        return entries, errors

    all_documents = [(i, entry) for i, entry in enumerate(entries)
                     if isinstance(entry, data.Document)]

    all_transactions = [(i, entry) for i, entry in enumerate(entries)
                        if isinstance(entry, data.Transaction)]

    for i, entry in all_transactions:
        statements = [value for key, value in entry.meta.items()
                      if key.startswith('statement')]

        _hash = hash_entry(entry)[:8]
        for statement in statements:
            statement_p = normpath(join(dirname(entry.meta['filename']),
                                        statement))
            documents = [(j, document) for j, document in all_documents
                         if (document.filename == statement_p) or
                            (document.account in
                                [pos.account for pos in entry.postings] and
                             basename(document.filename) == statement)]

            if (len(documents) == 0):
                errors.append(
                    StatementDocumentError(
                        entry.meta,
                        "Statement Document not found: {}".format(statement),
                        entry))
                continue

            for j, document in documents:
                tags = set(document.tags).union(
                    ['statement']).difference(['discovered']) \
                    if document.tags else set(['statement'])
                links = set(document.links).union([_hash]) \
                    if document.links else set([_hash])
                entries[j] = document._replace(links=links, tags=tags)

            links = set(entry.links).union([_hash]) \
                if entry.links else set([_hash])
            entries[i] = entry._replace(links=links)

    return entries, errors
Example #4
0
def _add_metadata(new_entry, entry):
    new_entry['meta'] = {
        'type': entry.__class__.__name__.lower(),
    }
    new_entry['hash'] = compare.hash_entry(entry)

    if entry.meta:
        new_entry['meta']['filename'] = getattr(entry.meta, 'filename', None)
        new_entry['meta']['lineno'] = getattr(entry.meta, 'lineno', None)

        new_entry['metadata'] = entry.meta.copy()
        new_entry['metadata'].pop("__tolerances__", None)
        new_entry['metadata'].pop("__automatic__", None)
        new_entry['metadata'].pop("filename", None)
        new_entry['metadata'].pop("lineno", None)

    return new_entry
Example #5
0
    def get_entry(self, entry_hash):
        """Find an entry.

        Arguments:
            entry_hash: Hash of the entry.

        Returns:
            The entry with the given hash.
        Raises:
            FavaAPIException: If there is no entry for the given hash.
        """
        try:
            return next(entry for entry in self.all_entries
                        if entry_hash == hash_entry(entry))
        except StopIteration:
            raise FavaAPIException('No entry found for hash "{}"'
                                   .format(entry_hash))
Example #6
0
    def context(self, ehash):
        matching_entries = [entry for entry in self.all_entries if ehash == compare.hash_entry(entry)]

        if not matching_entries:
            return

        # the hash should uniquely identify the entry
        assert len(matching_entries) == 1
        entry = matching_entries[0]
        context_str = context.render_entry_context(self.all_entries, self.options, entry)
        return {
            "hash": ehash,
            "context": context_str.split("\n", 2)[2],
            "filename": entry.meta["filename"],
            "lineno": entry.meta["lineno"],
            "journal": matching_entries,
        }
Example #7
0
def link_documents(entries, _):
    errors = []

    all_documents = [(index, entry) for index, entry in enumerate(entries)
                     if isinstance(entry, data.Document)]

    transactions = [(index, entry) for index, entry in enumerate(entries)
                    if isinstance(entry, data.Transaction)]

    for index, entry in transactions:
        disk_docs = [value for key, value in entry.meta.items()
                     if key.startswith('document')]

        _hash = hash_entry(entry)[:8]
        for disk_doc in disk_docs:
            disk_doc_path = normpath(join(dirname(entry.meta['filename']),
                                          disk_doc))
            documents = [(j, document) for j, document in all_documents
                         if (document.filename == disk_doc_path) or
                         (document.account in
                          [pos.account for pos in entry.postings] and
                          basename(document.filename) == disk_doc)]

            if not documents:
                errors.append(
                    DocumentError(
                        entry.meta,
                        "Document not found: {}".format(disk_doc),
                        entry))
                continue

            for j, document in documents:
                tags = set(document.tags).union(
                    ['linked']).difference(['discovered']) \
                    if document.tags else set(['linked'])
                links = set(document.links).union([_hash]) \
                    if document.links else set([_hash])
                entries[j] = document._replace(links=links, tags=tags)

            links = set(entry.links).union([_hash]) \
                if entry.links else set([_hash])
            entries[index] = entry._replace(links=links)

    return entries, errors
Example #8
0
    def context(self, ehash):
        matching_entries = [entry for entry in self.all_entries
                            if ehash == compare.hash_entry(entry)]

        if not matching_entries:
            return

        # the hash should uniquely identify the entry
        assert len(matching_entries) == 1
        entry = matching_entries[0]
        context_str = context.render_entry_context(self.all_entries,
                                                   self.options, entry)
        return {
            'hash': ehash,
            'context': context_str.split("\n", 2)[2],
            'filename': entry.meta['filename'],
            'lineno': entry.meta['lineno'],
            'journal': self._journal(matching_entries),
        }
Example #9
0
    def context(self, ehash=None):
        matching_entries = [entry
                                for entry in self.entries
                                if ehash == compare.hash_entry(entry)]

        contexts = []
        dcontext = self.options['dcontext']

        for entry in matching_entries:
            context_str = context.render_entry_context(
                self.entries, self.options, entry)

            hash_ = context_str.split("\n",2)[0].split(':')[1].strip()
            filenamelineno = context_str.split("\n",2)[1]
            filename = filenamelineno.split(":")[1].strip()
            lineno = int(filenamelineno.split(":")[2].strip())

            contexts.append({
                'hash': hash_,
                'context': context_str.split("\n",2)[2],
                'filename': filename,
                'line': lineno
            })

        # TODO
        #        if len(matching_entries) == 0:
        #            print("ERROR: Could not find matching entry for '{}'".format(ehash),
        #                  file=oss)
        #
        #        elif len(matching_entries) > 1:
        #            print("ERROR: Ambiguous entries for '{}'".format(ehash),
        #                  file=oss)
        #            print(file=oss)
        #            dcontext = app.options['dcontext']
        #            printer.print_entries(matching_entries, dcontext, file=oss)
        #
        #        else:

        return {
            'hash': ehash,
            'contexts': contexts,
            'journal': self._journal_for_postings(matching_entries)
        }
Example #10
0
    def context(self, ehash):
        matching_entries = [entry for entry in self.all_entries
                            if ehash == compare.hash_entry(entry)]

        if not matching_entries:
            return

        # the hash should uniquely identify the entry
        assert len(matching_entries) == 1
        entry = matching_entries[0]
        context_str = context.render_entry_context(self.all_entries,
                                                   self.options, entry)
        ctx = context_str.split("\n", 2)
        filenamelineno = ctx[1]
        filename = filenamelineno.split(":")[1].strip()
        lineno = int(filenamelineno.split(":")[2].strip())

        return {
            'hash': ehash,
            'context': ctx[2],
            'filename': filename,
            'line': lineno,
            'journal': self._journal(matching_entries)
        }
Example #11
0
 def hash_entry(self, entry):
     return compare.hash_entry(entry)
Example #12
0
    def _journal_for_postings(self, postings, include_types=None, with_change_and_balance=False):
        journal = []

        for posting, leg_postings, change, entry_balance in realization.iterate_with_balance(postings):

            if include_types and not isinstance(posting, include_types):
                continue

            if  isinstance(posting, Transaction) or \
                isinstance(posting, Note) or \
                isinstance(posting, Balance) or \
                isinstance(posting, Open) or \
                isinstance(posting, Close) or \
                isinstance(posting, Pad) or \
                isinstance(posting, Event) or \
                isinstance(posting, Document):

                entry = {
                    'meta': {
                        'type': posting.__class__.__name__.lower(),
                        'filename': posting.meta['filename'],
                        'lineno': posting.meta['lineno']
                    },
                    'date': posting.date,
                    'hash': compare.hash_entry(posting),
                    'metadata': posting.meta.copy()
                }

                entry['metadata'].pop("__tolerances__", None)
                entry['metadata'].pop("filename", None)
                entry['metadata'].pop("lineno", None)

                if isinstance(posting, Open):
                    entry['account']        = posting.account
                    entry['currencies']     = posting.currencies

                if isinstance(posting, Close):
                    entry['account']        = posting.account

                if isinstance(posting, Event):
                    entry['type']           = posting.type
                    entry['description']    = posting.description

                if isinstance(posting, Note):
                    entry['comment']        = posting.comment

                if isinstance(posting, Document):
                    entry['account']        = posting.account
                    entry['filename']       = posting.filename

                if isinstance(posting, Pad):
                    entry['account']        = posting.account
                    entry['source_account'] = posting.source_account

                if isinstance(posting, Balance):
                    entry['account']        = posting.account
                    entry['change']         = { posting.amount.currency: posting.amount.number }
                    entry['amount']         = { posting.amount.currency: posting.amount.number }

                    if posting.diff_amount:
                        balance              = entry_balance.get_units(posting.amount.currency)
                        entry['diff_amount'] = { posting.diff_amount.currency: posting.diff_amount.number }
                        entry['balance']     = { balance.currency: balance.number }

                if isinstance(posting, Transaction):
                    if posting.flag == 'P':
                        entry['meta']['type'] = 'padding'  # TODO handle Padding, Summarize and Transfer

                    entry['flag']       = posting.flag
                    entry['payee']      = posting.payee
                    entry['narration']  = posting.narration
                    entry['tags']       = posting.tags or []
                    entry['links']      = posting.links or []
                    entry['legs']       = []

                    for posting_ in posting.postings:
                        leg = {
                            'account': posting_.account,
                            'flag': posting_.flag,
                            'hash': entry['hash']
                        }

                        if posting_.position:
                            leg['position']          = posting_.position.number
                            leg['position_currency'] = posting_.position.lot.currency
                            cost                     = interpolate.get_posting_weight(posting_)
                            leg['cost']              = cost.number
                            leg['cost_currency']     = cost.currency

                        if posting_.price:
                            leg['price']             = posting_.price.number
                            leg['price_currency']    = posting_.price.currency

                        entry['legs'].append(leg)

                if with_change_and_balance:
                    if isinstance(posting, Balance):
                        entry['change']     = { posting.amount.currency: posting.amount.number }
                        entry['balance']    = self._inventory_to_json(entry_balance)  #, include_currencies=entry['change'].keys())

                    if isinstance(posting, Transaction):
                        entry['change']     = self._inventory_to_json(change)
                        entry['balance']    = self._inventory_to_json(entry_balance, include_currencies=entry['change'].keys())

                journal.append(entry)

        return journal
Example #13
0
    def _journal_for_postings(self, postings, include_types=None):
        journal = []

        for posting, leg_postings, change, entry_balance in realization.iterate_with_balance(postings):

            if include_types and not isinstance(posting, include_types):
                continue

            if  isinstance(posting, Transaction) or \
                isinstance(posting, Note) or \
                isinstance(posting, Balance) or \
                isinstance(posting, Open) or \
                isinstance(posting, Close) or \
                isinstance(posting, Pad) or \
                isinstance(posting, Document):   # TEMP

                # if isinstance(posting, TxnPosting):
                #     posting = posting.txn

                entry = {
                    'meta': {
                        'type': posting.__class__.__name__.lower(),
                        'filename': posting.meta['filename'],
                        'lineno': posting.meta['lineno']
                    },
                    'date': posting.date,
                    'hash': compare.hash_entry(posting)
                }

                if isinstance(posting, Open):
                    entry['account'] =       posting.account
                    entry['currencies'] =    posting.currencies
                    entry['booking'] =       posting.booking # TODO im html-template

                if isinstance(posting, Close):
                    entry['account'] =       posting.account

                if isinstance(posting, Note):
                    entry['comment'] =       posting.comment

                if isinstance(posting, Document):
                    entry['account'] =       posting.account
                    entry['filename'] =      posting.filename

                if isinstance(posting, Pad):
                    entry['account'] =       posting.account
                    entry['source_account'] =      posting.source_account

                if isinstance(posting, Balance):
                    # TODO failed balances
                    entry['account'] =       posting.account
                    entry['change'] =        { posting.amount.currency: posting.amount.number }
                    entry['balance'] =       { posting.amount.currency: posting.amount.number }
                    entry['tolerance'] =     posting.tolerance  # TODO currency? TODO in HTML-template
                    entry['diff_amount'] =   posting.diff_amount  # TODO currency? TODO in HTML-template

                if isinstance(posting, Transaction):
                    if posting.flag == 'P':
                        entry['meta']['type'] = 'padding'

                    entry['flag'] =         posting.flag
                    entry['payee'] =        posting.payee
                    entry['narration'] =    posting.narration
                    entry['tags'] =         posting.tags
                    entry['links'] =        posting.links
                    entry['change'] =       self._inventory_to_json(change)
                    entry['balance'] =      self._inventory_to_json(entry_balance)
                    entry['legs'] =         []


                    for posting_ in posting.postings:
                        leg = {
                            'account': posting_.account,
                            'flag': posting_.flag,
                            'hash': entry['hash']
                        }

                        if posting_.position:
                            leg['position'] = posting_.position.number
                            leg['position_currency'] = posting_.position.lot.currency

                        if posting_.price:
                            leg['price'] = posting_.price.number
                            leg['price_currency'] = posting_.price.currency

                        entry['legs'].append(leg)


                journal.append(entry)

        return journal
Example #14
0
def hash_entry(entry):
    """Hash an entry."""
    return compare.hash_entry(entry)