summaryrefslogtreecommitdiff
path: root/app/unused_apps/income
diff options
context:
space:
mode:
Diffstat (limited to 'app/unused_apps/income')
-rw-r--r--app/unused_apps/income/__init__.py0
-rw-r--r--app/unused_apps/income/admin.py88
-rw-r--r--app/unused_apps/income/migrations/0001_initial.py37
-rw-r--r--app/unused_apps/income/migrations/0002_gig_due_date.py21
-rw-r--r--app/unused_apps/income/migrations/0003_auto_20161213_1038.py25
-rw-r--r--app/unused_apps/income/migrations/0004_invoice_invoiceitem.py31
-rw-r--r--app/unused_apps/income/migrations/0005_invoice_slug.py19
-rw-r--r--app/unused_apps/income/migrations/0006_auto_20190131_2351.py17
-rw-r--r--app/unused_apps/income/migrations/__init__.py0
-rw-r--r--app/unused_apps/income/models.py103
-rw-r--r--app/unused_apps/income/parser.py23
-rw-r--r--app/unused_apps/income/views.py53
12 files changed, 417 insertions, 0 deletions
diff --git a/app/unused_apps/income/__init__.py b/app/unused_apps/income/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/unused_apps/income/__init__.py
diff --git a/app/unused_apps/income/admin.py b/app/unused_apps/income/admin.py
new file mode 100644
index 0000000..b165371
--- /dev/null
+++ b/app/unused_apps/income/admin.py
@@ -0,0 +1,88 @@
+import datetime
+from django.contrib import admin
+from django.db.models import Sum
+from django.contrib.gis.admin import OSMGeoAdmin
+from django.conf.urls import url
+from django.shortcuts import render
+
+
+from .models import Gig, Invoice, InvoiceItem
+
+
+@admin.register(InvoiceItem)
+class InvoiceItemAdmin(admin.ModelAdmin):
+ list_display = ('time_start', 'time_end', 'work_done')
+
+
+@admin.register(Invoice)
+class InvoiceAdmin(admin.ModelAdmin):
+ list_display = ('title', 'admin_link', 'date_start', 'date_end')
+
+
+@admin.register(Gig)
+class GigAdmin(OSMGeoAdmin):
+ list_display = ('title', 'status', 'due_date', 'payment_status', 'payment', 'publisher', 'word_count')
+ list_filter = ('publisher', 'status', 'payment_status')
+ fieldsets = (
+ ('Gig', {
+ 'fields': (
+ 'title',
+ 'pitch',
+ ('created', 'due_date'),
+ ('payment', 'pay_type', 'payment_status', 'invoice_date'),
+ ('status', 'pub_date', 'word_count'),
+ 'publisher',
+ 'pub_item'
+ ),
+ 'classes': (
+ 'show',
+ 'extrapretty',
+ 'wide'
+ )
+ }
+ ),
+ )
+
+ def get_urls(self):
+ urls = super(GigAdmin, self).get_urls()
+ custom_urls = [
+ url(
+ r'^monthly/$',
+ self.admin_site.admin_view(self.get_monthly),
+ name='monthly_admin'
+ )
+ ]
+ return custom_urls + urls
+
+ def get_monthly(self, request):
+ context = {
+ 'title': ("This month's income"),
+ 'app_label': self.model._meta.app_label,
+ 'opts': self.model._meta,
+ 'has_change_permission': self.has_change_permission(request)
+ }
+ try:
+ year = request.GET["m"].split("-")[0]
+ month = request.GET["m"].split("-")[1]
+ except:
+ year = datetime.datetime.now().strftime('%Y')
+ month = datetime.datetime.now().strftime('%m')
+ qs = self.model.objects.filter(
+ created__year=year,
+ created__month=month,
+ status__in=[1, 2, 3]
+ )
+ context['pitched'] = self.model.objects.filter(
+ created__year=year,
+ created__month=month,
+ status=0
+ )
+ context['date'] = datetime.datetime.now()
+ context['billed'] = qs.filter(payment_status=1)
+ context['billed_total'] = qs.filter(payment_status=1).aggregate(total_payment=Sum('payment'))
+ context['unbilled'] = qs.filter(payment_status=0)
+ context['unbilled_total'] = qs.filter(payment_status=0).aggregate(total_payment=Sum('payment'))
+ context['total_outstanding'] = qs.aggregate(total_payment=Sum('payment'))
+ context['months'] = self.model.objects.dates('created', 'month')
+ return render(request, 'admin/income_month.html', context)
+
diff --git a/app/unused_apps/income/migrations/0001_initial.py b/app/unused_apps/income/migrations/0001_initial.py
new file mode 100644
index 0000000..3a1e926
--- /dev/null
+++ b/app/unused_apps/income/migrations/0001_initial.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9 on 2016-02-10 08:48
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('resume', '0003_auto_20151211_1925'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Gig',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=200)),
+ ('pitch', models.TextField(blank=True, null=True)),
+ ('created', models.DateTimeField(default=django.utils.timezone.now)),
+ ('pub_date', models.DateTimeField(default=django.utils.timezone.now)),
+ ('status', models.IntegerField(choices=[(0, 'Pitched'), (1, 'Accepted'), (2, 'Submitted'), (3, 'Published'), (4, 'Rejected'), (5, 'TO PITCH')], default=1)),
+ ('invoice_date', models.DateTimeField(blank=True, null=True)),
+ ('payment', models.DecimalField(decimal_places=2, max_digits=10)),
+ ('payment_status', models.IntegerField(choices=[(0, 'NOT SUBMITTED'), (1, 'Invoiced'), (2, 'Paid')], default=1)),
+ ('pay_type', models.IntegerField(choices=[(0, 'Flat Rate'), (1, 'Per Word'), (2, 'Hourly')], default=1)),
+ ('word_count', models.DecimalField(blank=True, decimal_places=0, max_digits=7, null=True)),
+ ('pub_item', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='resume.PubItem')),
+ ('publisher', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='resume.Publisher')),
+ ],
+ ),
+ ]
diff --git a/app/unused_apps/income/migrations/0002_gig_due_date.py b/app/unused_apps/income/migrations/0002_gig_due_date.py
new file mode 100644
index 0000000..ccd0f73
--- /dev/null
+++ b/app/unused_apps/income/migrations/0002_gig_due_date.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9 on 2016-02-10 08:49
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('income', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='gig',
+ name='due_date',
+ field=models.DateField(default=django.utils.timezone.now),
+ ),
+ ]
diff --git a/app/unused_apps/income/migrations/0003_auto_20161213_1038.py b/app/unused_apps/income/migrations/0003_auto_20161213_1038.py
new file mode 100644
index 0000000..559cd5a
--- /dev/null
+++ b/app/unused_apps/income/migrations/0003_auto_20161213_1038.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9 on 2016-12-13 10:38
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('income', '0002_gig_due_date'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='gig',
+ name='due_date',
+ field=models.DateField(blank=True, null=True),
+ ),
+ migrations.AlterField(
+ model_name='gig',
+ name='pub_date',
+ field=models.DateTimeField(blank=True, null=True),
+ ),
+ ]
diff --git a/app/unused_apps/income/migrations/0004_invoice_invoiceitem.py b/app/unused_apps/income/migrations/0004_invoice_invoiceitem.py
new file mode 100644
index 0000000..59f389c
--- /dev/null
+++ b/app/unused_apps/income/migrations/0004_invoice_invoiceitem.py
@@ -0,0 +1,31 @@
+# Generated by Django 2.1 on 2018-09-03 17:58
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('income', '0003_auto_20161213_1038'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Invoice',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=200)),
+ ('date_start', models.DateField(blank=True, null=True)),
+ ('date_end', models.DateField(blank=True, null=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='InvoiceItem',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('time_start', models.DateTimeField(blank=True, null=True)),
+ ('time_end', models.DateTimeField(blank=True, null=True)),
+ ('work_done', models.TextField(blank=True, null=True)),
+ ],
+ ),
+ ]
diff --git a/app/unused_apps/income/migrations/0005_invoice_slug.py b/app/unused_apps/income/migrations/0005_invoice_slug.py
new file mode 100644
index 0000000..3b6dfb2
--- /dev/null
+++ b/app/unused_apps/income/migrations/0005_invoice_slug.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.1.1 on 2018-09-03 19:02
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('income', '0004_invoice_invoiceitem'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='invoice',
+ name='slug',
+ field=models.SlugField(default='slug'),
+ preserve_default=False,
+ ),
+ ]
diff --git a/app/unused_apps/income/migrations/0006_auto_20190131_2351.py b/app/unused_apps/income/migrations/0006_auto_20190131_2351.py
new file mode 100644
index 0000000..1c8f64c
--- /dev/null
+++ b/app/unused_apps/income/migrations/0006_auto_20190131_2351.py
@@ -0,0 +1,17 @@
+# Generated by Django 2.1.1 on 2019-01-31 23:51
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('income', '0005_invoice_slug'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='invoiceitem',
+ options={'ordering': ('time_start',)},
+ ),
+ ]
diff --git a/app/unused_apps/income/migrations/__init__.py b/app/unused_apps/income/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/unused_apps/income/migrations/__init__.py
diff --git a/app/unused_apps/income/models.py b/app/unused_apps/income/models.py
new file mode 100644
index 0000000..e5a351b
--- /dev/null
+++ b/app/unused_apps/income/models.py
@@ -0,0 +1,103 @@
+import datetime
+from datetime import timedelta
+from django.db import models
+from django.utils import timezone
+from django.urls import reverse
+from django.utils.html import format_html
+
+from resume.models import PubItem, Publisher
+
+
+class Gig(models.Model):
+ title = models.CharField(max_length=200)
+ pitch = models.TextField(null=True, blank=True)
+ created = models.DateTimeField(default=timezone.now)
+ pub_date = models.DateTimeField(blank=True, null=True)
+ due_date = models.DateField(blank=True, null=True)
+ STATUS = (
+ (0, "Pitched"),
+ (1, "Accepted"),
+ (2, "Submitted"),
+ (3, "Published"),
+ (4, "Rejected"),
+ (5, "TO PITCH"),
+ )
+ status = models.IntegerField(choices=STATUS, default=1)
+ invoice_date = models.DateTimeField(null=True, blank=True)
+ payment = models.DecimalField(max_digits=10, decimal_places=2)
+ PAY_STATUS = (
+ (0, "NOT SUBMITTED"),
+ (1, "Invoiced"),
+ (2, "Paid"),
+ )
+ payment_status = models.IntegerField(choices=PAY_STATUS, default=1)
+ PAY_TYPE = (
+ (0, "Flat Rate"),
+ (1, "Per Word"),
+ (2, "Hourly"),
+ )
+ pay_type = models.IntegerField(choices=PAY_TYPE, default=1)
+ word_count = models.DecimalField(max_digits=7, decimal_places=0, blank=True, null=True)
+ publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE, blank=True, null=True)
+ pub_item = models.ForeignKey(PubItem, on_delete=models.CASCADE, blank=True, null=True)
+
+ def __str__(self):
+ return self.title
+
+ def get_pay_date(self):
+ days = self.publisher.payment_time * 7
+ if self.invoice_date:
+ return self.invoice_date + datetime.timedelta(float(days))
+
+
+class Invoice(models.Model):
+ title = models.CharField(max_length=200)
+ slug = models.SlugField()
+ date_start = models.DateField(null=True, blank=True)
+ date_end = models.DateField(null=True, blank=True)
+
+ def __str__(self):
+ return self.title
+
+ def admin_link(self):
+ return format_html('<a href="/admin/income/invoice/monthlyview/%s/">View Invoice</a>' % (self.slug))
+ admin_link.short_description = 'Invoice'
+
+
+class InvoiceItem(models.Model):
+ time_start = models.DateTimeField(null=True, blank=True)
+ time_end = models.DateTimeField(null=True, blank=True)
+ work_done = models.TextField(null=True, blank=True)
+
+ class Meta:
+ ordering = ('time_start',)
+
+ def __str__(self):
+ return str(self.time_start)
+
+ @property
+ def total(self):
+ return self.time_end - self.time_start
+
+ @property
+ def rounded_total(self):
+ """
+ Rounds the given timedelta by the given timedelta period
+ :param td: `timedelta` to round
+ :param period: `timedelta` period to round by.
+ """
+ period = timedelta(minutes=15)
+ td = self.total
+ period_seconds = period.total_seconds()
+ half_period_seconds = period_seconds / 2
+ remainder = td.total_seconds() % period_seconds
+ if remainder >= half_period_seconds:
+ tdr = timedelta(seconds=td.total_seconds() + (period_seconds - remainder))
+ hours, remainder = divmod(tdr.total_seconds(), 3600)
+ r = remainder/3600
+ return float(hours)+r
+ else:
+ tdr = timedelta(seconds=td.total_seconds() - remainder)
+ hours, remainder = divmod(tdr.total_seconds(), 3600)
+ r = remainder/3600
+ return float(hours)+r
diff --git a/app/unused_apps/income/parser.py b/app/unused_apps/income/parser.py
new file mode 100644
index 0000000..b19d039
--- /dev/null
+++ b/app/unused_apps/income/parser.py
@@ -0,0 +1,23 @@
+import csv
+import datetime
+from .models import InvoiceItem
+
+
+def read_timesheet():
+ with open('timesheet.csv', newline='') as csvfile:
+ reader = csv.reader(csvfile, delimiter=';')
+ counter = 0
+ f = "%Y-%m-%d %H:%M:%S"
+ for row in reader:
+ if counter > 0:
+ print(row[4])
+ timer = row[0]+' '+row[1]
+ timerer = row[0]+' '+row[2]
+ time_start = datetime.datetime.strptime(timer, f)
+ time_end = datetime.datetime.strptime(timerer, f)
+ InvoiceItem.objects.get_or_create(
+ time_start=time_start,
+ time_end=time_end,
+ work_done=row[4]
+ )
+ counter = counter + 1
diff --git a/app/unused_apps/income/views.py b/app/unused_apps/income/views.py
new file mode 100644
index 0000000..1c34068
--- /dev/null
+++ b/app/unused_apps/income/views.py
@@ -0,0 +1,53 @@
+import datetime
+from django.views.generic.detail import DetailView
+from django.template.loader import render_to_string
+from django.http import HttpResponse
+from django.conf import settings
+
+#from weasyprint import HTML, CSS
+
+from .models import Invoice, InvoiceItem
+
+
+class MonthlyInvoiceView(DetailView):
+ model = Invoice
+ template_name = "admin/income/monthly.html"
+ slug_field = "slug"
+
+ def get_context_data(self, **kwargs):
+ context = super(MonthlyInvoiceView, self).get_context_data(**kwargs)
+ context['object_list'] = InvoiceItem.objects.filter(time_start__range=[self.object.date_start, self.object.date_end])
+ total_time = []
+ for item in context['object_list']:
+ total_time.append(item.rounded_total)
+ hours = (sum(total_time))
+ context['total_hours'] = hours
+ context['total_billed'] = int(hours * 100)
+ context['invoice_number'] = self.object.id+21
+ return context
+
+
+class DownloadMonthlyInvoiceView(MonthlyInvoiceView):
+ model = Invoice
+ slug_field = "slug"
+
+ def get(self, *args, **kwargs):
+ import logging
+ logger = logging.getLogger('weasyprint')
+ logger.addHandler(logging.FileHandler('weasyprint.log'))
+ self.object = self.get_object() # assign the object to the view
+ context = self.get_context_data()
+ c = {
+ 'object': self.object,
+ 'object_list': context['object_list'],
+ 'total_hours': context['total_hours'],
+ 'total_billed': context['total_billed'],
+ 'invoice_number': self.object.id+23
+ }
+ t = render_to_string('details/invoice.html', c).encode('utf-8')
+ #html = HTML(string=t, base_url=self.request.build_absolute_uri())
+ #pdf = html.write_pdf(stylesheets=[CSS(settings.MEDIA_ROOT + '/pdf_gen.css')], presentational_hints=True)
+ #response = HttpResponse(pdf, content_type='application/pdf')
+ #response['Content-Disposition'] = 'inline; filename="invoice.pdf"'
+ response = HttpResponse('', content_type='application/pdf')
+ return response