Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added wallet journal export, and a current filter export button to the wallet journal page #95

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions evething/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@

(r'^wallet_journal/$', 'wallet_journal'),
(r'^wallet_journal/aggregate/$', 'wallet_journal_aggregate'),
(r'^wallet_journal/export/$', 'wallet_journal_export'),
(r'^wallet_journal/graph/single/data/$', 'wallet_journal_graph_single_character_data'),
(r'^wallet_journal/graph/$', 'wallet_journal_graph_single'),


(r'^pi/$', 'pi'),
)
Expand Down
45 changes: 45 additions & 0 deletions static/js/evething/wallet_graph.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
function drawChart() {
$.getJSON( "single/data/?" + $.param(parseQueryString()), function( rawData ) {
var i, c, row, charOrder = [];

var charLastBalance = {};
for(i=0; i<rawData.length; i++) {
row = rawData[i];

if (charOrder.indexOf(row[2]) < 0) {
charLastBalance[row[2]] = undefined;
charOrder[charOrder.length] = row[2];
}
};

var chartData = new google.visualization.DataTable();
// Date, char 1, char 2, char 3, ...
chartData.addColumn('date', 'Timestamp');

// Add all character columns by charOrder
for (c=0; c<charOrder.length; c++) {
chartData.addColumn('number', charOrder[c]);
}

var charIndex, chartRow = [];
for (var i=0; i<rawData.length; i++) {
row = rawData[i]

// Since this row has data, it is the most recent data value for
// the current character
charLastBalance[row[2]] = row[1];

// Add the Date row
chartRow[0] = new Date(row[0] + "+00:00");

for (c=0; c<charOrder.length; c++) {
chartRow[c + 1] = parseFloat(charLastBalance[charOrder[c]]);
}

chartData.addRow(chartRow);
}

var chart = new google.visualization.AnnotationChart(document.getElementById('chart_div'));
chart.draw(chartData,{});
});
}
11 changes: 10 additions & 1 deletion static/js/evething/wallet_journal.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ EVEthing.wallet_journal = {
$(this).attr('href', '?' + $.param(params));
}
});


// Add query string to export link
$('a#export-button').each(function() {
var href = $(this).attr('href').split('?', 1)[0];
var param = $.param(parseQueryString())
if (param !== '') {
$(this).attr('href', href + '?' + param);
}
});

// Bind filter events
EVEthing.filters.bind_events();

Expand Down
1 change: 1 addition & 0 deletions templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@
<script src="{{ STATIC_URL}}js/evething/orders.js"></script>
<script src="{{ STATIC_URL}}js/evething/transactions.js"></script>
<script src="{{ STATIC_URL}}js/evething/wallet_journal.js"></script>
<script src="{{ STATIC_URL}}js/evething/wallet_graph.js"></script>
<script src="{{ STATIC_URL}}js/evething/pi.js"></script>
{% else %}
<script src="{{ static('js/evething-combined.min.js') }}"></script>
Expand Down
1 change: 1 addition & 0 deletions templates/thing/wallet_journal.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ <h2>Wallet Journal</h2>

{% include 'includes/wallet_journal_filters.html' %}

<a id="export-button" href="{{ url('thing.views.wallet_journal_export') }}" class="btn btn-info">Export filter as CSV</a>
<strong>Balance for this filter set</strong>: {{ total_amount|default('0.00')|commas }} ISK
</div>
</div>
Expand Down
34 changes: 34 additions & 0 deletions templates/thing/wallet_journal_graph.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{% extends "base.html" %}
{% import 'macros/icons.html' as icons %}

{% block title %}Wallet Journal{% endblock %}

{% block extra_js %}
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['annotationchart']}]}"></script>
<script type="text/javascript">
$(document).ready(function() {
var data = $.parseJSON('{{ json_data|safe }}');
EVEthing.filters.data = data.values;
EVEthing.filters.expected = data.expected;
EVEthing.wallet_journal.filters = data.filters;

EVEthing.wallet_journal.onload();
google.setOnLoadCallback(drawChart);
});


</script>
{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<h2>Wallet Journal</h2>

{% include 'includes/wallet_journal_filters.html' %}

<a id="export-button" href="{{ url('thing.views.wallet_journal_export') }}" class="btn btn-info">Export filter as CSV</a>
<strong>Balance for this filter set</strong>: {{ total_amount|default('0.00')|commas }} ISK
</div>
</div>
<div id='chart_div' style='width: 900px; height: 500px;'></div>
{% endblock %}
238 changes: 237 additions & 1 deletion thing/views/wallet_journal.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@
# ------------------------------------------------------------------------------

import json
import csv

from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q, Count, Sum
from django.http import StreamingHttpResponse, HttpResponse
from django.core.serializers.json import DjangoJSONEncoder

from thing.models import * # NOPEP8
from thing.stuff import * # NOPEP8


JOURNAL_EXPECTED = {
'char': {
'label': 'Character',
Expand Down Expand Up @@ -242,6 +244,240 @@ def wallet_journal(request):
)


class Echo(object):
"""An object that implements just the write method of the file-like
interface.
"""
def write(self, value):
"""Write the value by returning it, instead of storing in a buffer."""
return value


@login_required
def wallet_journal_export(request):
"""Wallet journal"""
# Get profile
profile = request.user.profile

characters = Character.objects.filter(
apikeys__user=request.user,
apikeys__valid=True,
apikeys__key_type__in=[APIKey.ACCOUNT_TYPE, APIKey.CHARACTER_TYPE]
).distinct()
character_ids = [c.id for c in characters]

corporation_ids = Corporation.get_ids_with_access(
request.user,
APIKey.CORP_WALLET_JOURNAL_MASK
)
corporations = Corporation.objects.filter(pk__in=corporation_ids)

# Parse filters and apply magic
filters, journal_ids, days = _journal_queryset(
request,
character_ids,
corporation_ids
)

# Return query set of journal entries with current filter
entries = journal_ids.select_related(
'character',
'corp_wallet__corporation'
)

# Do some stuff with entries
item_ids = set()
owner_ids = set()
reftype_ids = set()
station_ids = set()

for entry in entries:
owner_ids.add(entry.owner1_id)
owner_ids.add(entry.owner2_id)
reftype_ids.add(entry.ref_type_id)

# Insurance
if entry.ref_type_id == 19:
item_ids.add(int(entry.arg_name))
# Clone Transfer
elif entry.ref_type_id == 52:
station_ids.add(int(entry.arg_id))
# Bounty Prizes
elif entry.ref_type_id == 85:
for thing in entry.reason.split(','):
thing = thing.strip()
if ':' in thing:
item_ids.add(int(thing.split(':')[0]))

char_map = Character.objects.in_bulk(owner_ids)
corp_map = Corporation.objects.in_bulk(owner_ids)
alliance_map = Alliance.objects.in_bulk(owner_ids)
item_map = Item.objects.in_bulk(item_ids)
rt_map = RefType.objects.in_bulk(reftype_ids)
station_map = Station.objects.in_bulk(station_ids)

pseudo_buffer = Echo()
writer = csv.writer(pseudo_buffer)

def rowformatter(queryset):
yield writer.writerow([
'reference id',
'source',
'wallet division',
'timestamp',
'reference type',
'owner 1',
'owner 2',
'amount',
'balance',
'tax corp',
'tax amount',
'description'
])
for row in queryset:
owner1 = char_map.get(row.owner1_id)
if owner1 is None:
owner1 = corp_map.get(row.owner1_id)
if owner1 is None:
alliance_map.get(row.owner1_id)
if owner1 is None:
owner1 = row.owner1_id

owner2 = char_map.get(row.owner2_id)
if owner2 is None:
owner2 = corp_map.get(row.owner2_id)
if owner2 is None:
alliance_map.get(row.owner2_id)
if owner2 is None:
owner2 = row.owner2_id

description = ''
# Inheritance
if row.ref_type_id == 9:
description = row.reason
# Player Donation/Corporation Account Withdrawal
elif row.ref_type_id in (10, 37) and row.reason != '':
description = '"%s"' % (row.get_unescaped_reason()[5:].strip())
# Insurance, arg_name is the item_id of the ship that exploded
elif row.ref_type_id == 19:
if row.amount >= 0:
item = item_map.get(int(row.arg_name))
if item:
description = \
'Insurance payment for loss of a %s' % item.name
else:
description = \
'Insurance purchased (RefID: %s)' % (row.arg_name[1:])
# Clone Transfer, arg_name is the name of the station
# you're going to
elif row.ref_type_id == 52:
station = station_map.get(row.arg_id)
if station:
description = 'Clone transfer to %s' % (station.short_name)
# Bounty Prizes
elif row.ref_type_id == 85:
killed = []

for thing in row.reason.split(','):
thing = thing.strip()
if ':' in thing:
item_id, count = thing.split(':')
item = item_map.get(int(item_id))
if item:
killed.append((
item.name,
'%sx %s' % (count, item.name)
))
elif thing == '...':
killed.append(('ZZZ', '... (list truncated)'))

# Sort killed
killed = [k[1] for k in sorted(killed)]

description = \
'Bounty prizes for killing pirates in %s' % (
row.arg_name.strip()
)

yield writer.writerow([
row.ref_id,
row.character,
row.corp_wallet,
row.date,
rt_map.get(row.ref_type_id),
owner1,
owner2,
row.amount,
row.balance,
row.tax_corp,
row.tax_amount,
description
])

response = StreamingHttpResponse(
rowformatter(entries),
content_type="text/csv"
)
response['Content-Disposition'] = \
'attachment; filename="WalletJournal.csv"'
return response


@login_required
def wallet_journal_graph_single(request):
profile = request.user.profile

characters = Character.objects.filter(
apikeys__user=request.user,
apikeys__valid=True,
apikeys__key_type__in=[APIKey.ACCOUNT_TYPE, APIKey.CHARACTER_TYPE]
).distinct()
character_ids = [c.id for c in characters]

corporation_ids = Corporation.get_ids_with_access(request.user, APIKey.CORP_WALLET_JOURNAL_MASK)
corporations = Corporation.objects.filter(pk__in=corporation_ids)

# Parse filters and apply magic
filters, journal_ids, days = _journal_queryset(request, character_ids, corporation_ids)
return render_page(
'thing/wallet_journal_graph.html',
{
"group_by":(),
'json_data': _json_data(characters, corporations, filters)
},
request,
character_ids,
corporation_ids
)

@login_required
def wallet_journal_graph_single_character_data(request):
# Get profile
profile = request.user.profile

characters = Character.objects.filter(
apikeys__user=request.user,
apikeys__valid=True,
apikeys__key_type__in=[APIKey.ACCOUNT_TYPE, APIKey.CHARACTER_TYPE]
).distinct()
character_ids = [c.id for c in characters]

corporation_ids = Corporation.get_ids_with_access(
request.user,
APIKey.CORP_WALLET_JOURNAL_MASK
)
corporations = Corporation.objects.filter(pk__in=corporation_ids)

# Parse filters and apply magic
filters, journal_ids, days = _journal_queryset(
request,
character_ids,
corporation_ids
)

response_data = [[entry.date, entry.balance, str(entry.character)] for entry in journal_ids.order_by('date')]
return HttpResponse(json.dumps(response_data, cls=DjangoJSONEncoder), content_type="application/json")

@login_required
def wallet_journal_aggregate(request):
characters = Character.objects.filter(apikeys__user=request.user.id)
Expand Down