Merge branch 'chrisjrn/more_reports'
This commit is contained in:
		
						commit
						c64d0eaab8
					
				
					 3 changed files with 76 additions and 21 deletions
				
			
		|  | @ -67,6 +67,13 @@ class AttendeeProfileBase(models.Model): | |||
|         ''' | ||||
|         return None | ||||
| 
 | ||||
|     def attendee_name(self): | ||||
|         if type(self) == AttendeeProfileBase: | ||||
|             real = AttendeeProfileBase.objects.get_subclass(id=self.id) | ||||
|         else: | ||||
|             real = self | ||||
|         return getattr(real, real.name_field()) | ||||
| 
 | ||||
|     def invoice_recipient(self): | ||||
|         ''' | ||||
| 
 | ||||
|  |  | |||
|  | @ -89,6 +89,42 @@ def items_sold(request, form): | |||
|     return Report("Paid items", headings, data) | ||||
| 
 | ||||
| 
 | ||||
| @report_view("Reconcilitation") | ||||
| def reconciliation(request, form): | ||||
|     ''' Reconciles all sales in the system with the payments in the | ||||
|     system. ''' | ||||
| 
 | ||||
|     headings = ["Thing", "Total"] | ||||
|     data = [] | ||||
| 
 | ||||
|     sales = commerce.LineItem.objects.filter( | ||||
|         invoice__status=commerce.Invoice.STATUS_PAID, | ||||
|     ).values( | ||||
|         "price", "quantity" | ||||
|     ).aggregate(total=Sum(F("price") * F("quantity"))) | ||||
| 
 | ||||
|     data.append(["Paid items", sales["total"]]) | ||||
| 
 | ||||
|     payments = commerce.PaymentBase.objects.values( | ||||
|         "amount", | ||||
|     ).aggregate(total=Sum("amount")) | ||||
| 
 | ||||
|     data.append(["Payments", payments["total"]]) | ||||
| 
 | ||||
|     ucn = commerce.CreditNote.unclaimed().values( | ||||
|         "amount" | ||||
|     ).aggregate(total=Sum("amount")) | ||||
| 
 | ||||
|     data.append(["Unclaimed credit notes", 0 - ucn["total"]]) | ||||
| 
 | ||||
|     data.append([ | ||||
|         "(Money not on invoices)", | ||||
|         sales["total"] - payments["total"] - ucn["total"], | ||||
|     ]) | ||||
| 
 | ||||
|     return Report("Sales and Payments", headings, data) | ||||
| 
 | ||||
| 
 | ||||
| @report_view("Product status", form_type=forms.ProductAndCategoryForm) | ||||
| def product_status(request, form): | ||||
|     ''' Summarises the inventory status of the given items, grouping by | ||||
|  | @ -271,6 +307,23 @@ def attendee(request, form, attendee_id=None): | |||
|         Report("Credit Notes", headings, data, link_view="credit_note") | ||||
|     ) | ||||
| 
 | ||||
|     # All payments | ||||
|     headings = ["To Invoice", "Payment ID", "Reference", "Amount"] | ||||
|     data = [] | ||||
| 
 | ||||
|     payments = commerce.PaymentBase.objects.filter( | ||||
|         invoice__user=attendee.user, | ||||
|     ) | ||||
|     for payment in payments: | ||||
|         data.append([ | ||||
|             payment.invoice.id, payment.id, payment.reference, payment.amount, | ||||
|         ]) | ||||
| 
 | ||||
|     reports.append( | ||||
|         Report("Payments", headings, data, link_view="invoice") | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
|     return reports | ||||
| 
 | ||||
| 
 | ||||
|  | @ -279,28 +332,30 @@ def attendee_list(request): | |||
| 
 | ||||
|     attendees = people.Attendee.objects.all().select_related( | ||||
|         "attendeeprofilebase", | ||||
|         "user", | ||||
|     ) | ||||
| 
 | ||||
|     attendees = attendees.values("id", "user__email").annotate( | ||||
|     attendees = attendees.annotate( | ||||
|         has_registered=Count( | ||||
|             Q(user__invoice__status=commerce.Invoice.STATUS_PAID) | ||||
|         ), | ||||
|     ) | ||||
| 
 | ||||
|     headings = [ | ||||
|         "User ID", "Email", "Has registered", | ||||
|         "User ID", "Name", "Email", "Has registered", | ||||
|     ] | ||||
| 
 | ||||
|     data = [] | ||||
| 
 | ||||
|     for attendee in attendees: | ||||
|         data.append([ | ||||
|             attendee["id"], | ||||
|             attendee["user__email"], | ||||
|             attendee["has_registered"], | ||||
|             attendee.id, | ||||
|             attendee.attendeeprofilebase.attendee_name(), | ||||
|             attendee.user.email, | ||||
|             attendee.has_registered > 0, | ||||
|         ]) | ||||
| 
 | ||||
|     # Sort by whether they've registered, then ID. | ||||
|     data.sort(key=lambda attendee: (-attendee[2], attendee[0])) | ||||
|     data.sort(key=lambda attendee: (-attendee[3], attendee[0])) | ||||
| 
 | ||||
|     return Report("Attendees", headings, data, link_view="attendee") | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| from reporting import views as reporting_views | ||||
| from reporting import views as rv | ||||
| 
 | ||||
| from django.conf.urls import include | ||||
| from django.conf.urls import url | ||||
|  | @ -36,20 +36,13 @@ public = [ | |||
| 
 | ||||
| 
 | ||||
| reports = [ | ||||
|     url(r"^$", reporting_views.reports_list, name="reports_list"), | ||||
|     url(r"^attendee/?$", reporting_views.attendee, name="attendee"), | ||||
|     url(r"^attendee/([0-9]*)$", reporting_views.attendee, name="attendee"), | ||||
|     url( | ||||
|         r"^credit_notes/?$", | ||||
|         reporting_views.credit_notes, | ||||
|         name="credit_notes" | ||||
|     ), | ||||
|     url( | ||||
|         r"^product_status/?$", | ||||
|         reporting_views.product_status, | ||||
|         name="product_status", | ||||
|     ), | ||||
|     url(r"^items_sold/?$", reporting_views.items_sold, name="items_sold"), | ||||
|     url(r"^$", rv.reports_list, name="reports_list"), | ||||
|     url(r"^attendee/?$", rv.attendee, name="attendee"), | ||||
|     url(r"^attendee/([0-9]*)$", rv.attendee, name="attendee"), | ||||
|     url(r"^credit_notes/?$", rv.credit_notes, name="credit_notes"), | ||||
|     url(r"^items_sold/?$", rv.items_sold, name="items_sold"), | ||||
|     url(r"^product_status/?$", rv.product_status, name="product_status"), | ||||
|     url(r"^reconciliation/?$", rv.reconciliation, name="reconciliation"), | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Christopher Neugebauer
						Christopher Neugebauer