Exemplo n.º 1
0
def bank_reconciliation(request, account):

    template_name = 'subledgers/bank_reconciliations/banktransaction_list.html'

    context_data = {
        'object_list': BankLine.objects.unreconciled(),
        'bank_account': Account.objects.by_code(account),
        'account_list':
        Account.objects.regular().order_by('element', 'number')
    }

    if request.method == 'POST':
        form = BankReconciliationForm(request.POST)
        context_data['success'] = request.POST

        if form.is_valid():
            transaction_kwargs = {
                'user': request.user,
                'date': str(form.cleaned_data.get('date')),
                'source': get_source(BankLine),
                'value': form.cleaned_data.get('value'),
                'account_DR': account,
                'account_CR': form.cleaned_data.get('account'),
            }
            this = BankLine.objects.get(pk=form.cleaned_data.get('pk'))
            this.save_transaction(transaction_kwargs)
            context_data['success'] = "{} {}".format(this, this.transaction)
    return render(request, template_name, context_data)
Exemplo n.º 2
0
    def process_kwargs(self, kwargs):
        """
        Minimum keys assumed included: 'user', 'date', 'lines'

        1. Keys added (if not already defined): 'cls', 'source'
             add `source` using ledgers.utils.get_source(`Model`)
             based upon `Model` provided in object settings

        2. Keys checked: 'relation', dates, decimals, required fields
             IS_DATE using dateparser.parse
             IS_DECIMAL using ledgers.utils.make_decimal()
             IS_RELATION to normalise relation field name

        3. Create dicts: (obj_kwargs, trans_kwargs)

        Check all required fields are represented (or explode)
             append `row_dict` set to `list_kwargs`
        """

        # Generate list of codes to check against.
        # Cheaper than checking db for every account.
        ACCOUNT_CODE_LIST = Account.get_account_code_list()

        process_kwargs = {k.lower(): v for k, v in kwargs.items()}

        # If `cls` not manually described in kwargs.
        process_kwargs['source'] = utils.get_source(self)

        for key in kwargs:
            if key in settings.FIELD_IS_DATE:
                process_kwargs[key] = utils.make_date(kwargs[key])

            if key in settings.FIELD_IS_DECIMAL:
                process_kwargs[key] = utils.make_decimal(kwargs[key])

            if key in settings.FIELD_IS_RELATION:
                # Relation names are not always consistently used.
                # eg. Creditor, Relation
                if kwargs[key] is None:
                    # Is likely to have emtpy relation column heading.
                    # Remove empty relation, so doesn't blow up save.
                    process_kwargs.pop(key)
                else:
                    process_kwargs['relation'] = self.get_relation(kwargs[key])

            if key in ACCOUNT_CODE_LIST:
                process_kwargs.setdefault('accounts', []).append(
                    (key, kwargs[key]))

        self.check_required(process_kwargs)

        return process_kwargs
    def test_journalentry_save_transaction_account_code_passes(self):

        new_journalentry = JournalEntry()
        new_journalentry.save_transaction(self.kwargs)

        test_kwargs = {
            'transaction__date': utils.make_date('5-May-2020'),
            'transaction__user': self.user,
            'transaction__value': 1.00,
            'transaction__source': utils.get_source(JournalEntry)
        }
        test_object = JournalEntry.objects.get(**test_kwargs)
        self.assertEqual(new_journalentry, test_object)
    def test_creditorinvoice_save_transaction_lines_passes(self):

        self.kwargs = {
            'date': '5-May-2020',
            'user': self.user,
            'lines': [(self.a1, 1), (self.a2, 2), (self.c, -3)],
        }
        self.kwargs['invoice_number'] = 'abc123'
        self.kwargs['relation'] = self.creditor
        self.kwargs['gst_total'] = 0
        new_creditorinvoice = CreditorInvoice()
        new_creditorinvoice.save_transaction(self.kwargs)
        test_kwargs = {
            'transaction__date': utils.make_date('5-May-2020'),
            'transaction__user': self.user,
            'transaction__value': 3.00,
            'transaction__source': utils.get_source(CreditorInvoice)
        }
        test_object = CreditorInvoice.objects.get(**test_kwargs)
        self.assertEqual(new_creditorinvoice, test_object)
Exemplo n.º 5
0
def bank_categorisation(request):
    template_name = "subledgers/bank_reconciliations/bank_categorisation.html"
    context_data = {
        'object_list': BankLine.objects.unreconciled(),
        'subledger_list': SUBLEDGERS_AVAILABLE,
    }
    # @@TOOD: figure out how to display already sorted.

    if request.method == 'POST':
        context_data['request'] = request.POST
        subledger = request.POST['subledger']
        log = []

        for field in request.POST:
            if field.split('-')[0] == 'catpk':
                # @@TODO make this a method of some kind.
                pk = field.split('-')[1]
                bank_line = BankLine.objects.get(pk=pk)
                if request.POST['manual-account']:
                    account = request.POST['manual-account']
                else:
                    account = SUBLEDGERS_AVAILABLE[subledger]['account']

                transaction_kwargs = {
                    'user': request.user,
                    'date': bank_line.date,
                    'source': get_source(BankEntry),
                    'value': bank_line.value,
                    'account_DR': account,
                    'account_CR': bank_line.bank_account.account
                }
                bank_entry = BankEntry(bank_line=bank_line,
                                       subledger=subledger)
                bank_entry.save_transaction(transaction_kwargs)
                log.append(bank_entry)

        context_data['test'] = log

    return render(request, template_name, context_data)
Exemplo n.º 6
0
 def test_get_source_str_passes(self):
     test_input = 'ledgers.models.Account'
     test_result = "ledgers.models.Account"
     self.assertEqual(utils.get_source(test_input), test_result)
Exemplo n.º 7
0
 def test_get_source_Obj_object_passes(self):
     Account.objects.create(element="01", number="0001")
     test_input = Account.objects.first()
     test_result = "ledgers.models.Account"
     self.assertEqual(utils.get_source(test_input), test_result)
Exemplo n.º 8
0
 def test_get_source_Obj_instance_passes(self):
     test_input = Account()
     test_result = "ledgers.models.Account"
     self.assertEqual(utils.get_source(test_input), test_result)
Exemplo n.º 9
0
def convert_import_to_objects(dump, user, object_name=None, live=True):
    """
    ** End-to-End **

    Main function for bringing together the elements of constructing
    the list of kwargs for transactions / invoices based upon whatever is
    required for the object.

    Defining Object type by "object_name":
     Either: batch of same Object Class(using * arg `object_name`)
             or: by calling method from Object Class(eg. CreditorInvoice)
         or: column header `object_name` defining on a row-by-row basis.

     There is the choice of either preselecting what object_name of
     objects are being defined such as "CreditorInvoice" objects or
    "JournalEntry" objects.

     Alternatively each `row` should define a `object_name`.

    `user` will be added here as the individual creating this list is
    the one who should be tied to the objects.
    """

    # ** Part 1. convert dump to `list` of `dict` objects
    table = utils.tsv_to_dict(dump)

    obj_list, valid_kwargs = [], []

    for row_dict in table:

        # Copy kwargs for safety to ensure valid set/uniform keys
        kwargs = {k.lower(): v for k, v in row_dict.items()}

        kwargs['user'] = user

        """ There are a couple of different ways to provide `cls`.

        (a) `type` column provided for row in csv
        (b) `object_name` arg provided

        Alternatively done at the single object level not in scope of this
        function. Entry "make/create" methods employed below are used instead.
        """
        # `type` is particular to import as easy nomenclature for csv
        # 1. prioritise type provided for individual line
        if kwargs.get('type'):
            cls = utils.get_cls(kwargs['type'])
        # 2. fall back on `object_name` arg provided
        elif object_name:
            cls = utils.get_cls(object_name)
        else:
            raise Exception(
                "No `type` column specified for {}, unable to create objects.".format(kwargs))  # noqa
        cls = import_string(utils.get_source(cls))

        # If errors Blow up whole lot instead of processing few then blowing up
        cls().make_dicts(kwargs)

        # If doesn't blow up add to valid list
        valid_kwargs.append((cls, kwargs))

    # If whole set has been validated:
    for cls, kwargs in valid_kwargs:
        new_object = cls().save_transaction(kwargs, live=live)
        obj_list.append(new_object)

    # Returns list of generated objects/messages (depending if live or not).
    return obj_list
Exemplo n.º 10
0
    def setUp(self):
        self.user = User.objects.create_user('test_staff_user',
                                             '*****@*****.**', '1234')
        self.user.is_staff = True
        self.user.save()

        # create accounts
        self.a1 = Account.objects.create(element='01',
                                         number='0150',
                                         name='a1')
        self.a2 = Account.objects.create(element='01',
                                         number='0100',
                                         name='a2')

        # create creditors objects
        entity = Entity.objects.create(code='a', name='a')
        self.creditor = Creditor.objects.create(entity=entity)

        # create bank_reconciliation objects
        self.ba = BankAccount(account=self.a1, bank='CBA')
        self.ba.save()

        # banktransacion created, transaction matched
        # Payment 1
        t1_value = Decimal(350)
        lines = (self.a1, self.a2, t1_value)
        self.t1 = Transaction(date=date(2017, 6, 16),
                              value=0,
                              user=self.user,
                              source="{}".format(BankAccount.__module__))
        self.t1.save(lines=lines)
        self.b1 = BankLine(date=date(2017, 6, 16),
                           value=t1_value,
                           bank_account=self.ba,
                           line_dump='Test Transaction 1',
                           description='Test Transaction 1')
        self.b1.save()
        self.e1 = BankEntry.objects.create(transaction=self.t1,
                                           bank_line=self.b1)

        self.p1 = CreditorPayment(relation=self.creditor,
                                  bank_entry=self.e1,
                                  user=self.user)
        self.p1.save()

        # Payment 2
        t2_value = Decimal(20)
        lines = (self.a1, self.a2, t2_value)
        self.t2 = Transaction(date=date(2017, 6, 16),
                              value=0,
                              user=self.user,
                              source="{}".format(BankAccount.__module__))
        self.t2.save(lines=lines)
        self.b2 = BankLine(date=date(2017, 6, 16),
                           value=t2_value,
                           bank_account=self.ba,
                           line_dump='Test Transaction 2',
                           description='Test Transaction 2')
        self.b2.save()
        self.e2 = BankEntry.objects.create(transaction=self.t2,
                                           bank_line=self.b2)
        self.p2 = CreditorPayment(relation=self.creditor,
                                  bank_entry=self.e2,
                                  user=self.user)
        self.p2.save()

        for x in range(1, 6):
            new_transaction = Transaction(user=self.user,
                                          date=date(2017, 5, 2) -
                                          timedelta(days=x * 30),
                                          source=get_source(CreditorInvoice))
            new_transaction.save(lines=(self.a1, self.a2, 100.00))
            new_invoice = CreditorInvoice(relation=self.creditor,
                                          transaction=new_transaction,
                                          invoice_number=x)
            new_invoice.save()
Exemplo n.º 11
0
 def test_get_cls_valid_model_source_failure(self):
     source = utils.get_source(Creditor)
     self.assertRaises(Exception, utils.get_cls, source)
Exemplo n.º 12
0
 def test_get_cls_valid_model_CreditorInvoice_source_passes(self):
     source = utils.get_source(CreditorInvoice)
     self.assertEqual(utils.get_cls(source), CreditorInvoice)
Exemplo n.º 13
0
 def test_get_cls_valid_model_JournalEntry_source_passes(self):
     source = utils.get_source(JournalEntry)
     self.assertEqual(utils.get_cls(source), JournalEntry)