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
Пример #3
0
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"
Пример #4
0
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)
Пример #5
0
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)
Пример #6
0
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'
Пример #8
0
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
Пример #9
0
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))
Пример #10
0
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
Пример #11
0
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
Пример #12
0
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"
Пример #13
0
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
Пример #14
0
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
Пример #15
0
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'
Пример #16
0
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)
Пример #17
0
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'
Пример #18
0
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"
Пример #19
0
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'
Пример #20
0
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"
Пример #21
0
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'
Пример #22
0
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"
Пример #23
0
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
Пример #24
0
    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']))
Пример #25
0
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()
Пример #27
0
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()
Пример #28
0
    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))
Пример #29
0
    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