4 |
4 |
import pytest
|
5 |
5 |
|
6 |
6 |
from wcs import fields
|
|
7 |
from wcs.backoffice.management import format_time
|
7 |
8 |
from wcs.blocks import BlockDef
|
8 |
9 |
from wcs.carddef import CardDef
|
9 |
10 |
from wcs.categories import CardDefCategory, Category
|
... | ... | |
15 |
16 |
from .utils import sign_uri
|
16 |
17 |
|
17 |
18 |
|
|
19 |
def get_humanized_duration_serie(json_resp):
|
|
20 |
return [format_time(x) for x in json_resp['data']['series'][0]['data']]
|
|
21 |
|
|
22 |
|
18 |
23 |
@pytest.fixture
|
19 |
24 |
def pub():
|
20 |
25 |
pub = create_temporary_pub()
|
... | ... | |
246 |
251 |
]
|
247 |
252 |
|
248 |
253 |
|
|
254 |
def test_statistics_index_resolution_time(pub):
|
|
255 |
formdef = FormDef()
|
|
256 |
formdef.name = 'test 1'
|
|
257 |
formdef.fields = []
|
|
258 |
formdef.store()
|
|
259 |
formdef.data_class().wipe()
|
|
260 |
|
|
261 |
resp = get_app(pub).get(sign_uri('/api/statistics/'))
|
|
262 |
resolution_time_stat = [x for x in resp.json['data'] if x['id'] == 'resolution_time'][0]
|
|
263 |
form_filter = [x for x in resolution_time_stat['filters'] if x['id'] == 'form'][0]
|
|
264 |
assert form_filter['options'] == [{'id': 'test-1', 'label': 'test 1'}]
|
|
265 |
|
|
266 |
|
249 |
267 |
def test_statistics_forms_count(pub):
|
250 |
268 |
category_a = Category(name='Category A')
|
251 |
269 |
category_a.store()
|
... | ... | |
762 |
780 |
|
763 |
781 |
resp = get_app(pub).get(sign_uri('/api/statistics/cards/count/?card=%s' % 'invalid'), status=400)
|
764 |
782 |
assert resp.text == 'invalid form'
|
|
783 |
|
|
784 |
|
|
785 |
def test_statistics_resolution_time(pub, freezer):
|
|
786 |
workflow = Workflow(name='Workflow One')
|
|
787 |
new_status = workflow.add_status(name='New status')
|
|
788 |
middle_status = workflow.add_status(name='Middle status')
|
|
789 |
workflow.add_status(name='End status')
|
|
790 |
workflow.add_status(name='End status 2')
|
|
791 |
|
|
792 |
# add jump from new to end
|
|
793 |
jump = new_status.add_action('jump', id='_jump')
|
|
794 |
jump.status = '3'
|
|
795 |
|
|
796 |
# add jump form new to middle and from middle to end 2
|
|
797 |
jump = new_status.add_action('jump', id='_jump')
|
|
798 |
jump.status = '2'
|
|
799 |
jump = middle_status.add_action('jump', id='_jump')
|
|
800 |
jump.status = '4'
|
|
801 |
|
|
802 |
workflow.store()
|
|
803 |
|
|
804 |
formdef = FormDef()
|
|
805 |
formdef.name = 'test'
|
|
806 |
formdef.workflow_id = workflow.id
|
|
807 |
formdef.store()
|
|
808 |
|
|
809 |
freezer.move_to(datetime.date(2021, 1, 1))
|
|
810 |
formdata_list = []
|
|
811 |
for i in range(3):
|
|
812 |
formdata = formdef.data_class()()
|
|
813 |
formdata.just_created()
|
|
814 |
formdata_list.append(formdata)
|
|
815 |
|
|
816 |
# one formdata resolved in one day
|
|
817 |
freezer.move_to(datetime.date(2021, 1, 2))
|
|
818 |
formdata_list[0].jump_status('3')
|
|
819 |
formdata_list[0].store()
|
|
820 |
|
|
821 |
# one formdata resolved in two days, passing by middle status
|
|
822 |
formdata_list[1].jump_status('2')
|
|
823 |
freezer.move_to(datetime.date(2021, 1, 3))
|
|
824 |
formdata_list[1].jump_status('4')
|
|
825 |
formdata_list[1].store()
|
|
826 |
|
|
827 |
# one formdata blocked in middle status for three days
|
|
828 |
freezer.move_to(datetime.date(2021, 1, 4))
|
|
829 |
formdata_list[2].jump_status('2')
|
|
830 |
formdata_list[2].store()
|
|
831 |
|
|
832 |
# by default, count forms between initial status and final statuses
|
|
833 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test'))
|
|
834 |
assert resp.json['data'] == {
|
|
835 |
'series': [
|
|
836 |
{
|
|
837 |
'data': [86400.0, 172800.0, 129600.0, 129600.0],
|
|
838 |
'label': 'Time between two statuses',
|
|
839 |
}
|
|
840 |
],
|
|
841 |
'subfilters': [
|
|
842 |
{
|
|
843 |
'id': 'start_status',
|
|
844 |
'label': 'Start status',
|
|
845 |
'options': [
|
|
846 |
{'id': '1', 'label': 'New status'},
|
|
847 |
{'id': '2', 'label': 'Middle status'},
|
|
848 |
{'id': '3', 'label': 'End status'},
|
|
849 |
{'id': '4', 'label': 'End status 2'},
|
|
850 |
],
|
|
851 |
'required': True,
|
|
852 |
'default': '1',
|
|
853 |
},
|
|
854 |
{
|
|
855 |
'default': 'done',
|
|
856 |
'id': 'end_status',
|
|
857 |
'label': 'End status',
|
|
858 |
'options': [
|
|
859 |
{'id': 'done', 'label': 'Any final status'},
|
|
860 |
{'id': '2', 'label': 'Middle status'},
|
|
861 |
{'id': '3', 'label': 'End status'},
|
|
862 |
{'id': '4', 'label': 'End status 2'},
|
|
863 |
],
|
|
864 |
'required': True,
|
|
865 |
},
|
|
866 |
],
|
|
867 |
'x_labels': ['Minimum time', 'Maximum time', 'Mean', 'Median'],
|
|
868 |
}
|
|
869 |
|
|
870 |
assert get_humanized_duration_serie(resp.json) == [
|
|
871 |
'1 day(s) and 0 hour(s)',
|
|
872 |
'2 day(s) and 0 hour(s)',
|
|
873 |
'1 day(s) and 12 hour(s)',
|
|
874 |
'1 day(s) and 12 hour(s)',
|
|
875 |
]
|
|
876 |
|
|
877 |
# specify end status
|
|
878 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test&end_status=3'))
|
|
879 |
assert get_humanized_duration_serie(resp.json) == [
|
|
880 |
'1 day(s) and 0 hour(s)',
|
|
881 |
'1 day(s) and 0 hour(s)',
|
|
882 |
'1 day(s) and 0 hour(s)',
|
|
883 |
'1 day(s) and 0 hour(s)',
|
|
884 |
]
|
|
885 |
|
|
886 |
# specify start status
|
|
887 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test&start_status=2'))
|
|
888 |
assert get_humanized_duration_serie(resp.json) == [
|
|
889 |
'1 day(s) and 0 hour(s)',
|
|
890 |
'1 day(s) and 0 hour(s)',
|
|
891 |
'1 day(s) and 0 hour(s)',
|
|
892 |
'1 day(s) and 0 hour(s)',
|
|
893 |
]
|
|
894 |
|
|
895 |
# specify start and end statuses
|
|
896 |
resp = get_app(pub).get(
|
|
897 |
sign_uri('/api/statistics/resolution-time/?form=test&start_status=2&end_status=4')
|
|
898 |
)
|
|
899 |
assert get_humanized_duration_serie(resp.json) == [
|
|
900 |
'1 day(s) and 0 hour(s)',
|
|
901 |
'1 day(s) and 0 hour(s)',
|
|
902 |
'1 day(s) and 0 hour(s)',
|
|
903 |
'1 day(s) and 0 hour(s)',
|
|
904 |
]
|
|
905 |
|
|
906 |
resp = get_app(pub).get(
|
|
907 |
sign_uri('/api/statistics/resolution-time/?form=test&start_status=1&end_status=2')
|
|
908 |
)
|
|
909 |
assert get_humanized_duration_serie(resp.json) == [
|
|
910 |
'1 day(s) and 0 hour(s)',
|
|
911 |
'3 day(s) and 0 hour(s)',
|
|
912 |
'2 day(s) and 0 hour(s)',
|
|
913 |
'2 day(s) and 0 hour(s)',
|
|
914 |
]
|
|
915 |
|
|
916 |
# unknown statuses
|
|
917 |
default_resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test'))
|
|
918 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test&start_status=42'))
|
|
919 |
assert resp.json == default_resp.json
|
|
920 |
|
|
921 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test&end_status=42'))
|
|
922 |
assert resp.json == default_resp.json
|
|
923 |
|
|
924 |
# specify start and end statuses which does not match any formdata
|
|
925 |
resp = get_app(pub).get(
|
|
926 |
sign_uri('/api/statistics/resolution-time/?form=test&start_status=2&end_status=3')
|
|
927 |
)
|
|
928 |
assert resp.json['data']['series'][0]['data'] == []
|
|
929 |
|
|
930 |
# unknown form
|
|
931 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=xxx'), status=400)
|
|
932 |
|
|
933 |
|
|
934 |
def test_statistics_resolution_time_median(pub, freezer):
|
|
935 |
workflow = Workflow(name='Workflow One')
|
|
936 |
new_status = workflow.add_status(name='New status')
|
|
937 |
workflow.add_status(name='End status')
|
|
938 |
jump = new_status.add_action('jump', id='_jump')
|
|
939 |
jump.status = '2'
|
|
940 |
workflow.store()
|
|
941 |
|
|
942 |
formdef = FormDef()
|
|
943 |
formdef.name = 'test'
|
|
944 |
formdef.workflow_id = workflow.id
|
|
945 |
formdef.store()
|
|
946 |
|
|
947 |
for i in range(2, 11):
|
|
948 |
formdata = formdef.data_class()()
|
|
949 |
freezer.move_to(datetime.date(2021, 1, 1))
|
|
950 |
formdata.just_created()
|
|
951 |
|
|
952 |
if i != 10:
|
|
953 |
# add lots of formdata resolved in a few days
|
|
954 |
freezer.move_to(datetime.date(2021, 1, i))
|
|
955 |
else:
|
|
956 |
# one formdata took 3 months
|
|
957 |
freezer.move_to(datetime.date(2021, 4, 1))
|
|
958 |
|
|
959 |
formdata.jump_status('2')
|
|
960 |
formdata.store()
|
|
961 |
|
|
962 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test'))
|
|
963 |
assert get_humanized_duration_serie(resp.json) == [
|
|
964 |
'1 day(s) and 0 hour(s)', # min
|
|
965 |
'89 day(s) and 22 hour(s)', # max
|
|
966 |
'13 day(s) and 23 hour(s)', # mean
|
|
967 |
'5 day(s) and 0 hour(s)', # median
|
|
968 |
]
|
|
969 |
|
|
970 |
|
|
971 |
def test_statistics_resolution_time_start_end_filter(pub, freezer):
|
|
972 |
workflow = Workflow(name='Workflow One')
|
|
973 |
new_status = workflow.add_status(name='New status')
|
|
974 |
workflow.add_status(name='End status')
|
|
975 |
jump = new_status.add_action('jump', id='_jump')
|
|
976 |
jump.status = '2'
|
|
977 |
workflow.store()
|
|
978 |
|
|
979 |
formdef = FormDef()
|
|
980 |
formdef.name = 'test'
|
|
981 |
formdef.workflow_id = workflow.id
|
|
982 |
formdef.store()
|
|
983 |
|
|
984 |
# create formdata, the latest being the longest to resolve
|
|
985 |
for i in range(1, 10):
|
|
986 |
formdata = formdef.data_class()()
|
|
987 |
freezer.move_to(datetime.date(2021, 1, i))
|
|
988 |
formdata.just_created()
|
|
989 |
freezer.move_to(datetime.date(2021, 1, i * 2))
|
|
990 |
formdata.jump_status('2')
|
|
991 |
formdata.store()
|
|
992 |
|
|
993 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test'))
|
|
994 |
assert get_humanized_duration_serie(resp.json) == [
|
|
995 |
'1 day(s) and 0 hour(s)', # min
|
|
996 |
'9 day(s) and 0 hour(s)', # max
|
|
997 |
'5 day(s) and 0 hour(s)', # mean
|
|
998 |
'5 day(s) and 0 hour(s)', # median
|
|
999 |
]
|
|
1000 |
|
|
1001 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test&start=2021-01-05'))
|
|
1002 |
assert get_humanized_duration_serie(resp.json) == [
|
|
1003 |
'5 day(s) and 0 hour(s)', # min
|
|
1004 |
'9 day(s) and 0 hour(s)', # max
|
|
1005 |
'7 day(s) and 0 hour(s)', # mean
|
|
1006 |
'7 day(s) and 0 hour(s)', # median
|
|
1007 |
]
|
|
1008 |
|
|
1009 |
resp = get_app(pub).get(sign_uri('/api/statistics/resolution-time/?form=test&end=2021-01-05'))
|
|
1010 |
assert get_humanized_duration_serie(resp.json) == [
|
|
1011 |
'1 day(s) and 0 hour(s)', # min
|
|
1012 |
'4 day(s) and 0 hour(s)', # max
|
|
1013 |
'2 day(s) and 12 hour(s)', # mean
|
|
1014 |
'2 day(s) and 12 hour(s)', # median
|
|
1015 |
]
|
|
1016 |
|
|
1017 |
resp = get_app(pub).get(
|
|
1018 |
sign_uri('/api/statistics/resolution-time/?form=test&start=2021-01-04&end=2021-01-05')
|
|
1019 |
)
|
|
1020 |
assert get_humanized_duration_serie(resp.json) == [
|
|
1021 |
'4 day(s) and 0 hour(s)', # min
|
|
1022 |
'4 day(s) and 0 hour(s)', # max
|
|
1023 |
'4 day(s) and 0 hour(s)', # mean
|
|
1024 |
'4 day(s) and 0 hour(s)', # median
|
|
1025 |
]
|