diff --git a/sstreasury/jinja2/sstreasury/claim_processing.html b/sstreasury/jinja2/sstreasury/claim_processing.html index 0086e60..d1af607 100644 --- a/sstreasury/jinja2/sstreasury/claim_processing.html +++ b/sstreasury/jinja2/sstreasury/claim_processing.html @@ -24,8 +24,9 @@

Claims processing

- - + + + diff --git a/sstreasury/views.py b/sstreasury/views.py index f4daedd..44777e9 100644 --- a/sstreasury/views.py +++ b/sstreasury/views.py @@ -29,6 +29,7 @@ from django.views import generic from . import aba from . import models +from . import xero from ssmain.email import Emailer import functools @@ -600,6 +601,20 @@ def claim_processing(request): response['Content-Disposition'] = 'attachment; filename="claims.aba"' return response + if request.POST['action'] == 'ExportXero': + claims = models.ReimbursementClaim.objects.filter(state=models.ClaimState.APPROVED.value).all() + claims = [c for c in claims if request.POST.get('claim_{}'.format(c.id), False)] + + csv_file = io.StringIO() + csv_writer = xero.new_writer(csv_file) + + for claim in claims: + xero.write_claim(csv_writer, claim) + + response = HttpResponse(csv_file.getvalue(), content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="claims.csv"' + return response + if request.POST['action'] == 'Pay': claims = models.ReimbursementClaim.objects.filter(state=models.ClaimState.APPROVED.value).all() claims = [c for c in claims if request.POST.get('claim_{}'.format(c.id), False)] diff --git a/sstreasury/xero.py b/sstreasury/xero.py new file mode 100644 index 0000000..16d3ef0 --- /dev/null +++ b/sstreasury/xero.py @@ -0,0 +1,41 @@ +# Society Self-Service +# Copyright © 2018–2020 Yingtong Li (RunasSudo) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django.utils import timezone + +import csv + +def new_writer(f): + writer = csv.DictWriter(f, ['*ContactName', 'EmailAddress', 'POAddressLine1', 'POAddressLine2', 'POAddressLine3', 'POAddressLine4', 'POCity', 'PORegion', 'POPostalCode', 'POCountry', '*InvoiceNumber', '*InvoiceDate', '*DueDate', 'InventoryItemCode', 'Description', '*Quantity', '*UnitAmount', '*AccountCode', '*TaxType', 'TrackingName1', 'TrackingOption1', 'TrackingName2', 'TrackingOption2', 'Currency']) + writer.writeheader() + return writer + +def write_row(writer, d): + writer.writerow(d) + +def write_claim(writer, claim): + for item in claim.items: + write_row(writer, { + '*ContactName': claim.payee_name, + '*InvoiceNumber': 'RE-{}'.format(claim.id), + '*InvoiceDate': timezone.now().strftime('%d/%m/%Y'), + '*DueDate': timezone.now().strftime('%d/%m/%Y'), + 'Description': item['Description'], + '*Quantity': str(item['Units']), + '*UnitAmount': str(item['Unit price']), + '*AccountCode': '850', # Suspense + '*TaxType': 'GST Free Expenses' if item['GST-free'] else 'GST on Expenses', + })