2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-09-18 08:31:33 +00:00

Calendar export (#3858)

* Basic implementation of iCal feed

* Add calendar download to API

* Improve comments, remove unused outputs

* Basic implementation of iCal feed

* Add calendar download to API

* Improve comments, remove unused outputs

* Improve comment

* Implement filter include_completed

* update requirements.txt with pip-compile --output-file=requirements.txt requirements.in -U

* Fix less than filter

* Change URL to include calendar.ics

* Fix filtering of orders

* Remove URL/functions for calendar in views

* Lint

* More lint

* Even more style fixes

* Updated requirements-dev.txt because of style fail

* Now?

* Fine, fix it manually

* Gaaah

* Fix with same method as in common/settings.py

* Fix setting name; improve name of calendar endpoint

* Adapt InvenTreeAPITester get function to match post, etc (required for calendar test)

* Merge

* Reduce requirements.txt

* Update requirements-dev.txt

* Update tests

* Set expected codes in API calendar test

* SO completion can not work without line items; set a target date on existing orders instead

* Correct method to PATCH

* Well that didn't work for some reason.. try with cancelled orders instead

* Make sure there are more completed orders than other orders in test

* Correct wrong variable

* Lint

* Use correct status code

* Add test for unauthorized access to calendar

* Add a working test for unauthorised access

* Put the correct test in place, fix Lint

* Revert changes to requirements-dev, which appear magically...

* Lint

* Add test for basic auth

* make sample simpler

* Increment API version

Co-authored-by: Matthias Mair <code@mjmair.com>
This commit is contained in:
miggland
2022-12-21 13:17:27 +01:00
committed by GitHub
parent 4034349043
commit fdc4a46b26
7 changed files with 348 additions and 4 deletions

View File

@@ -1,11 +1,13 @@
"""Tests for the Order API."""
import base64
import io
from datetime import datetime, timedelta
from django.core.exceptions import ValidationError
from django.urls import reverse
from icalendar import Calendar
from rest_framework import status
import order.models as models
@@ -409,6 +411,111 @@ class PurchaseOrderTest(OrderTest):
order = models.PurchaseOrder.objects.get(pk=1)
self.assertEqual(order.get_metadata('yam'), 'yum')
def test_po_calendar(self):
"""Test the calendar export endpoint"""
# Create required purchase orders
self.assignRole('purchase_order.add')
for i in range(1, 9):
self.post(
reverse('api-po-list'),
{
'reference': f'PO-1100000{i}',
'supplier': 1,
'description': f'Calendar PO {i}',
'target_date': f'2024-12-{i:02d}',
},
expected_code=201
)
# Get some of these orders with target date, complete or cancel them
for po in models.PurchaseOrder.objects.filter(target_date__isnull=False):
if po.reference in ['PO-11000001', 'PO-11000002', 'PO-11000003', 'PO-11000004']:
# Set issued status for these POs
self.post(
reverse('api-po-issue', kwargs={'pk': po.pk}),
{},
expected_code=201
)
if po.reference in ['PO-11000001', 'PO-11000002']:
# Set complete status for these POs
self.post(
reverse('api-po-complete', kwargs={'pk': po.pk}),
{
'accept_incomplete': True,
},
expected_code=201
)
elif po.reference in ['PO-11000005', 'PO-11000006']:
# Set cancel status for these POs
self.post(
reverse('api-po-cancel', kwargs={'pk': po.pk}),
{
'accept_incomplete': True,
},
expected_code=201
)
url = reverse('api-po-so-calendar', kwargs={'ordertype': 'purchase-order'})
# Test without completed orders
response = self.get(url, expected_code=200, format=None)
number_orders = len(models.PurchaseOrder.objects.filter(target_date__isnull=False).filter(status__lt=PurchaseOrderStatus.COMPLETE))
# Transform content to a Calendar object
calendar = Calendar.from_ical(response.content)
n_events = 0
# Count number of events in calendar
for component in calendar.walk():
if component.name == 'VEVENT':
n_events += 1
self.assertGreaterEqual(n_events, 1)
self.assertEqual(number_orders, n_events)
# Test with completed orders
response = self.get(url, data={'include_completed': 'True'}, expected_code=200, format=None)
number_orders_incl_completed = len(models.PurchaseOrder.objects.filter(target_date__isnull=False))
self.assertGreater(number_orders_incl_completed, number_orders)
# Transform content to a Calendar object
calendar = Calendar.from_ical(response.content)
n_events = 0
# Count number of events in calendar
for component in calendar.walk():
if component.name == 'VEVENT':
n_events += 1
self.assertGreaterEqual(n_events, 1)
self.assertEqual(number_orders_incl_completed, n_events)
def test_po_calendar_noauth(self):
"""Test accessing calendar without authorization"""
self.client.logout()
response = self.client.get(reverse('api-po-so-calendar', kwargs={'ordertype': 'purchase-order'}), format='json')
self.assertEqual(response.status_code, 401)
resp_dict = response.json()
self.assertEqual(resp_dict['detail'], "Authentication credentials were not provided.")
def test_po_calendar_auth(self):
"""Test accessing calendar with header authorization"""
self.client.logout()
base64_token = base64.b64encode(f'{self.username}:{self.password}'.encode('ascii')).decode('ascii')
response = self.client.get(
reverse('api-po-so-calendar', kwargs={'ordertype': 'purchase-order'}),
format='json',
HTTP_AUTHORIZATION=f'basic {base64_token}'
)
self.assertEqual(response.status_code, 200)
class PurchaseOrderLineItemTest(OrderTest):
"""Unit tests for PurchaseOrderLineItems."""
@@ -1077,6 +1184,67 @@ class SalesOrderTest(OrderTest):
order = models.SalesOrder.objects.get(pk=1)
self.assertEqual(order.get_metadata('xyz'), 'abc')
def test_so_calendar(self):
"""Test the calendar export endpoint"""
# Create required sales orders
self.assignRole('sales_order.add')
for i in range(1, 9):
self.post(
reverse('api-so-list'),
{
'reference': f'SO-1100000{i}',
'customer': 4,
'description': f'Calendar SO {i}',
'target_date': f'2024-12-{i:02d}',
},
expected_code=201
)
# Cancel a few orders - these will not show in incomplete view below
for so in models.SalesOrder.objects.filter(target_date__isnull=False):
if so.reference in ['SO-11000006', 'SO-11000007', 'SO-11000008', 'SO-11000009']:
self.post(
reverse('api-so-cancel', kwargs={'pk': so.pk}),
expected_code=201
)
url = reverse('api-po-so-calendar', kwargs={'ordertype': 'sales-order'})
# Test without completed orders
response = self.get(url, expected_code=200, format=None)
number_orders = len(models.SalesOrder.objects.filter(target_date__isnull=False).filter(status__lt=SalesOrderStatus.SHIPPED))
# Transform content to a Calendar object
calendar = Calendar.from_ical(response.content)
n_events = 0
# Count number of events in calendar
for component in calendar.walk():
if component.name == 'VEVENT':
n_events += 1
self.assertGreaterEqual(n_events, 1)
self.assertEqual(number_orders, n_events)
# Test with completed orders
response = self.get(url, data={'include_completed': 'True'}, expected_code=200, format=None)
number_orders_incl_complete = len(models.SalesOrder.objects.filter(target_date__isnull=False))
self.assertGreater(number_orders_incl_complete, number_orders)
# Transform content to a Calendar object
calendar = Calendar.from_ical(response.content)
n_events = 0
# Count number of events in calendar
for component in calendar.walk():
if component.name == 'VEVENT':
n_events += 1
self.assertGreaterEqual(n_events, 1)
self.assertEqual(number_orders_incl_complete, n_events)
class SalesOrderLineItemTest(OrderTest):
"""Tests for the SalesOrderLineItem API."""