Example #1
0
def _homeview(request, invoice_objects, unpaid=False, pending=False, deleted=False, paid=False, searchterm=None):
    # Utility function for all main invoice views, so make the shared permissions
    # check here.
    authenticate_backend_group(request, 'Invoice managers')

    # Add info about refunds to all invoices
    invoice_objects = invoice_objects.extra(select={
        'has_refund': 'EXISTS (SELECT 1 FROM invoices_invoicerefund r WHERE r.invoice_id=invoices_invoice.id)',
    })

    # Render a list of all invoices
    (invoices, paginator, page_range) = simple_pagination(request, invoice_objects, 50)

    has_pending = Invoice.objects.filter(finalized=False).exists()
    has_unpaid = Invoice.objects.filter(finalized=True, paidat__isnull=False).exists()
    return render(request, 'invoices/home.html', {
        'invoices': invoices,
        'paid': paid,
        'unpaid': unpaid,
        'pending': pending,
        'deleted': deleted,
        'has_pending': has_pending,
        'has_unpaid': has_unpaid,
        'searchterm': searchterm,
        'page_range': page_range,
        'breadcrumbs': [('/invoiceadmin/', 'Invoices'), ],
        'helplink': 'payment',
    })
Example #2
0
def bankfile_transactions(request, methodid):
    authenticate_backend_group(request, 'Invoice managers')

    method = get_object_or_404(InvoicePaymentMethod, pk=methodid)

    # Needed for backlinks
    methodcount = InvoicePaymentMethod.objects.filter(
        config__has_key='file_upload_interval').count()

    backbutton = "../"
    breadlabel = "Bank transactions"

    if methodcount == 1:
        # If there is only one method, we have to return all the way back to the index page, or we'll
        # just get redirected back to ourselves.
        backbutton = "/admin/"

    q = Q(method=method)
    if 'file' in request.GET:
        q = q & Q(fromfile=get_int_or_error(request.GET, 'file'))
        backbutton = "../../"
        breadlabel = "Bankfiles"

    allrows = BankStatementRow.objects.filter(q).order_by('-date', 'id')
    (rows, paginator, page_range) = simple_pagination(request, allrows, 50)

    extrakeys = set()
    hasvaluefor = {
        'uniqueid': False,
        'balance': False,
    }
    for r in rows:
        extrakeys.update(r.other.keys())
        for k in hasvaluefor.keys():
            if getattr(r, k, None):
                hasvaluefor[k] = True

    params = request.GET.copy()
    if 'page' in params:
        del params['page']

    return render(
        request, 'invoices/bankfile_transactions.html', {
            'rows': rows,
            'extrakeys': extrakeys,
            'hasvaluefor': hasvaluefor,
            'page_range': page_range,
            'topadmin': 'Invoices',
            'helplink': 'payment',
            'requestparams': params.urlencode(),
            'breadcrumbs': [
                (backbutton, breadlabel),
            ],
            'backbutton': backbutton,
        })
Example #3
0
def bankfiles(request):
    authenticate_backend_group(request, 'Invoice managers')

    if request.method == 'POST':
        # Uploading a file!
        method = get_object_or_404(InvoicePaymentMethod,
                                   active=True,
                                   config__has_key='file_upload_interval',
                                   id=get_int_or_error(request.POST, 'id'))
        if 'f' not in request.FILES:
            messages.error(request, "No file included in upload")
        elif request.FILES['f'].size < 1:
            messages.error(request, "Uploaded file is empty")
        else:
            f = request.FILES['f']
            impl = method.get_implementation()

            try:
                (contents, numrows, numtrans,
                 numpending) = impl.parse_uploaded_file(f)
                BankFileUpload(
                    method=method,
                    uploadby=request.user.username,
                    name=f.name,
                    textcontents=contents,
                    parsedrows=numrows,
                    newtrans=numtrans,
                    newpending=numpending,
                ).save()
                messages.info(
                    request,
                    "File uploaded. {} rows parsed, {} transactions stored, resulting in {} pending transactions."
                    .format(numrows, numtrans, numpending))
                return HttpResponseRedirect('.')
            except Exception as e:
                messages.error(request, "Error uploading file: {}".format(e))

    methods = InvoicePaymentMethod.objects.filter(
        active=True, config__has_key='file_upload_interval').annotate(
            latest_file=Max('bankfileupload__created'))
    file_objects = BankFileUpload.objects.select_related(
        'method').all().order_by('-created')[:1000]
    (files, paginator, page_range) = simple_pagination(request, file_objects,
                                                       50)

    return render(
        request, 'invoices/bankfiles.html', {
            'files': files,
            'page_range': page_range,
            'methods': methods,
            'topadmin': 'Invoices',
            'helplink': 'payment',
        })
Example #4
0
def job(request, jobid):
    if not request.user.is_superuser:
        raise PermissionDenied("Access denied")

    job = get_object_or_404(ScheduledJob, id=jobid)

    if request.method == 'POST':
        if request.POST.get('schedule-now', '') == '1':
            job.nextrun = timezone.now()
            job.save()
            notify_job_change()
            messages.info(
                request,
                "Scheduled immediate run of '{0}'".format(job.description))
            return HttpResponseRedirect('../')
        elif request.POST.get('reset-failure', '') == '1':
            job.lastrun = None
            job.lastrunsuccess = False
            job.save()
            messages.info(
                request, "Reset last run failure state of '{0}'".format(
                    job.description))
            return HttpResponseRedirect('../')

        form = ScheduledJobForm(request,
                                conference=None,
                                instance=job,
                                data=request.POST)
        if form.is_valid():
            form.save()
            reschedule_job(job, notify=True)
            return HttpResponseRedirect("../")
    else:
        form = ScheduledJobForm(request, conference=None, instance=job)

    history_objects = JobHistory.objects.filter(job=job).order_by('-time')
    (history, paginator,
     page_range) = simple_pagination(request, history_objects, 15)

    return render(
        request, 'scheduler/job.html', {
            'job': job,
            'history': history,
            'form': form,
            'page_range': page_range,
            'breadcrumbs': [
                ('/admin/jobs/', 'Scheduled jobs'),
            ],
            'helplink': 'jobs',
        })
Example #5
0
def refunds(request):
    authenticate_backend_group(request, 'Invoice managers')

    refund_objects = InvoiceRefund.objects.\
        select_related('invoice', 'invoice__paidusing').\
        only('id', 'invoice_id', 'completed', 'issued', 'registered', 'reason', 'invoice__paidusing__internaldescription').\
        order_by(F('completed').desc(nulls_first=True), F('issued').desc(nulls_first=True), F('registered').desc())

    (refunds, paginator, page_range) = simple_pagination(request, refund_objects, 20)

    return render(request, 'invoices/refunds.html', {
        'refunds': refunds,
        'page_range': page_range,
        'breadcrumbs': [('/admin/invoices/refunds/', 'Refunds'), ],
        'helplink': 'payment',
    })
Example #6
0
def history(request):
    if not request.user.is_superuser:
        raise PermissionDenied("Access denied")

    history_objects = JobHistory.objects.only(
        'time', 'job__description', 'success',
        'runtime').select_related('job').order_by('-time')
    (history, paginator,
     page_range) = simple_pagination(request, history_objects, 50)

    return render(
        request, 'scheduler/history.html', {
            'history': history,
            'page_range': page_range,
            'breadcrumbs': [
                ('/admin/jobs/', 'Scheduled jobs'),
            ],
            'helplink': 'jobs',
        })
Example #7
0
def bankfiles(request):
    authenticate_backend_group(request, 'Invoice managers')

    if request.method == 'POST':
        # Uploading a file!
        method = get_object_or_404(InvoicePaymentMethod,
                                   active=True,
                                   config__has_key='file_upload_interval',
                                   id=get_int_or_error(request.POST, 'id'))

        impl = method.get_implementation()
        # Stage 1 upload has the file in request.FILES. Stage 2 has it in a hidden field in the form instead,
        # because we can't make it upload th file twice.
        if 'fc' in request.POST:
            # In stage 2 the file is included ase base64
            txt = impl.convert_uploaded_file_to_utf8(
                BytesIO(base64.b64decode(request.POST['fc'])))

            try:
                rows = impl.parse_uploaded_file_to_rows(txt)
                (anyerror, extrakeys,
                 hasvaluefor) = impl.process_loaded_rows(rows)

                numrows = len(rows)
                numtrans = 0
                numpending = 0
                numerrors = 0

                with transaction.atomic():
                    # Store thef file itself
                    bankfile = BankFileUpload(
                        method=method,
                        parsedrows=numrows,
                        newtrans=0,
                        newpending=0,
                        errors=0,
                        uploadby=request.user.username,
                        name=request.POST['name'],
                        textcontents=txt,
                    )
                    bankfile.save()  # To get an id we can use

                    for r in rows:
                        if r['row_already_exists']:
                            continue
                        if r.get('row_errors', []):
                            numerrors += 1
                            continue

                        # Insert the row
                        b = BankStatementRow(
                            method=method,
                            fromfile=bankfile,
                            uniqueid=r.get('uniqueid', None),
                            date=r['date'],
                            amount=r['amount'],
                            description=r['text'],
                            balance=r.get('balance', None),
                            other=r['other'],
                        )
                        b.save()
                        numtrans += 1

                        if not register_bank_transaction(
                                b.method, b.id, b.amount, b.description, ''):
                            # This means the transaction wasn't directly matched and has been
                            # registered as a pending transaction.
                            numpending += 1

                    bankfile.newtrans = numtrans
                    bankfile.newpending = numpending
                    bankfile.errors = numerrors
                    bankfile.save()
            except Exception as e:
                messages.error(request, "Error uploading file: {}".format(e))

            return HttpResponseRedirect(".")

        if 'f' not in request.FILES:
            messages.error(request, "No file included in upload")
        elif request.FILES['f'].size < 1:
            messages.error(request, "Uploaded file is empty")
        else:
            f = request.FILES['f']

            try:
                # Stage 1, mean we parse it and render a second form to confirm
                rows = impl.parse_uploaded_file_to_rows(
                    impl.convert_uploaded_file_to_utf8(f))
                (anyerror, extrakeys,
                 hasvaluefor) = impl.process_loaded_rows(rows)

                f.seek(0)

                return render(
                    request, 'invoices/bankfile_uploaded.html', {
                        'method': method,
                        'rows': rows,
                        'extrakeys': sorted(extrakeys),
                        'hasvaluefor': hasvaluefor,
                        'anyerror': anyerror,
                        'filename': f.name,
                        'fc': base64.b64encode(f.read()).decode('ascii'),
                        'topadmin': 'Invoices',
                        'helplink': 'payment',
                        'breadcrumbs': [
                            ('../../', 'Bank files'),
                        ],
                    })
            except Exception as e:
                messages.error(request, "Error uploading file: {}".format(e))

    methods = InvoicePaymentMethod.objects.filter(
        active=True, config__has_key='file_upload_interval').annotate(
            latest_file=Max('bankfileupload__created'))
    file_objects = BankFileUpload.objects.select_related(
        'method').all().order_by('-created')[:1000]
    (files, paginator, page_range) = simple_pagination(request, file_objects,
                                                       50)

    return render(
        request, 'invoices/bankfiles.html', {
            'files': files,
            'page_range': page_range,
            'methods': methods,
            'topadmin': 'Invoices',
            'helplink': 'payment',
        })