def test_notify_reviewers_with_cc_and_message(db, mailoutbox, cc, message): """Test time range 2017-7-1 till 2017-7-31.""" # a reviewer which will be notified reviewer_work = UserFactory.create() project_work = ProjectFactory.create() project_work.reviewers.add(reviewer_work) task_work = TaskFactory.create(project=project_work) ReportFactory.create(date=date(2017, 7, 1), task=task_work, verified_by=None) # a reviewer which doesn't have any unverfied reports reviewer_no_work = UserFactory.create() project_no_work = ProjectFactory.create() project_no_work.reviewers.add(reviewer_no_work) task_no_work = TaskFactory.create(project=project_no_work) ReportFactory.create(date=date(2017, 7, 1), task=task_no_work, verified_by=reviewer_no_work) call_command( "notify_reviewers_unverified", "--cc={0}".format(cc), "--message={0}".format(message), ) # checks assert len(mailoutbox) == 1 mail = mailoutbox[0] assert mail.to == [reviewer_work.email] url = ("http://localhost:4200/analysis?fromDate=2017-07-01&" "toDate=2017-07-31&reviewer=%d&editable=1") % reviewer_work.id assert url in mail.body assert message in mail.body assert mail.cc[0] == cc
def test_notify_reviewers(db, mailoutbox): """Test time range 2017-7-1 till 2017-7-31.""" # a reviewer which will be notified reviewer_work = UserFactory.create() project_work = ProjectFactory.create() project_work.reviewers.add(reviewer_work) task_work = TaskFactory.create(project=project_work) ReportFactory.create(date=date(2017, 7, 1), task=task_work, verified_by=None) # a reviewer which doesn't have any unverfied reports reviewer_no_work = UserFactory.create() project_no_work = ProjectFactory.create() project_no_work.reviewers.add(reviewer_no_work) task_no_work = TaskFactory.create(project=project_no_work) ReportFactory.create(date=date(2017, 7, 1), task=task_no_work, verified_by=reviewer_no_work) call_command('notify_reviewers_unverified') # checks assert len(mailoutbox) == 1 mail = mailoutbox[0] assert mail.to == [reviewer_work.email] url = ( 'http://localhost:4200/reschedule?from_date=2017-07-01&' 'to_date=2017-07-31&reviewer=%d' ) % reviewer_work.id assert url in mail.body
def test_task_statistic_list(auth_client, django_assert_num_queries): task_z = TaskFactory.create(name="Z") task_test = TaskFactory.create(name="Test") ReportFactory.create(duration=timedelta(hours=1), task=task_test) ReportFactory.create(duration=timedelta(hours=2), task=task_test) ReportFactory.create(duration=timedelta(hours=2), task=task_z) url = reverse("task-statistic-list") with django_assert_num_queries(4): result = auth_client.get( url, data={ "ordering": "task__name", "include": "task,task.project,task.project.customer", }, ) assert result.status_code == 200 json = result.json() expected_json = [ { "type": "task-statistics", "id": str(task_test.id), "attributes": { "duration": "03:00:00" }, "relationships": { "task": { "data": { "id": str(task_test.id), "type": "tasks" } } }, }, { "type": "task-statistics", "id": str(task_z.id), "attributes": { "duration": "02:00:00" }, "relationships": { "task": { "data": { "id": str(task_z.id), "type": "tasks" } } }, }, ] assert json["data"] == expected_json assert len(json["included"]) == 6 assert json["meta"]["total-time"] == "05:00:00"
def test_task_list_not_archived(auth_client): task = TaskFactory.create(archived=False) TaskFactory.create(archived=True) url = reverse("task-list") response = auth_client.get(url, data={"archived": 0}) assert response.status_code == status.HTTP_200_OK json = response.json() assert len(json["data"]) == 1 assert json["data"][0]["id"] == str(task.id)
def test_task_list_not_archived(auth_client): task = TaskFactory.create(archived=False) TaskFactory.create(archived=True) url = reverse('task-list') response = auth_client.get(url, data={'archived': 0}) assert response.status_code == status.HTTP_200_OK json = response.json() assert len(json['data']) == 1 assert json['data'][0]['id'] == str(task.id)
def test_task_statistic_list(auth_client, django_assert_num_queries): task_z = TaskFactory.create(name='Z') task_test = TaskFactory.create(name='Test') ReportFactory.create(duration=timedelta(hours=1), task=task_test) ReportFactory.create(duration=timedelta(hours=2), task=task_test) ReportFactory.create(duration=timedelta(hours=2), task=task_z) url = reverse('task-statistic-list') with django_assert_num_queries(5): result = auth_client.get(url, data={ 'ordering': 'task__name', 'include': 'task,task.project,task.project.customer' }) assert result.status_code == 200 json = result.json() expected_json = [{ 'type': 'task-statistics', 'id': str(task_test.id), 'attributes': { 'duration': '03:00:00' }, 'relationships': { 'task': { 'data': { 'id': str(task_test.id), 'type': 'tasks' } } } }, { 'type': 'task-statistics', 'id': str(task_z.id), 'attributes': { 'duration': '02:00:00' }, 'relationships': { 'task': { 'data': { 'id': str(task_z.id), 'type': 'tasks' } } } }] assert json['data'] == expected_json assert len(json['included']) == 6 assert json['meta']['total-time'] == '05:00:00'
def test_subscription_project_list(auth_client): customer = CustomerFactory.create() billing_type = BillingTypeFactory() project = ProjectFactory.create(billing_type=billing_type, customer=customer, customer_visible=True) PackageFactory.create_batch(2, billing_type=billing_type) # create spent hours task = TaskFactory.create(project=project) TaskFactory.create(project=project) ReportFactory.create(task=task, duration=timedelta(hours=2)) ReportFactory.create(task=task, duration=timedelta(hours=3)) # not billable reports should not be included in spent hours ReportFactory.create(not_billable=True, task=task, duration=timedelta(hours=4)) # project of same customer but without customer_visible set # should not appear ProjectFactory.create(customer=customer) # create purchased time OrderFactory.create(project=project, acknowledged=True, duration=timedelta(hours=2)) OrderFactory.create(project=project, acknowledged=True, duration=timedelta(hours=4)) # report on different project should not be included in spent time ReportFactory.create(duration=timedelta(hours=2)) # not acknowledged order should not be included in purchased time OrderFactory.create(project=project, duration=timedelta(hours=2)) url = reverse('subscription-project-list') res = auth_client.get(url, data={ 'customer': customer.id, 'ordering': 'id' }) assert res.status_code == HTTP_200_OK json = res.json() assert len(json['data']) == 1 assert json['data'][0]['id'] == str(project.id) attrs = json['data'][0]['attributes'] assert attrs['spent-time'] == '05:00:00' assert attrs['purchased-time'] == '06:00:00'
def test_report_update_bulk(auth_client): task = TaskFactory.create() report = ReportFactory.create(user=auth_client.user) url = reverse("report-bulk") data = { "data": { "type": "report-bulks", "id": None, "relationships": { "task": { "data": { "type": "tasks", "id": task.id } } }, } } response = auth_client.post(url + "?editable=1", data) assert response.status_code == status.HTTP_204_NO_CONTENT report.refresh_from_db() assert report.task == task
def test_activity_create(auth_client): """Should create a new activity and automatically set the user.""" user = auth_client.user task = TaskFactory.create() data = { 'data': { 'type': 'activities', 'id': None, 'attributes': { 'date': '2017-01-01', 'comment': 'Test activity' }, 'relationships': { 'task': { 'data': { 'type': 'tasks', 'id': task.id } } } } } url = reverse('activity-list') response = auth_client.post(url, data) assert response.status_code == status.HTTP_201_CREATED json = response.json() assert (int(json['data']['relationships']['user']['data']['id']) == int( user.id))
def test_report_update_bulk(auth_client): task = TaskFactory.create() report = ReportFactory.create(user=auth_client.user) url = reverse('report-bulk') data = { 'data': { 'type': 'report-bulks', 'id': None, 'relationships': { 'task': { 'data': { 'type': 'tasks', 'id': task.id } } }, } } response = auth_client.post(url + '?editable=1', data) assert response.status_code == status.HTTP_204_NO_CONTENT report.refresh_from_db() assert report.task == task
def test_notify_supervisors(db, mailoutbox): """Test time range 2017-7-17 till 2017-7-23.""" start = date(2017, 7, 14) # supervisee with short time supervisee = UserFactory.create() supervisor = UserFactory.create() supervisee.supervisors.add(supervisor) EmploymentFactory.create(user=supervisee, start_date=start, percentage=100) workdays = rrule( DAILY, dtstart=start, until=date.today(), # range is excluding last byweekday=range(MO.weekday, FR.weekday + 1), ) task = TaskFactory.create() for dt in workdays: ReportFactory.create(user=supervisee, date=dt, task=task, duration=timedelta(hours=7)) call_command("notify_supervisors_shorttime") # checks assert len(mailoutbox) == 1 mail = mailoutbox[0] assert mail.to == [supervisor.email] body = mail.body assert "Time range: July 17, 2017 - July 23, 2017\nRatio: 0.9" in body expected = ("{0} 35.0/42.5 (Ratio 0.82 Delta -7.5 Balance -9.0)").format( supervisee.get_full_name()) assert expected in body
def test_work_report_multiple_projects(auth_client, django_assert_num_queries): NUM_PROJECTS = 2 user = auth_client.user customer = CustomerFactory.create(name="Customer") report_date = date(2017, 8, 17) for i in range(NUM_PROJECTS): project = ProjectFactory.create(customer=customer, name="Project{0}".format(i)) task = TaskFactory.create(project=project) ReportFactory.create_batch(10, user=user, task=task, date=report_date) url = reverse("work-report-list") with django_assert_num_queries(3): res = auth_client.get(url, data={"user": auth_client.user.id, "verified": 0}) assert res.status_code == status.HTTP_200_OK assert "20170901-WorkReports.zip" in (res["Content-Disposition"]) content = io.BytesIO(res.content) with ZipFile(content, "r") as zipfile: for i in range(NUM_PROJECTS): ods_content = zipfile.read( "1708-20170901-Customer-Project{0}.ods".format(i) ) doc = ezodf.opendoc(io.BytesIO(ods_content)) table = doc.sheets[0] assert table["C5"].value == "2017-08-17" assert table["C6"].value == "2017-08-17"
def test_task_detail(auth_client): task = TaskFactory.create() url = reverse('task-detail', args=[task.id]) response = auth_client.get(url) assert response.status_code == status.HTTP_200_OK
def test_task_delete(auth_client): task = TaskFactory.create() url = reverse('task-detail', args=[task.id]) response = auth_client.delete(url) assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED
def test_work_report_single_project(auth_client, django_assert_num_queries): user = auth_client.user # spaces should be replaced with underscore customer = CustomerFactory.create(name='Customer Name') # slashes should be dropped from file name project = ProjectFactory.create(customer=customer, name='Project/') task = TaskFactory.create(project=project) ReportFactory.create_batch( 10, user=user, verified_by=user, task=task, date=date(2017, 8, 17) ) url = reverse('work-report-list') with django_assert_num_queries(4): res = auth_client.get(url, data={ 'user': auth_client.user.id, 'from_date': '2017-08-01', 'to_date': '2017-08-31', 'verified': 1 }) assert res.status_code == HTTP_200_OK assert '1708-20170901-Customer_Name-Project.ods' in ( res['Content-Disposition'] ) content = io.BytesIO(res.content) doc = ezodf.opendoc(content) table = doc.sheets[0] assert table['C5'].value == '2017-08-01' assert table['C6'].value == '2017-08-31' assert table['C9'].value == 'Test User' assert table['C10'].value == 'Test User'
def test_activity_create(auth_client): """Should create a new activity and automatically set the user.""" user = auth_client.user task = TaskFactory.create() data = { "data": { "type": "activities", "id": None, "attributes": { "from-time": "08:00", "date": "2017-01-01", "comment": "Test activity", }, "relationships": { "task": { "data": { "type": "tasks", "id": task.id } } }, } } url = reverse("activity-list") response = auth_client.post(url, data) assert response.status_code == status.HTTP_201_CREATED json = response.json() assert int(json["data"]["relationships"]["user"]["data"]["id"]) == int( user.id)
def test_work_report_multiple_projects(auth_client, django_assert_num_queries): NUM_PROJECTS = 2 user = auth_client.user customer = CustomerFactory.create(name='Customer') report_date = date(2017, 8, 17) for i in range(NUM_PROJECTS): project = ProjectFactory.create( customer=customer, name='Project{0}'.format(i) ) task = TaskFactory.create(project=project) ReportFactory.create_batch(10, user=user, task=task, date=report_date) url = reverse('work-report-list') with django_assert_num_queries(4): res = auth_client.get(url, data={ 'user': auth_client.user.id, 'verified': 0 }) assert res.status_code == HTTP_200_OK assert '20170901-WorkReports.zip' in ( res['Content-Disposition'] ) content = io.BytesIO(res.content) with ZipFile(content, 'r') as zipfile: for i in range(NUM_PROJECTS): ods_content = zipfile.read( '1708-20170901-Customer-Project{0}.ods'.format(i) ) doc = ezodf.opendoc(io.BytesIO(ods_content)) table = doc.sheets[0] assert table['C5'].value == '2017-08-17' assert table['C6'].value == '2017-08-17'
def test_work_report_single_project(auth_client, django_assert_num_queries): user = auth_client.user # spaces should be replaced with underscore customer = CustomerFactory.create(name="Customer Name") # slashes should be dropped from file name project = ProjectFactory.create(customer=customer, name="Project/") task = TaskFactory.create(project=project) ReportFactory.create_batch(10, user=user, verified_by=user, task=task, date=date(2017, 8, 17)) url = reverse("work-report-list") with django_assert_num_queries(3): res = auth_client.get( url, data={ "user": auth_client.user.id, "from_date": "2017-08-01", "to_date": "2017-08-31", "verified": 1, }, ) assert res.status_code == status.HTTP_200_OK assert "1708-20170901-Customer_Name-Project.ods" in ( res["Content-Disposition"]) content = io.BytesIO(res.content) doc = ezodf.opendoc(content) table = doc.sheets[0] assert table["C5"].value == "2017-08-01" assert table["C6"].value == "2017-08-31" assert table["C9"].value == "Test User" assert table["C10"].value == "Test User"
def test_task_detail_no_reports(auth_client): task = TaskFactory.create() url = reverse('task-detail', args=[task.id]) res = auth_client.get(url) assert res.status_code == status.HTTP_200_OK json = res.json() assert json['meta']['spent-time'] == '00:00:00'
def test_task_detail_no_reports(auth_client): task = TaskFactory.create() url = reverse("task-detail", args=[task.id]) res = auth_client.get(url) assert res.status_code == status.HTTP_200_OK json = res.json() assert json["meta"]["spent-time"] == "00:00:00"
def test_task_detail_with_reports(auth_client): task = TaskFactory.create() ReportFactory.create_batch(5, task=task, duration=timedelta(minutes=30)) url = reverse('task-detail', args=[task.id]) res = auth_client.get(url) assert res.status_code == status.HTTP_200_OK json = res.json() assert json['meta']['spent-time'] == '02:30:00'
def test_project_detail_with_reports(auth_client): project = ProjectFactory.create() task = TaskFactory.create(project=project) ReportFactory.create_batch(10, task=task, duration=timedelta(hours=1)) url = reverse("project-detail", args=[project.id]) res = auth_client.get(url) assert res.status_code == status.HTTP_200_OK json = res.json() assert json["meta"]["spent-time"] == "10:00:00"
def test_report_list_filter_cost_center(auth_client): cost_center = CostCenterFactory.create() # 1st valid case: report with task of given cost center # but different project cost center task = TaskFactory.create(cost_center=cost_center) report_task = ReportFactory.create(task=task) # 2nd valid case: report with project of given cost center project = ProjectFactory.create(cost_center=cost_center) task = TaskFactory.create(cost_center=None, project=project) report_project = ReportFactory.create(task=task) # Invalid case: report without cost center project = ProjectFactory.create(cost_center=None) task = TaskFactory.create(cost_center=None, project=project) ReportFactory.create(task=task) url = reverse("report-list") res = auth_client.get(url, data={"cost_center": cost_center.id}) assert res.status_code == status.HTTP_200_OK json = res.json() assert len(json["data"]) == 2 ids = {int(entry["id"]) for entry in json["data"]} assert {report_task.id, report_project.id} == ids
def test_report_update_owner(self): """Should update an existing report.""" report = self.reports[0] task = TaskFactory.create() data = { 'data': { 'type': 'reports', 'id': report.id, 'attributes': { 'comment': 'foobar', 'duration': '01:00:00', 'date': '2017-02-04' }, 'relationships': { 'task': { 'data': { 'type': 'tasks', 'id': task.id } } } } } url = reverse('report-detail', args=[report.id]) noauth_res = self.noauth_client.patch(url, data) user_res = self.client.patch(url, data) assert noauth_res.status_code == HTTP_401_UNAUTHORIZED assert user_res.status_code == HTTP_200_OK result = self.result(user_res) assert (result['data']['attributes']['comment'] == data['data'] ['attributes']['comment']) assert (result['data']['attributes']['duration'] == data['data'] ['attributes']['duration']) assert (result['data']['attributes']['date'] == data['data'] ['attributes']['date']) assert (int( result['data']['relationships']['task']['data']['id']) == int( data['data']['relationships']['task']['data']['id']))
def test_work_report_count( auth_client, settings, settings_count, given_count, expected_status ): user = auth_client.user customer = CustomerFactory.create(name="Customer") report_date = date(2017, 8, 17) settings.WORK_REPORTS_EXPORT_MAX_COUNT = settings_count project = ProjectFactory.create(customer=customer) task = TaskFactory.create(project=project) ReportFactory.create_batch(given_count, user=user, task=task, date=report_date) url = reverse("work-report-list") res = auth_client.get(url, data={"user": auth_client.user.id, "verified": 0}) assert res.status_code == expected_status
def test_redmine_report_no_estimated_time(db, freezer, mocker): redmine_instance = mocker.MagicMock() issue = mocker.MagicMock() redmine_instance.issue.get.return_value = issue redmine_class = mocker.patch("redminelib.Redmine") redmine_class.return_value = redmine_instance freezer.move_to("2017-07-28") project = ProjectFactory.create(estimated_time=None) task = TaskFactory.create(project=project) report = ReportFactory.create(comment="ADSY <=> Other", task=task) RedmineProject.objects.create(project=report.task.project, issue_id=1000) freezer.move_to("2017-07-31") call_command("redmine_report", last_days=7) redmine_instance.issue.get.assert_called_once_with(1000) issue.save.assert_called_once_with()
def test_redmine_report_no_estimated_time(db, freezer, mocker): redmine_instance = mocker.MagicMock() issue = mocker.MagicMock() redmine_instance.issue.get.return_value = issue redmine_class = mocker.patch('redminelib.Redmine') redmine_class.return_value = redmine_instance freezer.move_to('2017-07-28') project = ProjectFactory.create(estimated_time=None) task = TaskFactory.create(project=project) report = ReportFactory.create(comment='ADSY <=> Other', task=task) RedmineProject.objects.create(project=report.task.project, issue_id=1000) freezer.move_to('2017-07-31') call_command('redmine_report', options={'--last-days': '7'}) redmine_instance.issue.get.assert_called_once_with(1000) issue.save.assert_called_once_with()
def test_absence_update_on_create_report(self): """Should update the absence after creating a new report.""" task = TaskFactory.create() type = AbsenceTypeFactory.create(fill_worktime=True) day = date(2017, 5, 3) employment = EmploymentFactory.create(user=self.user, start_date=day) absence = AbsenceFactory.create(user=self.user, date=day, type=type) Report.objects.create(user=self.user, date=day, task=task, duration=timedelta(hours=1)) assert (Absence.objects.get( pk=absence.pk).duration == employment.worktime_per_day - timedelta(hours=1))
def test_report_create(self): """Should create a new report and automatically set the user.""" task = TaskFactory.create() data = { 'data': { 'type': 'reports', 'id': None, 'attributes': { 'comment': 'foo', 'duration': '00:50:00', 'date': '2017-02-01' }, 'relationships': { 'task': { 'data': { 'type': 'tasks', 'id': task.id } }, 'verified-by': { 'data': None }, } } } url = reverse('report-list') noauth_res = self.noauth_client.post(url, data) user_res = self.client.post(url, data) assert noauth_res.status_code == HTTP_401_UNAUTHORIZED assert user_res.status_code == HTTP_201_CREATED result = self.result(user_res) assert (int( result['data']['relationships']['user']['data']['id']) == int( self.user.id)) assert (int( result['data']['relationships']['task']['data']['id']) == int( data['data']['relationships']['task']['data']['id']))
def test_notify_reviewers(db, mailoutbox): """Test time range 2017-7-1 till 2017-7-31.""" # a reviewer which will be notified reviewer_work = UserFactory.create() project_work = ProjectFactory.create() project_work.reviewers.add(reviewer_work) task_work = TaskFactory.create(project=project_work) ReportFactory.create(date=date(2017, 7, 1), task=task_work, verified_by=None) call_command("notify_reviewers_unverified") # checks assert len(mailoutbox) == 1 mail = mailoutbox[0] assert mail.to == [reviewer_work.email] url = ("http://localhost:4200/analysis?fromDate=2017-07-01&" "toDate=2017-07-31&reviewer=%d&editable=1") % reviewer_work.id assert url in mail.body