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()
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)
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)
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.']})
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)
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
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)
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
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)
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)
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'])
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'])
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)
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)
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)
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)
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)
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)
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'])
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)
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)
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)
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
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.' ] })
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'))
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'])