示例#1
0
    def test_currency(self):
        instance = PublicsCurrencyFactory.build(name='xyz')
        self.assertEqual(str(instance), 'xyz')

        # Polish Zloty
        instance = PublicsCurrencyFactory.build(name='z\u0142oty')
        self.assertEqual(str(instance), 'z\u0142oty')
    def setUpTestData(cls):
        cls.unicef_staff = UserFactory(is_staff=True)

        cls.currency_usd = PublicsCurrencyFactory(code='USD')
        cls.currency_huf = PublicsCurrencyFactory(name='Hungarian Forint',
                                                  code='HUF')

        cls.user_et_1 = PublicsTravelExpenseTypeFactory(
            title='Train cost',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)
        cls.user_et_2 = PublicsTravelExpenseTypeFactory(
            title='Other expenses',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)
        cls.ta_et = PublicsTravelExpenseTypeFactory(title='Travel agent')

        netherlands = PublicsCountryFactory(name='Netherlands',
                                            long_name='Netherlands')
        hungary = PublicsCountryFactory(name='Hungary', long_name='Hungary')
        denmark = PublicsCountryFactory(name='Denmark', long_name='Denmark')
        germany = PublicsCountryFactory(name='Germany', long_name='Germany')

        cls.amsterdam = PublicsDSARegionFactory(country=netherlands,
                                                area_name='Amsterdam',
                                                area_code='ds1')
        PublicsDSARateFactory(region=cls.amsterdam,
                              dsa_amount_usd=100,
                              dsa_amount_60plus_usd=60)

        cls.budapest = PublicsDSARegionFactory(country=hungary,
                                               area_name='Budapest',
                                               area_code='ds2')
        PublicsDSARateFactory(region=cls.budapest,
                              dsa_amount_usd=200,
                              dsa_amount_60plus_usd=120)

        cls.copenhagen = PublicsDSARegionFactory(country=denmark,
                                                 area_name='Copenhagen',
                                                 area_code='ds3')
        PublicsDSARateFactory(region=cls.copenhagen,
                              dsa_amount_usd=300,
                              dsa_amount_60plus_usd=180)

        cls.dusseldorf = PublicsDSARegionFactory(country=germany,
                                                 area_name='Duesseldorf',
                                                 area_code='ds4')
        PublicsDSARateFactory(region=cls.dusseldorf,
                              dsa_amount_usd=400,
                              dsa_amount_60plus_usd=240)

        # Delete default items created by factory
        cls.travel = TravelFactory(currency=cls.currency_huf)
        cls.travel.itinerary.all().delete()
        cls.travel.expenses.all().delete()
        cls.travel.deductions.all().delete()
示例#3
0
    def test_travel_creation(self):
        dsaregion = DSARegion.objects.first()
        currency = PublicsCurrencyFactory()
        location = LocationFactory()

        data = {
            '0': {},
            '1': {
                'date': '2016-12-16',
                'breakfast': False,
                'lunch': False,
                'dinner': False,
                'accomodation': False,
                'no_dsa': False
            },
            'itinerary': [{
                'airlines': [],
                'overnight_travel': False,
                'origin': 'a',
                'destination': 'b',
                'dsa_region': dsaregion.id,
                'departure_date': '2016-12-15T15:02:13+01:00',
                'arrival_date': '2016-12-16T15:02:13+01:00',
                'mode_of_travel': ModeOfTravel.BOAT
            }],
            'activities': [{
                'is_primary_traveler': True,
                'locations': [location.id],
                'travel_type': TravelType.ADVOCACY,
                'date': '2016-12-15T15:02:13+01:00'
            }],
            'ta_required':
            True,
            'international_travel':
            False,
            'mode_of_travel': [ModeOfTravel.BOAT],
            'traveler':
            self.traveler.id,
            'supervisor':
            self.unicef_staff.id,
            'start_date':
            '2016-12-15T15:02:13+01:00',
            'end_date':
            '2016-12-16T15:02:13+01:00',
            'estimated_travel_cost':
            '123',
            'currency':
            currency.id,
            'purpose':
            'Purpose',
            'additional_note':
            'Notes'
        }

        response = self.forced_auth_req('post',
                                        reverse('t2f:travels:list:index'),
                                        data=data,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(len(response_json['itinerary']), 1)
示例#4
0
 def test_command(self):
     # Not able to actually create a tenant, so checking
     # the raises exception that this is where the command
     # failed
     name = "test"
     PublicsCurrencyFactory(code="USD")
     with self.assertRaisesRegexp(CommandError, "Can't create tenant"):
         call_command("add_country", name)
示例#5
0
    def test_overlapping_trips(self):
        currency = PublicsCurrencyFactory()
        dsa_region = PublicsDSARegionFactory()

        data = {'deductions': [],
                'itinerary': [{'origin': 'Berlin',
                               'destination': 'Budapest',
                               'departure_date': '2017-04-07T17:06:55.821490',
                               'arrival_date': '2017-04-08T17:06:55.821490',
                               'dsa_region': dsa_region.id,
                               'overnight_travel': False,
                               'mode_of_travel': ModeOfTravel.RAIL,
                               'airlines': []},
                              {'origin': 'Budapest',
                               'destination': 'Berlin',
                               'departure_date': '2017-05-20T12:06:55.821490',
                               'arrival_date': '2017-05-21T12:06:55.821490',
                               'dsa_region': dsa_region.id,
                               'overnight_travel': False,
                               'mode_of_travel': ModeOfTravel.RAIL,
                               'airlines': []}],
                'activities': [],
                'cost_assignments': [],
                'clearances': {'medical_clearance': 'requested',
                               'security_clearance': 'requested',
                               'security_course': 'requested'},
                'ta_required': True,
                'international_travel': False,
                'mode_of_travel': [ModeOfTravel.BOAT],
                'traveler': self.traveler.id,
                'supervisor': self.unicef_staff.id,
                'start_date': '2017-04-07T15:02:13+01:00',
                'end_date': '2017-05-22T15:02:13+01:00',
                'currency': currency.id,
                'purpose': 'Purpose',
                'additional_note': 'Notes'}

        response = self.forced_auth_req('post', reverse('t2f:travels:list:index'),
                                        data=data, user=self.traveler)
        response_json = json.loads(response.rendered_content)

        travel_id = response_json['id']

        with freeze_time(datetime(2017, 4, 14, 16, 00, tzinfo=UTC)):
            response = self.forced_auth_req('post', reverse('t2f:travels:details:state_change',
                                                            kwargs={'travel_pk': travel_id,
                                                                    'transition_name': 'submit_for_approval'}),
                                            data=response_json, user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json,
                         {'non_field_errors': ['You have an existing trip with overlapping dates. '
                                               'Please adjust your trip accordingly.']})
示例#6
0
    def _prepare_test(self):
        currency = PublicsCurrencyFactory()
        expense_type = PublicsTravelExpenseTypeFactory()
        dsaregion = PublicsDSARegionFactory()
        airlines = PublicsAirlineCompanyFactory()

        data = {'cost_assignments': [],
                'deductions': [{'date': '2016-11-03',
                                'breakfast': True,
                                'lunch': True,
                                'dinner': False,
                                'accomodation': True}],
                'itinerary': [{'origin': 'Berlin',
                               'destination': 'Budapest',
                               'departure_date': '2016-11-15T12:06:55.821490',
                               'arrival_date': '2016-11-16T12:06:55.821490',
                               'dsa_region': dsaregion.id,
                               'overnight_travel': False,
                               'mode_of_travel': ModeOfTravel.RAIL,
                               'airlines': [airlines.id]},
                              {'origin': 'Budapest',
                               'destination': 'Berlin',
                               'departure_date': '2016-11-16T12:06:55.821490',
                               'arrival_date': '2016-11-17T12:06:55.821490',
                               'dsa_region': dsaregion.id,
                               'overnight_travel': False,
                               'mode_of_travel': ModeOfTravel.RAIL,
                               'airlines': [airlines.id]}],
                'traveler': self.traveler.id,
                'ta_required': True,
                'supervisor': self.unicef_staff.id,
                'expenses': [{'amount': '120',
                              'type': expense_type.id,
                              'currency': currency.id,
                              'document_currency': currency.id}]}
        response = self.forced_auth_req('post', reverse('t2f:travels:list:index'), data=data, user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['cost_summary']['preserved_expenses'], None)

        travel_id = response_json['id']

        response = self.forced_auth_req('post', reverse('t2f:travels:details:state_change',
                                                        kwargs={'travel_pk': travel_id,
                                                                'transition_name': 'submit_for_approval'}),
                                        data=data, user=self.traveler)

        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['cost_summary']['preserved_expenses'], None)

        return travel_id, data
 def test_init(self):
     currency_usd = PublicsCurrencyFactory(code='USD')
     travel = TravelFactory(currency=currency_usd)
     expense_type = PublicsTravelExpenseTypeFactory(
         title='Train cost',
         vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)
     expense = ExpenseFactory(travel=travel,
                              type=expense_type,
                              currency=currency_usd,
                              amount=100)
     dto = ExpenseDTO("vendor_number", expense)
     self.assertEqual(dto.vendor_number, "vendor_number")
     self.assertEqual(dto.label, expense_type.title)
     self.assertEqual(dto.currency, currency_usd)
     self.assertEqual(dto.amount, 100)
示例#8
0
    def prepare_travel(self):
        # Currencies
        huf = PublicsCurrencyFactory(name='HUF', code='huf')

        # Add wbs/grant/fund
        wbs_1 = PublicsWBSFactory(name='WBS #1')
        grant_1 = PublicsGrantFactory(name='Grant #1')
        wbs_1.grants.add(grant_1)
        fund_1 = PublicsFundFactory(name='Fund #1')
        grant_1.funds.add(fund_1)

        dsa_region = PublicsDSARegionFactory()
        PublicsDSARateFactory(region=dsa_region)

        # Expense types
        et_t_food = PublicsTravelExpenseTypeFactory(
            title='Food',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER
        )

        # Make a travel
        travel = Travel.objects.create(traveler=self.traveler,
                                       supervisor=self.unicef_staff,
                                       currency=huf)

        # Add expenses
        Expense.objects.create(travel=travel,
                               type=et_t_food,
                               currency=huf,
                               amount=35)

        ItineraryItemFactory(travel=travel,
                             departure_date=datetime(2017, 5, 10, tzinfo=UTC),
                             arrival_date=datetime(2017, 5, 11, tzinfo=UTC),
                             dsa_region=dsa_region)
        ItineraryItemFactory(travel=travel,
                             departure_date=datetime(2017, 5, 20, tzinfo=UTC),
                             arrival_date=datetime(2017, 5, 21, tzinfo=UTC),
                             dsa_region=dsa_region)

        # Add cost assignments
        CostAssignment.objects.create(travel=travel,
                                      share=100,
                                      wbs=wbs_1,
                                      grant=grant_1,
                                      fund=fund_1)

        return travel
示例#9
0
    def test_daylight_saving(self):
        budapest_tz = pytz.timezone('Europe/Budapest')
        self.travel.end_date = budapest_tz.localize(datetime(2017, 10, 29, 2, 0), is_dst=True)
        self.travel.save()

        # Same date as the previous, but it's already after daylight saving
        start_date = budapest_tz.localize(datetime(2017, 10, 29, 2, 0), is_dst=False).isoformat()

        currency = PublicsCurrencyFactory()
        dsa_region = PublicsDSARegionFactory()

        data = {'deductions': [],
                'itinerary': [{'origin': 'Berlin',
                               'destination': 'Budapest',
                               'departure_date': '2017-04-14T17:06:55.821490',
                               'arrival_date': '2017-04-15T17:06:55.821490',
                               'dsa_region': dsa_region.id,
                               'overnight_travel': False,
                               'mode_of_travel': ModeOfTravel.RAIL,
                               'airlines': []},
                              {'origin': 'Budapest',
                               'destination': 'Berlin',
                               'departure_date': '2017-05-20T12:06:55.821490',
                               'arrival_date': '2017-05-21T12:06:55.821490',
                               'dsa_region': dsa_region.id,
                               'overnight_travel': False,
                               'mode_of_travel': ModeOfTravel.RAIL,
                               'airlines': []}],
                'activities': [],
                'cost_assignments': [],
                'clearances': {'medical_clearance': 'requested',
                               'security_clearance': 'requested',
                               'security_course': 'requested'},
                'ta_required': True,
                'international_travel': False,
                'mode_of_travel': [ModeOfTravel.BOAT],
                'traveler': self.traveler.id,
                'supervisor': self.unicef_staff.id,
                'start_date': start_date,
                'end_date': '2017-05-22T15:02:13+00:00',
                'currency': currency.id,
                'purpose': 'Purpose',
                'additional_note': 'Notes'}

        response = self.forced_auth_req('post', reverse('t2f:travels:list:index'),
                                        data=data, user=self.traveler)
        self.assertEqual(response.status_code, 201)
示例#10
0
    def test_cost_summary(self):
        # Currencies
        huf = PublicsCurrencyFactory(name='HUF', code='huf')

        # Expense types
        et_t_food = PublicsTravelExpenseTypeFactory(
            title='Food',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)
        et_t_travel = PublicsTravelExpenseTypeFactory(
            title='Travel',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)
        et_t_other = PublicsTravelExpenseTypeFactory(
            title='Other',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)

        # Make a travel
        travel = Travel.objects.create(traveler=self.traveler,
                                       supervisor=self.unicef_staff,
                                       currency=huf)

        # Add expenses
        Expense.objects.create(travel=travel,
                               type=et_t_food,
                               currency=huf,
                               amount=35)

        Expense.objects.create(travel=travel,
                               type=et_t_travel,
                               currency=huf,
                               amount=50)

        Expense.objects.create(travel=travel,
                               type=et_t_other,
                               currency=huf,
                               amount=15)

        Expense.objects.create(travel=travel,
                               type=et_t_travel,
                               currency=huf,
                               amount=None)

        # This should not raise 500
        travel.cost_summary
示例#11
0
    def test_local_currency(self):
        """Verify the local_currency portion of the response in two parts"""
        # By default the test user has no local currency set. If that changes, this test will break, so I assert
        # that first.
        self.assertIsNone(self.user.profile.country.local_currency)

        # Verify None returned when no local currency set
        response = self.forced_auth_req('get', self.url)
        d = self._assertResponseFundamentals(response)
        self.assertIsNone(d['local_currency'])

        # Associate a currency with the test user's country and ensure it's returned.
        currency = PublicsCurrencyFactory()
        self.user.profile.country.local_currency = currency
        self.user.profile.country.save()

        response = self.forced_auth_req('get', self.url)
        d = self._assertResponseFundamentals(response)

        self.assertEqual(d['local_currency'], currency.id)
示例#12
0
    def test_personal_number_usage(self):
        travel = self.prepare_travel()

        travel_agent_expense_type = PublicsTravelExpenseTypeFactory(
            title='Travel Agent',
            vendor_number='trav01'
        )

        eur = PublicsCurrencyFactory(name='EUR', code='eur')

        # Add expenses
        Expense.objects.create(travel=travel,
                               type=travel_agent_expense_type,
                               currency=eur,
                               amount=35)

        # Generate invoice
        self.make_invoices(travel)

        response = self.forced_auth_req('get', reverse('t2f:vision_invoice_export'), user=self.unicef_staff)
        xml_data = response.content.decode('utf-8')

        self.assertEqual(xml_data.count('<pernr />'), 1)
        self.assertEqual(xml_data.count('<pernr>{}</pernr>'.format(self.traveler.profile.staff_id)), 1)
示例#13
0
    def test_finance_export(self):
        currency_usd = PublicsCurrencyFactory(code="USD")
        travel = TravelFactory(traveler=self.traveler,
                               supervisor=self.unicef_staff,
                               start_date=datetime(2016, 11, 20, tzinfo=UTC),
                               end_date=datetime(2016, 12, 5, tzinfo=UTC),
                               mode_of_travel=[ModeOfTravel.PLANE, ModeOfTravel.CAR, ModeOfTravel.RAIL])
        travel.expenses.all().delete()
        ExpenseFactory(travel=travel, amount=Decimal('500'), currency=currency_usd)

        travel_2 = TravelFactory(traveler=self.traveler,
                                 supervisor=self.unicef_staff,
                                 start_date=datetime(2016, 11, 20, tzinfo=UTC),
                                 end_date=datetime(2016, 12, 5, tzinfo=UTC),
                                 mode_of_travel=None)
        travel_2.expenses.all().delete()
        ExpenseFactory(travel=travel_2, amount=Decimal('200'), currency=currency_usd)
        ExpenseFactory(travel=travel_2, amount=Decimal('100'), currency=None)

        with self.assertNumQueries(27):
            response = self.forced_auth_req('get', reverse('t2f:travels:list:finance_export'),
                                            user=self.unicef_staff)
        export_csv = csv.reader(StringIO(response.content.decode('utf-8')))
        rows = [r for r in export_csv]

        self.assertEqual(len(rows), 3)

        # check header
        self.assertEqual(rows[0],
                         ['reference_number',
                          'traveler',
                          'office',
                          'section',
                          'status',
                          'supervisor',
                          'start_date',
                          'end_date',
                          'purpose_of_travel',
                          'mode_of_travel',
                          'international_travel',
                          'require_ta',
                          'dsa_total',
                          'expense_total',
                          'deductions_total'])

        self.assertEqual(rows[1],
                         ['{}/1'.format(datetime.now().year),
                          'John Doe',
                          'An Office',
                          travel.sector.name,
                          'planned',
                          'Jakab Gipsz',
                          '20-Nov-2016',
                          '05-Dec-2016',
                          travel.purpose,
                          'Plane, Car, Rail',
                          'No',
                          'Yes',
                          '0.00',
                          '500 USD',
                          '0.00'])

        self.assertEqual(rows[2],
                         ['{}/2'.format(datetime.now().year),
                          'John Doe',
                          'An Office',
                          travel_2.sector.name,
                          'planned',
                          'Jakab Gipsz',
                          '20-Nov-2016',
                          '05-Dec-2016',
                          travel_2.purpose,
                          '',
                          'No',
                          'Yes',
                          '0.00',
                          '200 USD',
                          '0.00'])
示例#14
0
    def test_invoice_export(self):
        # Setting up initial data
        wbs_1 = PublicsWBSFactory(name='2060/A0/12/1222')
        wbs_2 = PublicsWBSFactory(name='2060/A0/12/1214')

        grant_1 = PublicsGrantFactory(name='SM130147')
        grant_2 = PublicsGrantFactory(name='SM130952')

        fund_1 = PublicsFundFactory(name='BMA')
        fund_2 = PublicsFundFactory(name='NON-GRANT')

        wbs_1.grants.add(grant_1)
        wbs_2.grants.add(grant_2)

        grant_1.funds.add(fund_1)
        grant_2.funds.add(fund_2)

        usd = PublicsCurrencyFactory(name='USD', code='usd')

        # Setting up test data
        travel_1 = TravelFactory(traveler=self.traveler, supervisor=self.unicef_staff)
        travel_2 = TravelFactory(traveler=self.traveler, supervisor=self.unicef_staff)

        # Successful invoice
        invoice_1 = InvoiceFactory(travel=travel_1,
                                   currency=usd,
                                   business_area='2060',
                                   status=Invoice.SUCCESS,
                                   vendor_number='100009998',
                                   amount=Decimal('1232.12'),
                                   vision_fi_id='FI12345',
                                   messages=['Payment was made.'])

        InvoiceItemFactory(invoice=invoice_1,
                           wbs=wbs_1,
                           grant=grant_1,
                           fund=fund_1,
                           amount=Decimal('1232.12'))

        # Failed invoice
        invoice_2 = InvoiceFactory(travel=travel_1,
                                   currency=usd,
                                   business_area='2060',
                                   status=Invoice.ERROR,
                                   vendor_number='100009998',
                                   amount=Decimal('123'),
                                   messages=['Payment failed. Not enough money'])

        InvoiceItemFactory(invoice=invoice_2,
                           wbs=wbs_1,
                           grant=grant_1,
                           fund=fund_1,
                           amount=Decimal('123'))

        # 2 item invoice
        invoice_3 = InvoiceFactory(travel=travel_2,
                                   currency=usd,
                                   business_area='2060',
                                   status=Invoice.PROCESSING,
                                   vendor_number='12343424',
                                   amount=Decimal('1919.11'))

        InvoiceItemFactory(invoice=invoice_3,
                           wbs=wbs_1,
                           grant=grant_1,
                           fund=fund_1,
                           amount=Decimal('1000'))

        InvoiceItemFactory(invoice=invoice_3,
                           wbs=wbs_2,
                           grant=grant_2,
                           fund=fund_2,
                           amount=Decimal('919.11'))

        with self.assertNumQueries(1):
            response = self.forced_auth_req('get', reverse('t2f:travels:list:invoice_export'),
                                            user=self.unicef_staff)
        export_csv = csv.reader(StringIO(response.content.decode('utf-8')))
        rows = [r for r in export_csv]

        self.assertEqual(len(rows), 5)

        self.assertEqual(rows[0],
                         ['reference_number',
                          'ta_number',
                          'vendor_number',
                          'currency',
                          'total_amount',
                          'status',
                          'message',
                          'vision_fi_doc',
                          'wbs',
                          'grant',
                          'fund',
                          'amount'])

        self.assertEqual(rows[1],
                         ['2060/{}/1/01'.format(datetime.now().year),
                          '{}/1'.format(datetime.now().year),
                          '100009998',
                          'USD',
                          '1232.1200',
                          'success',
                          'Payment was made.',
                          'FI12345',
                          '2060/A0/12/1222',
                          'SM130147',
                          'BMA',
                          '1232.1200'])

        self.assertEqual(rows[2],
                         ['2060/{}/1/02'.format(datetime.now().year),
                          '{}/1'.format(datetime.now().year),
                          '100009998',
                          'USD',
                          '123.0000',
                          'error',
                          'Payment failed. Not enough money',
                          '',
                          '2060/A0/12/1222',
                          'SM130147',
                          'BMA',
                          '123.0000'])

        self.assertEqual(rows[3],
                         ['2060/{}/2/01'.format(datetime.now().year),
                          '{}/2'.format(datetime.now().year),
                          '12343424',
                          'USD',
                          '1919.1100',
                          'processing',
                          '',
                          '',
                          '2060/A0/12/1222',
                          'SM130147',
                          'BMA',
                          '1000.0000'])

        self.assertEqual(rows[4],
                         ['2060/{}/2/01'.format(datetime.now().year),
                          '{}/2'.format(datetime.now().year),
                          '12343424',
                          'USD',
                          '1919.1100',
                          'processing',
                          '',
                          '',
                          '2060/A0/12/1214',
                          'SM130952',
                          'NON-GRANT',
                          '919.1100'])
示例#15
0
    def test_almost_overlapping_trips(self):
        currency = PublicsCurrencyFactory()
        expense_type = PublicsTravelExpenseTypeFactory()
        dsa_rate = PublicsDSARateFactory(effective_from_date=datetime(2017, 4, 10, 16, 00, tzinfo=UTC))
        dsa_region = dsa_rate.region

        data = {'deductions': [],
                'itinerary': [{'origin': 'Berlin',
                               'destination': 'Budapest',
                               'departure_date': '2017-04-14T17:06:55.821490',
                               'arrival_date': '2017-04-15T17:06:55.821490',
                               'dsa_region': dsa_region.id,
                               'overnight_travel': False,
                               'mode_of_travel': ModeOfTravel.RAIL,
                               'airlines': []},
                              {'origin': 'Budapest',
                               'destination': 'Berlin',
                               'departure_date': '2017-05-20T12:06:55.821490',
                               'arrival_date': '2017-05-21T12:06:55.821490',
                               'dsa_region': dsa_region.id,
                               'overnight_travel': False,
                               'mode_of_travel': ModeOfTravel.RAIL,
                               'airlines': []}],
                'activities': [],
                'cost_assignments': [],
                'clearances': {'medical_clearance': 'requested',
                               'security_clearance': 'requested',
                               'security_course': 'requested'},
                'ta_required': True,
                'international_travel': False,
                'mode_of_travel': [ModeOfTravel.BOAT],
                'traveler': self.traveler.id,
                'supervisor': self.unicef_staff.id,
                'start_date': '2017-04-14T16:05:00+00:00',
                'end_date': '2017-05-22T15:02:13+00:00',
                'currency': currency.id,
                'purpose': 'Purpose',
                'additional_note': 'Notes',
                'expenses': [{'amount': '120',
                              'type': expense_type.id,
                              'currency': currency.id,
                              'document_currency': currency.id}]}

        response = self.forced_auth_req('post', reverse('t2f:travels:list:index'),
                                        data=data, user=self.traveler)
        response_json = json.loads(response.rendered_content)

        with freeze_time(datetime(2017, 4, 14, 16, 00, tzinfo=UTC)):
            response = self.forced_auth_req('post', reverse('t2f:travels:details:state_change',
                                                            kwargs={'travel_pk': response_json['id'],
                                                                    'transition_name': 'submit_for_approval'}),
                                            data=response_json, user=self.traveler)
        # No error should appear, expected 200
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response.status_code, 200, response_json)
        response_json = json.loads(response.rendered_content)

        travel = Travel.objects.get(id=response_json['id'])
        travel.approve()
        travel.save()

        response = self.forced_auth_req('post', reverse('t2f:travels:details:state_change',
                                                        kwargs={'travel_pk': response_json['id'],
                                                                'transition_name': 'send_for_payment'}),
                                        data=response_json, user=self.traveler)
        self.assertEqual(response.status_code, 200)
示例#16
0
    def setUp(self):
        super(InvoiceMaking, self).setUp()
        self.unicef_staff = UserFactory(is_staff=True)
        self.traveler = UserFactory()

        profile = self.traveler.profile
        profile.vendor_number = 'user0001'
        profile.save()

        country = profile.country
        country.business_area_code = '0060'
        country.save()

        dsa_region = PublicsDSARegionFactory()
        PublicsDSARateFactory(region=dsa_region)

        # Currencies
        self.huf = PublicsCurrencyFactory(name='HUF', code='huf')
        self.usd = PublicsCurrencyFactory(name='USD', code='usd')

        # Add wbs/grant/fund
        self.wbs_1 = PublicsWBSFactory(name='WBS #1')
        self.wbs_2 = PublicsWBSFactory(name='WBS #2')

        self.grant_1 = PublicsGrantFactory(name='Grant #1')
        self.grant_2 = PublicsGrantFactory(name='Grant #2')
        self.grant_3 = PublicsGrantFactory(name='Grant #3')

        self.wbs_1.grants.add(self.grant_1)
        self.wbs_2.grants.add(self.grant_2, self.grant_3)

        self.fund_1 = PublicsFundFactory(name='Fund #1')
        self.fund_2 = PublicsFundFactory(name='Fund #4')

        self.grant_1.funds.add(self.fund_1)
        self.grant_3.funds.add(self.fund_2)

        # Expense types
        self.et_t_food = PublicsTravelExpenseTypeFactory(
            title='Food',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)
        self.et_t_travel = PublicsTravelExpenseTypeFactory(
            title='Travel',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)
        self.et_t_other = PublicsTravelExpenseTypeFactory(
            title='Other',
            vendor_number=TravelExpenseType.USER_VENDOR_NUMBER_PLACEHOLDER)

        self.et_a_nico = PublicsTravelExpenseTypeFactory(
            title='Nico Travel', vendor_number='a_nico')
        self.et_a_torben = PublicsTravelExpenseTypeFactory(
            title='Torben Travel', vendor_number='a_torben')

        # Make a travel
        self.travel = Travel.objects.create(traveler=self.traveler,
                                            supervisor=self.unicef_staff,
                                            currency=self.huf)

        ItineraryItemFactory(travel=self.travel,
                             departure_date=datetime(2017, 5, 10, tzinfo=UTC),
                             arrival_date=datetime(2017, 5, 11, tzinfo=UTC),
                             dsa_region=dsa_region)
        ItineraryItemFactory(travel=self.travel,
                             departure_date=datetime(2017, 5, 20, tzinfo=UTC),
                             arrival_date=datetime(2017, 5, 21, tzinfo=UTC),
                             dsa_region=dsa_region)
示例#17
0
    def test_travel_creation(self):
        dsa_region = PublicsDSARegionFactory()
        currency = PublicsCurrencyFactory()
        wbs = PublicsWBSFactory()
        grant = wbs.grants.first()
        fund = grant.funds.first()
        location = LocationFactory()

        purpose = 'Some purpose to check later'

        data = {
            'deductions': [{
                'date': '2016-12-15',
                'breakfast': False,
                'lunch': False,
                'dinner': False,
                'accomodation': False,
                'no_dsa': False
            }, {
                'date': '2016-12-16',
                'breakfast': False,
                'lunch': False,
                'dinner': False,
                'accomodation': False,
                'no_dsa': False
            }],
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'activities': [{
                'is_primary_traveler': True,
                'locations': [location.id],
                'travel_type': TravelType.ADVOCACY,
                'date': '2016-12-15T15:02:13+01:00'
            }],
            'cost_assignments': [{
                'wbs': wbs.id,
                'grant': grant.id,
                'fund': fund.id,
                'share': '100'
            }],
            'clearances': {
                'medical_clearance': 'requested',
                'security_clearance': 'requested',
                'security_course': 'requested'
            },
            'ta_required':
            True,
            'international_travel':
            False,
            'mode_of_travel': [ModeOfTravel.BOAT],
            'traveler':
            self.traveler.id,
            'supervisor':
            self.unicef_staff.id,
            'start_date':
            '2016-12-15T15:02:13+01:00',
            'end_date':
            '2016-12-16T15:02:13+01:00',
            'estimated_travel_cost':
            '123',
            'currency':
            currency.id,
            'purpose':
            purpose,
            'additional_note':
            'Notes',
            'medical_clearance':
            'requested',
            'security_clearance':
            'requested',
            'security_course':
            'requested'
        }

        response = self.forced_auth_req(
            'post',
            reverse('t2f:travels:list:state_change',
                    kwargs={'transition_name': 'save_and_submit'}),
            data=data,
            user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['purpose'], purpose)
        self.assertEqual(response_json['status'], Travel.SUBMITTED)
        travel_id = response_json['id']

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk': travel_id,
                                                'transition_name': 'approve'
                                            }),
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['status'], Travel.APPROVED)

        data = {'purpose': 'Some totally different purpose than before'}
        response = self.forced_auth_req(
            'patch',
            reverse('t2f:travels:details:index',
                    kwargs={'travel_pk': response_json['id']}),
            data=data,
            user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['purpose'], purpose)
示例#18
0
    def test_state_machine_flow(self):
        currency = PublicsCurrencyFactory()
        expense_type = PublicsTravelExpenseTypeFactory()
        business_area = PublicsBusinessAreaFactory()
        dsa_region = PublicsDSARegionFactory()

        wbs = PublicsWBSFactory(business_area=business_area)
        grant = wbs.grants.first()
        fund = grant.funds.first()

        workspace = self.unicef_staff.profile.country
        workspace.business_area_code = business_area.code
        workspace.save()

        data = {
            'cost_assignments': [{
                'wbs': wbs.id,
                'grant': grant.id,
                'fund': fund.id,
                'share': 100
            }],
            'deductions': [{
                'date': '2016-11-03',
                'breakfast': True,
                'lunch': True,
                'dinner': False,
                'accomodation': True
            }],
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'traveler':
            self.traveler.id,
            'ta_required':
            True,
            'currency':
            currency.id,
            'supervisor':
            self.unicef_staff.id,
            'expenses': [{
                'amount': '120',
                'type': expense_type.id,
                'currency': currency.id,
                'document_currency': currency.id
            }]
        }
        response = self.forced_auth_req('post',
                                        reverse('t2f:travels:list:index'),
                                        data=data,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['cost_summary']['preserved_expenses'],
                         None)

        travel_id = response_json['id']

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'submit_for_approval'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)

        travel = Travel.objects.get(id=travel_id)
        self.assertIsNotNone(travel.submitted_at)
        self.assertIsNotNone(travel.first_submission_date)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk': travel_id,
                                                'transition_name': 'approve'
                                            }),
                                        data=response_json,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'send_for_payment'
                                            }),
                                        data=response_json,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_certified'
                                            }),
                                        data=response_json,
                                        user=self.traveler)

        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['non_field_errors'], [
            'Your TA has pending payments to be processed through '
            'VISION. Until payments are completed, you can not certify'
            ' your TA. Please check with your Finance focal point on '
            'how to proceed.'
        ])

        travel = Travel.objects.get(id=travel_id)
        travel.invoices.all().update(status=Invoice.SUCCESS)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_certified'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['status'], Travel.CERTIFIED)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_completed'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['non_field_errors'],
                         ['Field report has to be filled.'])
        self.assertEqual(travel.report_note, '')
        # None should be handled as empty string
        travel.report_note = None  # This has to be set explicitly since serializer does not accept None
        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_completed'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['non_field_errors'],
                         ['Field report has to be filled.'])
        self.assertEqual(travel.report_note, None)

        data = response_json
        data['report'] = 'Something'
        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_completed'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['status'], Travel.COMPLETED)
示例#19
0
    def test_almost_overlapping_trips(self):
        currency = PublicsCurrencyFactory()
        dsa_rate = PublicsDSARateFactory(effective_from_date=datetime.datetime(
            2017, 4, 10, 16, 00, tzinfo=UTC))
        dsa_region = dsa_rate.region

        data = {
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'activities': [],
            'ta_required':
            True,
            'international_travel':
            False,
            'mode_of_travel': [ModeOfTravel.BOAT],
            'traveler':
            self.traveler.id,
            'supervisor':
            self.unicef_staff.id,
            'start_date':
            '2017-04-14T16:05:00+00:00',
            'end_date':
            '2017-05-22T15:02:13+00:00',
            'currency':
            currency.id,
            'purpose':
            'Purpose',
            'additional_note':
            'Notes'
        }

        response = self.forced_auth_req('post',
                                        reverse('t2f:travels:list:index'),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)

        with freeze_time(datetime.datetime(2017, 4, 14, 16, 00, tzinfo=UTC)):
            response = self.forced_auth_req(
                'post',
                reverse('t2f:travels:details:state_change',
                        kwargs={
                            'travel_pk': response_json['id'],
                            'transition_name': Travel.SUBMIT_FOR_APPROVAL
                        }),
                data=response_json,
                user=self.traveler)
        # No error should appear, expected 200
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response.status_code, 200, response_json)
示例#20
0
    def test_state_machine_flow_invoice_disabled(self):
        currency = PublicsCurrencyFactory()
        expense_type = PublicsTravelExpenseTypeFactory()
        business_area = PublicsBusinessAreaFactory()
        dsa_region = PublicsDSARegionFactory()

        wbs = PublicsWBSFactory(business_area=business_area)
        grant = wbs.grants.first()
        fund = grant.funds.first()

        workspace = self.unicef_staff.profile.country
        workspace.business_area_code = business_area.code
        workspace.save()

        data = {
            'cost_assignments': [{
                'wbs': wbs.id,
                'grant': grant.id,
                'fund': fund.id,
                'share': 100
            }],
            'deductions': [{
                'date': '2016-11-03',
                'breakfast': True,
                'lunch': True,
                'dinner': False,
                'accomodation': True
            }],
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'traveler':
            self.traveler.id,
            'ta_required':
            True,
            'currency':
            currency.id,
            'supervisor':
            self.unicef_staff.id,
            'expenses': [{
                'amount': '120',
                'type': expense_type.id,
                'currency': currency.id,
                'document_currency': currency.id
            }]
        }
        response = self.forced_auth_req('post',
                                        reverse('t2f:travels:list:index'),
                                        data=data,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['cost_summary']['preserved_expenses'],
                         None)

        travel_id = response_json['id']

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'submit_for_approval'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)

        travel = Travel.objects.get(id=travel_id)
        self.assertIsNotNone(travel.submitted_at)
        self.assertIsNotNone(travel.first_submission_date)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk': travel_id,
                                                'transition_name': 'approve'
                                            }),
                                        data=response_json,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        # Go straight to sent for payment when invoicing is disabled.
        self.assertEqual(response_json['status'], Travel.SENT_FOR_PAYMENT)

        # No email has been sent regarding SENT_FOR_PAYMENT status when invoicing is disabled.
        subjects = [x.subject for x in mail.outbox]
        self.assertNotIn(
            'Travel #{} sent for payment.'.format(
                response_json["reference_number"]), subjects)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_certified'
                                            }),
                                        data=response_json,
                                        user=self.traveler)

        response_json = json.loads(response.rendered_content)
        # No pending invoice check when invoicing is disabled.
        self.assertEqual(response_json['status'], Travel.CERTIFIED)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_completed'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['non_field_errors'],
                         ['Field report has to be filled.'])
        self.assertEqual(travel.report_note, '')

        # None should be handled as empty string
        travel.report_note = None  # This has to be set explicitly since serializer does not accept None
        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_completed'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['non_field_errors'],
                         ['Field report has to be filled.'])
        self.assertEqual(travel.report_note, None)

        data = response_json
        data['report'] = 'Something'
        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'mark_as_completed'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['status'], Travel.COMPLETED)
示例#21
0
    def test_completed_counts(self):
        currency = PublicsCurrencyFactory()
        dsa_region = PublicsDSARegionFactory()

        traveler = UserFactory(is_staff=True)
        traveler.profile.vendor_number = 'usrvend'
        traveler.profile.save()

        travel = TravelFactory(reference_number=make_travel_reference_number(),
                               traveler=traveler,
                               status=Travel.APPROVED,
                               supervisor=self.unicef_staff)
        data = {
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'traveler':
            traveler.id,
            'ta_required':
            True,
            'report':
            'Some report',
            'currency':
            currency.id,
            'supervisor':
            self.unicef_staff.id
        }
        act1 = TravelActivityFactory(
            travel_type=TravelType.PROGRAMME_MONITORING,
            primary_traveler=traveler)
        act2 = TravelActivityFactory(travel_type=TravelType.SPOT_CHECK,
                                     primary_traveler=traveler)
        act1.travels.add(travel)
        act2.travels.add(travel)
        partner_programmatic_visits = PartnerOrganization.objects.get(
            id=act1.partner.id)
        partner_spot_checks = PartnerOrganization.objects.get(
            id=act2.partner.id)
        response = self.forced_auth_req(
            'post',
            reverse('t2f:travels:details:state_change',
                    kwargs={
                        'travel_pk': travel.id,
                        'transition_name': Travel.COMPLETE
                    }),
            user=traveler,
            data=data)

        response_json = json.loads(response.rendered_content)
        partner_programmatic_visits_after_complete = PartnerOrganization.objects.get(
            id=act1.partner.id)
        partner_spot_checks_after_complete = PartnerOrganization.objects.get(
            id=act2.partner.id)
        self.assertEqual(response_json['status'], Travel.COMPLETED)
        self.assertEqual(
            partner_programmatic_visits.hact_values['programmatic_visits']
            ['completed']['total'] + 1,
            partner_programmatic_visits_after_complete.
            hact_values['programmatic_visits']['completed']['total'])
        self.assertEqual(
            partner_spot_checks.hact_values['spot_checks']['completed']
            ['total'] + 1,
            partner_spot_checks_after_complete.hact_values['spot_checks']
            ['completed']['total'])
示例#22
0
    def test_state_machine_flow(self):
        currency = PublicsCurrencyFactory()
        business_area = PublicsBusinessAreaFactory()
        dsa_region = PublicsDSARegionFactory()

        workspace = self.unicef_staff.profile.country
        workspace.business_area_code = business_area.code
        workspace.save()

        data = {
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'traveler':
            self.traveler.id,
            'ta_required':
            True,
            'currency':
            currency.id,
            'supervisor':
            self.unicef_staff.id
        }
        response = self.forced_auth_req('post',
                                        reverse('t2f:travels:list:index'),
                                        data=data,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)

        travel_id = response_json['id']

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                Travel.SUBMIT_FOR_APPROVAL
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)

        travel = Travel.objects.get(id=travel_id)
        self.assertIsNotNone(travel.submitted_at)
        self.assertIsNotNone(travel.first_submission_date)

        response = self.forced_auth_req(
            'post',
            reverse('t2f:travels:details:state_change',
                    kwargs={
                        'travel_pk': travel_id,
                        'transition_name': Travel.APPROVE
                    }),
            data=response_json,
            user=self.traveler)
        response_json = json.loads(response.rendered_content)

        self.assertEqual(response_json['status'], Travel.APPROVED)

        response = self.forced_auth_req(
            'post',
            reverse('t2f:travels:details:state_change',
                    kwargs={
                        'travel_pk': travel_id,
                        'transition_name': Travel.COMPLETE
                    }),
            data=data,
            user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['non_field_errors'],
                         ['Field report has to be filled.'])
        self.assertEqual(travel.report_note, '')
        # None should be handled as empty string
        travel.report_note = None  # This has to be set explicitly since serializer does not accept None
        response = self.forced_auth_req(
            'post',
            reverse('t2f:travels:details:state_change',
                    kwargs={
                        'travel_pk': travel_id,
                        'transition_name': Travel.COMPLETE
                    }),
            data=data,
            user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['non_field_errors'],
                         ['Field report has to be filled.'])
        self.assertEqual(travel.report_note, None)

        # data = response_json
        data['report'] = 'Something'
        response = self.forced_auth_req(
            'post',
            reverse('t2f:travels:details:state_change',
                    kwargs={
                        'travel_pk': travel_id,
                        'transition_name': Travel.COMPLETE
                    }),
            data=data,
            user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['status'], Travel.COMPLETED)
示例#23
0
    def test_expense_required_on_send_for_payment(self):
        business_area = PublicsBusinessAreaFactory()
        dsa_region = PublicsDSARegionFactory()
        currency = PublicsCurrencyFactory()

        workspace = self.unicef_staff.profile.country
        workspace.business_area_code = business_area.code
        workspace.save()

        data = {
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'traveler':
            self.traveler.id,
            'ta_required':
            True,
            'supervisor':
            self.unicef_staff.id,
            'currency':
            currency.id
        }
        response = self.forced_auth_req('post',
                                        reverse('t2f:travels:list:index'),
                                        data=data,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)

        travel_id = response_json['id']

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'submit_for_approval'
                                            }),
                                        data=data,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk': travel_id,
                                                'transition_name': 'approve'
                                            }),
                                        data=response_json,
                                        user=self.unicef_staff)
        self.assertEqual(response.status_code, 200)
示例#24
0
    def test_multi_step_reach(self, permission_matrix_getter):
        permission_matrix_getter.return_value = {'travel': {}}

        travel_id, data = self._prepare_test()

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk': travel_id,
                                                'transition_name': 'approve'
                                            }),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)

        travel = Travel.objects.get(id=travel_id)
        self.assertEqual(travel.approved_cost_traveler, 0)
        self.assertEqual(travel.approved_cost_travel_agencies, 120)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'send_for_payment'
                                            }),
                                        data=response_json,
                                        user=self.traveler)

        response_json = json.loads(response.rendered_content)

        travel = Travel.objects.get(id=travel_id)
        self.assertEqual(travel.approved_cost_traveler, 0)
        self.assertEqual(travel.approved_cost_travel_agencies, 120)

        # Threshold not reached yet. Still send for payment
        data = response_json
        data['expenses'][0]['amount'] = '180'
        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'send_for_payment'
                                            }),
                                        data=data,
                                        user=self.traveler)

        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['status'], Travel.SENT_FOR_PAYMENT)

        travel = Travel.objects.get(id=travel_id)
        self.assertEqual(travel.approved_cost_traveler, 0)
        self.assertEqual(travel.approved_cost_travel_agencies, 120)

        # Threshold reached. Send for approval
        currency = PublicsCurrencyFactory()
        # If vendor number is empty, considered as estimated travel cost
        # and should be included while calculating the threshold
        expense_type = PublicsTravelExpenseTypeFactory(vendor_number='')

        data = response_json
        data['expenses'].append({
            'amount': '41',
            'type': expense_type.id,
            'currency': currency.id,
            'document_currency': currency.id
        })
        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'send_for_payment'
                                            }),
                                        data=data,
                                        user=self.traveler)

        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['status'], Travel.SUBMITTED)

        travel = Travel.objects.get(id=travel_id)
        self.assertEqual(travel.approved_cost_traveler, 0)
        self.assertEqual(travel.approved_cost_travel_agencies, 120)
示例#25
0
    def test_end_start_match(self):
        # the new itinerary end date matches the start date
        # of a current itinerary
        currency = PublicsCurrencyFactory()
        dsa_region = PublicsDSARegionFactory()

        data = {
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-03-14T17:06:55.821490',
                'arrival_date': '2017-03-20T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-03-25T12:06:55.821490',
                'arrival_date': '2017-04-04T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'activities': [],
            'ta_required':
            True,
            'international_travel':
            False,
            'mode_of_travel': [ModeOfTravel.BOAT],
            'traveler':
            self.traveler.id,
            'supervisor':
            self.unicef_staff.id,
            'start_date':
            '2017-03-14T15:06:55+01:00',
            'end_date':
            '2017-04-04T15:02:13+01:00',
            'currency':
            currency.id,
            'purpose':
            'Purpose',
            'additional_note':
            'Notes'
        }

        response = self.forced_auth_req(
            'post',
            reverse('t2f:travels:list:index'),
            data=data,
            user=self.traveler,
        )
        response_json = json.loads(response.rendered_content)

        travel_id = response_json['id']

        response = self.forced_auth_req(
            'post',
            reverse('t2f:travels:details:state_change',
                    kwargs={
                        'travel_pk': travel_id,
                        'transition_name': Travel.SUBMIT_FOR_APPROVAL,
                    }),
            data=response_json,
            user=self.traveler,
        )
        assert response.status_code == 200
示例#26
0
    def test_edit_to_overlap(self):
        currency = PublicsCurrencyFactory()
        dsa_region = PublicsDSARegionFactory()

        data = {
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'activities': [],
            'ta_required':
            True,
            'international_travel':
            False,
            'mode_of_travel': [ModeOfTravel.BOAT],
            'traveler':
            self.traveler.id,
            'supervisor':
            self.unicef_staff.id,
            'start_date':
            '2017-04-14T16:05:00+00:00',
            'end_date':
            '2017-05-22T15:02:13+00:00',
            'currency':
            currency.id,
            'purpose':
            'Purpose',
            'additional_note':
            'Notes'
        }

        response = self.forced_auth_req('post',
                                        reverse('t2f:travels:list:index'),
                                        data=data,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)

        with freeze_time(datetime.datetime(2017, 4, 14, 16, 00, tzinfo=UTC)):
            response = self.forced_auth_req(
                'post',
                reverse('t2f:travels:details:state_change',
                        kwargs={
                            'travel_pk': response_json['id'],
                            'transition_name': Travel.SUBMIT_FOR_APPROVAL
                        }),
                data=response_json,
                user=self.traveler)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response.status_code, 200, response_json)

        travel = Travel.objects.get(id=response_json['id'])
        travel.reject()
        travel.save()

        data = response_json
        # Adjust it to overlap
        data['itinerary'] = [{
            'origin': 'Berlin',
            'destination': 'Budapest',
            'departure_date': '2017-04-10T16:05:00+00:00',
            'arrival_date': '2017-04-15T17:06:55.821490',
            'dsa_region': dsa_region.id,
            'overnight_travel': False,
            'mode_of_travel': ModeOfTravel.RAIL,
            'airlines': []
        }, {
            'origin': 'Budapest',
            'destination': 'Berlin',
            'departure_date': '2017-05-20T12:06:55.821490',
            'arrival_date': '2017-05-21T12:06:55.821490',
            'dsa_region': dsa_region.id,
            'overnight_travel': False,
            'mode_of_travel': ModeOfTravel.RAIL,
            'airlines': []
        }]

        response = self.forced_auth_req('patch',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                response_json['id'],
                                                'transition_name':
                                                Travel.SUBMIT_FOR_APPROVAL
                                            }),
                                        data=response_json,
                                        user=self.traveler)
        response_json = json.loads(response.rendered_content)
        assert response.status_code == 400
        self.assertEqual(
            response_json, {
                'non_field_errors': [
                    'You have an existing trip with overlapping dates. '
                    'Please adjust your trip accordingly.'
                ]
            })
示例#27
0
    def test_expense_required_on_send_for_payment(self):
        business_area = PublicsBusinessAreaFactory()
        dsa_region = PublicsDSARegionFactory()
        currency = PublicsCurrencyFactory()

        wbs = PublicsWBSFactory(business_area=business_area)
        grant = wbs.grants.first()
        fund = grant.funds.first()

        workspace = self.unicef_staff.profile.country
        workspace.business_area_code = business_area.code
        workspace.save()

        data = {
            'cost_assignments': [{
                'wbs': wbs.id,
                'grant': grant.id,
                'fund': fund.id,
                'share': 100
            }],
            'deductions': [{
                'date': '2016-11-03',
                'breakfast': True,
                'lunch': True,
                'dinner': False,
                'accomodation': True
            }],
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'traveler':
            self.traveler.id,
            'ta_required':
            True,
            'supervisor':
            self.unicef_staff.id,
            'expenses': [],
            'currency':
            currency.id
        }
        response = self.forced_auth_req('post',
                                        reverse('t2f:travels:list:index'),
                                        data=data,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response_json['cost_summary']['preserved_expenses'],
                         None)

        travel_id = response_json['id']

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'submit_for_approval'
                                            }),
                                        data=data,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk': travel_id,
                                                'transition_name': 'approve'
                                            }),
                                        data=response_json,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)

        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel_id,
                                                'transition_name':
                                                'send_for_payment'
                                            }),
                                        data=response_json,
                                        user=self.unicef_staff)
        response_json = json.loads(response.rendered_content)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(
            Decimal(response_json['cost_summary']['preserved_expenses']),
            Decimal('0.00'))
示例#28
0
    def test_completed_counts(self):
        currency = PublicsCurrencyFactory()
        expense_type = PublicsTravelExpenseTypeFactory()
        business_area = PublicsBusinessAreaFactory()
        dsa_region = PublicsDSARegionFactory()

        wbs = PublicsWBSFactory(business_area=business_area)
        grant = wbs.grants.first()
        fund = grant.funds.first()
        traveler = UserFactory(is_staff=True)
        traveler.profile.vendor_number = 'usrvend'
        traveler.profile.save()

        travel = TravelFactory(reference_number=make_travel_reference_number(),
                               traveler=traveler,
                               status=Travel.CERTIFIED,
                               supervisor=self.unicef_staff)
        data = {
            'cost_assignments': [{
                'wbs': wbs.id,
                'grant': grant.id,
                'fund': fund.id,
                'share': 100
            }],
            'deductions': [{
                'date': '2016-11-03',
                'breakfast': True,
                'lunch': True,
                'dinner': False,
                'accomodation': True
            }],
            'itinerary': [{
                'origin': 'Berlin',
                'destination': 'Budapest',
                'departure_date': '2017-04-14T17:06:55.821490',
                'arrival_date': '2017-04-15T17:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }, {
                'origin': 'Budapest',
                'destination': 'Berlin',
                'departure_date': '2017-05-20T12:06:55.821490',
                'arrival_date': '2017-05-21T12:06:55.821490',
                'dsa_region': dsa_region.id,
                'overnight_travel': False,
                'mode_of_travel': ModeOfTravel.RAIL,
                'airlines': []
            }],
            'traveler':
            traveler.id,
            'ta_required':
            True,
            'report':
            'Some report',
            'currency':
            currency.id,
            'supervisor':
            self.unicef_staff.id,
            'expenses': [{
                'amount': '120',
                'type': expense_type.id,
                'currency': currency.id,
                'document_currency': currency.id
            }]
        }
        act1 = TravelActivityFactory(
            travel_type=TravelType.PROGRAMME_MONITORING,
            primary_traveler=traveler)
        act2 = TravelActivityFactory(travel_type=TravelType.SPOT_CHECK,
                                     primary_traveler=traveler)
        act1.travels.add(travel)
        act2.travels.add(travel)
        partner_programmatic_visits = PartnerOrganization.objects.get(
            id=act1.partner.id)
        partner_spot_checks = PartnerOrganization.objects.get(
            id=act2.partner.id)
        response = self.forced_auth_req('post',
                                        reverse(
                                            't2f:travels:details:state_change',
                                            kwargs={
                                                'travel_pk':
                                                travel.id,
                                                'transition_name':
                                                'mark_as_completed'
                                            }),
                                        user=traveler,
                                        data=data)

        response_json = json.loads(response.rendered_content)
        partner_programmatic_visits_after_complete = PartnerOrganization.objects.get(
            id=act1.partner.id)
        partner_spot_checks_after_complete = PartnerOrganization.objects.get(
            id=act2.partner.id)
        self.assertEqual(response_json['status'], Travel.COMPLETED)
        self.assertEqual(
            partner_programmatic_visits.hact_values['programmatic_visits']
            ['completed']['total'] + 1,
            partner_programmatic_visits_after_complete.
            hact_values['programmatic_visits']['completed']['total'])
        self.assertEqual(
            partner_spot_checks.hact_values['spot_checks']['completed']
            ['total'] + 1,
            partner_spot_checks_after_complete.hact_values['spot_checks']
            ['completed']['total'])