class ProjectService(object): hash_key_service = HashKeyService() request_service = WebRequestService() def get_projects_by_company(self, company_id, active_only=False): api_url = '{0}/company/{1}/projects'.format( API_URL_COI, self.hash_key_service.encode_key_with_environment(company_id)) # Make the request and parse the response as json r = self.request_service.get(api_url) projects = r.json() if (active_only): filtered = [] for project in projects: if (project['status'] == PROJECT_STATUS_ACTIVE): filtered.append(project) projects = filtered view_models = [] for project in projects: view_models.append(self._map_domain_to_view_model(project)) return view_models def _map_domain_to_view_model(self, domain_model): return { 'project_id': domain_model['_id'], 'name': domain_model['name'], 'status': domain_model['status'] }
def _get_site_URL(self, user_id): user = User.objects.get(pk=user_id) if user.check_password(settings.DEFAULT_USER_PW): hash_key_service = HashKeyService() return "%semployee/signup/%s" % ( settings.SITE_URL, hash_key_service.encode_key(user_id)) return settings.SITE_URL
class TimeTrackingService(object): hash_key_service = HashKeyService() request_service = WebRequestService() def get_all_users_submitted_work_timesheet_by_week_start_date( self, week_start_date): users = [] api_url = '{0}?start_date={1}&end_date={1}'.format( API_URL_WORK_TIMESHEET, week_start_date.isoformat()) # Make the request and parse the response as json r = self.request_service.get(api_url) all_entries = r.json() for entry in all_entries: user_descriptor = entry['employee']['personDescriptor'] user_id = int( self.hash_key_service.decode_key_with_environment( user_descriptor)) users.append(user_id) return users def get_company_users_submitted_work_timesheet_by_week_range( self, company_id, start_week_start_date, end_week_start_date): week_user_timesheets = {} api_url = '{0}api/v1/company/{1}/work_timesheets?start_date={2}&end_date={3}'.format( settings.TIME_TRACKING_SERVICE_URL, self.hash_key_service.encode_key_with_environment(company_id), start_week_start_date.isoformat(), end_week_start_date.isoformat()) r = self.request_service.get(api_url) if r.status_code == 404: return week_user_timesheets all_entries = r.json() for entry in all_entries: user_descriptor = entry['employee']['personDescriptor'] user_id = self.hash_key_service.decode_key_with_environment( user_descriptor) item = copy.deepcopy(entry) item['user_id'] = user_id # Group returned timesheet by work start date week_start_date_str = entry['weekStartDate'] week_start_date = datetime.strptime( week_start_date_str, '%Y-%m-%dT%H:%M:%S.%fZ').date() if week_start_date in week_user_timesheets: week_user_timesheets[week_start_date].append(item) else: week_user_timesheets[week_start_date] = [item] return week_user_timesheets
def onboard_email(name, company_id, to_emails, id): try: company = Company.objects.get(pk=company_id) except Company.DoesNotExist: raise Http404 hash_key_service = HashKeyService() link = "%semployee/signup/%s" % (URL, hash_key_service.encode_key(id)) c = CONTENT % (name, company.name, link) send_mail(SUBJECT, c, FROM, to_emails, fail_silently=False)
def build_from_record(self, compensation_record): self.key_hasher = HashKeyService() if compensation_record: self.id = self.key_hasher.encode_key(compensation_record.id) self.effective_date = compensation_record.effective_date self.annual_base_salary = compensation_record.annual_base_salary self.hourly_rate = compensation_record.hourly_rate self.increase_percentage = compensation_record.increase_percentage self.projected_hour_per_month = compensation_record.projected_hour_per_month self.created_at = compensation_record.created_at self.updated_at = compensation_record.updated_at self.reason = compensation_record.reason self.is_current = False
class ContratorService(object): hash_key_service = HashKeyService() request_service = WebRequestService() def get_contractor_by_id(self, contractor_id): api_url = '{0}/contractor/{1}'.format(API_URL_COI, contractor_id) # Make the request and parse the response as json r = self.request_service.get(api_url) entry = r.json() return entry
def _get_action_data(self): hash_key_service = HashKeyService() send_email_service = SendEmailService() company_emails = send_email_service.get_employer_emails_for_all_companies( ) result = [] for companyId in company_emails.keys(): result.append({ 'descriptor': hash_key_service.encode_key_with_environment(companyId), 'emailList': company_emails[companyId] }) return result
def _get_or_create_group(self, group_name, company_id): comp_group = CompanyGroup.objects.filter(company=company_id, name=group_name) if not comp_group: # Let's create a new company_group new_comp_group = {'company': company_id, 'name': group_name} group_serializer = CompanyGroupPostSerializer(data=new_comp_group) if group_serializer.is_valid(): group_serializer.save() hash_key_service = HashKeyService() return hash_key_service.decode_key(group_serializer.data['id']) else: raise Exception( "Group cannot be created with the name {}".format( group_name)) else: return comp_group[0].id
class TimeOffService(object): hash_key_service = HashKeyService() request_service = WebRequestService() def get_company_users_time_off_records_by_date_range( self, company_id, start_date, end_date): user_records = [] api_url = '{0}api/v1/company/{1}/timeoffs?start_date={2}&end_date={3}'.format( settings.TIME_TRACKING_SERVICE_URL, self.hash_key_service.encode_key_with_environment(company_id), start_date.isoformat(), end_date.isoformat()) r = self.request_service.get(api_url) if r.status_code == 404: return user_records r.raise_for_status() all_entries = r.json() for entry in all_entries: user_records.append(TimeOffRecord(entry)) # Sort the records by user ID sorted_records = sorted( user_records, key=lambda record: (record.requestor_user_id, record.start_date_time)) return sorted_records def get_company_users_time_off_record_aggregates_by_date_range( self, company_id, start_date, end_date): mappings = {} all_records = self.get_company_users_time_off_records_by_date_range( company_id, start_date, end_date) for record in all_records: if record.requestor_user_id not in mappings: mappings[ record.requestor_user_id] = EmployeeTimeOffRecordAggregate( record.requestor_user_id) mappings[record.requestor_user_id].add_record(record) unsorted = mappings.values() return sorted(unsorted, key=lambda aggregate: aggregate.user_id)
def test_get_user_by_credential_successful(self): email = '*****@*****.**' credential = { 'email': email, 'password': '******' } response = self.client.post( reverse('user_by_credential'), json.dumps(credential), content_type='application/json' ) hash_key_service = HashKeyService() response_object = json.loads(response.content) self.assertTrue('user_info' in response_object) user_info = response_object['user_info'] self.assertEqual(type(user_info), dict) self.assertTrue('user_id' in user_info and user_info['user_id']) self.assertTrue('user_id_env_encode' in user_info and user_info['user_id_env_encode']) self.assertEqual(str(user_info['user_id']), hash_key_service.decode_key_with_environment(user_info['user_id_env_encode'])) self.assertTrue('account_email' in user_info and user_info['account_email']) self.assertEqual(user_info['account_email'], email) self.assertTrue('first_name' in user_info and user_info['first_name']) self.assertTrue('last_name' in user_info and user_info['last_name']) self.assertTrue('hourly_rate' in user_info and user_info['hourly_rate']) self.assertTrue('company_info' in response_object) company_info = response_object['company_info'] self.assertEqual(type(company_info), dict) self.assertTrue('company_id' in company_info and company_info['company_id']) self.assertTrue('company_id_env_encode' in company_info and company_info['company_id_env_encode']) self.assertEqual(str(company_info['company_id']), hash_key_service.decode_key_with_environment(company_info['company_id_env_encode'])) self.assertTrue('app_features_info' in response_object) app_features_info = response_object['app_features_info'] self.assertEqual(type(app_features_info), dict)
def __init__(self): self.hash_service = HashKeyService()
class ViewTestBase(object): hash_key_service = HashKeyService() def normalize_key(self, key): return self.hash_key_service.encode_key(key)
class TimePunchCard(object): hash_key_service = HashKeyService() date_time_service = DateTimeService() def __init__(self, punch_card_domain_model): if (punch_card_domain_model is None): raise ValueError('Must pass valid time punch card domain model.') # List out instance variables self.user_id = None self.user_info = None self.date = None self.start = None self.end = None self.state = None self.card_type = None self.in_progress = None self.system_stopped = None # Parse out user ID user_descriptor = punch_card_domain_model['employee'][ 'personDescriptor'] self.user_id = int( self.hash_key_service.decode_key_with_environment(user_descriptor)) # Parse card type self.card_type = punch_card_domain_model.get('recordType') # Parse all dates and times to objects self.date = self.date_time_service.parse_date_time( punch_card_domain_model['date']) start_str = punch_card_domain_model.get('start') if (start_str): self.start = self.date_time_service.parse_date_time(start_str) end_str = punch_card_domain_model.get('end') if (end_str): self.end = self.date_time_service.parse_date_time(end_str) # Parse attributes attributes = punch_card_domain_model.get('attributes') if (attributes): for attribute in attributes: # For now only cares about state if attribute['name'] == PUNCH_CARD_ATTRIBUTE_TYPE_STATE: self.state = attribute['value'] break in_progress_str = punch_card_domain_model.get('inProgress') if (in_progress_str): self.in_progress = bool(in_progress_str) system_stopped_str = punch_card_domain_model.get('systemStopped') if (system_stopped_str): self.system_stopped = bool(system_stopped_str) # Support lasy-evaluated validation self._validation_issues = None def get_punch_card_hours(self): raw_hours = self.__get_raw_card_hours() if self.card_type == PUNCH_CARD_TYPE_BREAK_TIME: return -raw_hours return raw_hours def __get_raw_card_hours(self): if (self.start is not None and self.end is not None): card_hours = self.date_time_service.get_time_diff_in_hours( self.start, self.end, 2) return card_hours return 0.0 def get_card_day_of_week_iso(self): return self.date.isoweekday() % 7 @property def validation_issues(self): if (self._validation_issues is None): self._validation_issues = self._validate() return self._validation_issues def is_valid(self): issues = self.validation_issues blocking_issue = next( (issue for issue in issues if issue.level > TimeCardValidationIssue.LEVEL_WARNING), None) return blocking_issue is None def _validate(self): validation_issues = [] card_hours = self.__get_raw_card_hours() # 1. Unclosed timecard (clocked in, but not out) if ((self.start is not None and self.end is None) or (self.in_progress)): validation_issues.append( TimeCardValidationIssue( TimeCardValidationIssue.LEVEL_ERROR, '[Unclosed Card] Clocked in, but not out, by midnight.')) # 2. Negative hours if (card_hours < 0.0): validation_issues.append( TimeCardValidationIssue( TimeCardValidationIssue.LEVEL_ERROR, '[Invalid Card Balance] Card with negative accounted hours.' )) # 3. Long working hours, such as over 10 hours work if (card_hours >= 10.0): validation_issues.append( TimeCardValidationIssue( TimeCardValidationIssue.LEVEL_WARNING, '[Unusual Card Balance] Card with more than 10 hours.')) if (self.system_stopped): validation_issues.append( TimeCardValidationIssue( TimeCardValidationIssue.LEVEL_ERROR, '[System Closed Card] Card stopped accruing hours by system. Please validate!' )) return validation_issues
def from_native(self, data): hash_key_service = HashKeyService() return hash_key_service.decode_key(data)
def to_native(self, obj): hash_key_service = HashKeyService() return hash_key_service.encode_key(obj)
def execute_creation(self, account_info, do_validation=True): result = OperationResult(account_info) account_result = None # Do validation first, and short circuit if failed if (do_validation): account_result = self.validate(account_info) else: # directly construct the result, skipping validation account_result = OperationResult(account_info) # If the account creation info is not valid to begin with # simply short circuit and return it if (account_result.has_issue()): return account_result userManager = AuthUserManager() # Create the actual user data password = settings.DEFAULT_USER_PW if account_info.password: password = account_info.password user = User.objects.create_user(account_info.email, password) user.first_name = account_info.first_name user.last_name = account_info.last_name user.save() # Create the company_user data company_user = CompanyUser( company_id=account_info.company_id, user=user, company_user_type=account_info.company_user_type) if account_info.new_employee is not None: company_user.new_employee = account_info.new_employee company_user.save() # Now create the person object person_data = { 'first_name': account_info.first_name, 'last_name': account_info.last_name, 'user': user.id, 'relationship': SELF, 'person_type': 'primary_contact', 'email': user.email } person_serializer = PersonSimpleSerializer(data=person_data) if person_serializer.is_valid(): person_serializer.save() else: raise Exception("Failed to create person record") # Create the employee profile key_service = HashKeyService() person_id = key_service.decode_key(person_serializer.data['id']) pin = account_info.pin pinService = EmployeePinService() if not pin: pin = pinService.get_company_wide_unique_pin( account_info.company_id, user.id) profile_data = { 'person': person_id, 'company': account_info.company_id, 'start_date': account_info.start_date, 'benefit_start_date': account_info.benefit_start_date, 'pin': pin } if (account_info.compensation_info.annual_base_salary is not None): profile_data[ 'annual_base_salary'] = account_info.compensation_info.annual_base_salary if (account_info.employment_type): profile_data['employment_type'] = account_info.employment_type if (account_info.manager_id): profile_data['manager'] = account_info.manager_id if (account_info.employee_number): profile_data['employee_number'] = account_info.employee_number profile_serializer = EmployeeProfilePostSerializer(data=profile_data) if profile_serializer.is_valid(): profile_serializer.save() else: raise Exception("Failed to create employee profile record") # Now check to see send email and create documents if company_user.company_user_type == 'employee': if account_info.send_email: # now try to create the onboard email for this user. try: onboard_email( "%s %s" % (user.first_name, user.last_name), account_info.company_id, [account_info.email, settings.SUPPORT_EMAIL_ADDRESS], user.id) except StandardError: raise Exception("Failed to send email to employee") if (account_info.create_docs): # Let's create the documents for this new user try: doc_gen = UserDocumentGenerator(company_user.company, user) doc_gen.generate_all_document(account_info.doc_fields) except Exception: raise Exception( "Failed to generate documents for employee") # Create the initial compensation record compensation_data = { 'person': person_id, 'company': account_info.company_id, 'annual_base_salary': account_info.compensation_info.annual_base_salary, 'projected_hour_per_month': account_info.compensation_info.projected_hour_per_month, 'hourly_rate': account_info.compensation_info.hourly_rate, 'effective_date': account_info.compensation_info.effective_date, 'increase_percentage': None } compensation_serializer = EmployeeCompensationPostSerializer( data=compensation_data) if (compensation_serializer.is_valid()): compensation_serializer.save() else: raise Exception("Failed to create compensation record") if account_info.group_id: self._add_to_group(account_info.group_id, user.id) elif account_info.group_name: group_id = self._get_or_create_group(account_info.group_name, account_info.company_id) if group_id: self._add_to_group(group_id, user.id) else: raise Exception( "Cannot get group_id from group name {}".format( account_info.group_name)) account_info.user_id = user.id account_result.set_output_data(account_info) # Now for the new employee being created, setup any information # required for external parties (such as payroll and benefit service) # providers. self.company_integration_provider_data_service.generate_and_record_external_employee_number( user.id) return account_result
class TestHashKeyService(TestCase): hash_key_service = HashKeyService() ''' encode a 'None' key, should return None ''' def test_Encode_NoneKey_None(self): key = None encodedKey = self.hash_key_service.encode_key(key) self.assertTrue(not encodedKey) ''' encode a valid key is expected to yield result with valid token format ''' def test_Encode_Key_ValidFormat(self): key = 20 encodedKey = self.hash_key_service.encode_key(key) regex = re.compile(HashKeyService.HASH_TOKEN_REGEX_PATTERN) self.assertTrue(not regex.match(encodedKey) is None) def test_Encode_Key_With_Environment_ValidFormat(self): key = 20 encoded_env_key = self.hash_key_service.encode_key_with_environment(key) env_token = encoded_env_key.split('_', 1)[0] self.assertEqual(env_token, settings.ENVIRONMENT_IDENTIFIER) encoded_key = encoded_env_key.split('_', 1)[1] regex = re.compile(HashKeyService.HASH_TOKEN_REGEX_PATTERN) self.assertTrue(not regex.match(encoded_key) is None) ''' decode a 'None' key, should return None ''' def test_Decode_NoneKey_None(self): encodedkey = None key = self.hash_key_service.decode_key(encodedkey) self.assertTrue(not key) ''' decode an invalid key, should return None ''' def test_Decode_InvalidKey_None(self): encodedkey = 'This_Is_A_Bad_Token' key = self.hash_key_service.decode_key(encodedkey) self.assertTrue(not key) ''' encode a valid key then decode it, should return original key ''' def test_EncodeAndDecode_Key_OriginalKey(self): key = 20 encodedKey = self.hash_key_service.encode_key(key) decodedKey = self.hash_key_service.decode_key(encodedKey) self.assertEqual(str(key), str(decodedKey)) def test_Decode_With_Environment_InvalidEnvironment_None(self): key = 20 encoded_key = self.hash_key_service.encode_key(key) encoded_env_key = "{0}_{1}".format('invalidEnv', encoded_key) decoded_key = self.hash_key_service.decode_key_with_environment(encoded_env_key) self.assertTrue(not decoded_key) def test_Decode_With_Environment_Valid_OriginalKey(self): key = 20 encoded_env_key = self.hash_key_service.encode_key_with_environment(key) decoded_key = self.hash_key_service.decode_key_with_environment(encoded_env_key) self.assertTrue(str(key), str(decoded_key))
def _decode_value(self, value): hash_key_service = HashKeyService() return hash_key_service.decode_key(value)
class TimeOffRecord(object): hash_key_service = HashKeyService() date_time_service = DateTimeService() def __init__(self, time_off_domain_model): if (time_off_domain_model is None): raise ValueError('Must pass valid time off domain model.') # List out instance variables self.requestor_user_id = None self.requestor_user_info = None self.approver_user_id = None self.approver_user_info = None self.start_date_time = None self.duration = None self.status = None self.decision_timestamp = None self.record_type = None self.request_timestamp = None # Parse requestor info requestor_user_descriptor = time_off_domain_model['requestor'][ 'personDescriptor'] self.requestor_user_id = int( self.hash_key_service.decode_key_with_environment( requestor_user_descriptor)) if (self.requestor_user_id): user_model = User.objects.get(pk=self.requestor_user_id) self.requestor_user_info = UserInfo(user_model) # Parse approver info if ('approver' in time_off_domain_model and time_off_domain_model['approver']): approver_user_descriptor = time_off_domain_model['approver'][ 'personDescriptor'] self.approver_user_id = int( self.hash_key_service.decode_key_with_environment( approver_user_descriptor)) if (self.approver_user_id): user_model = User.objects.get(pk=self.approver_user_id) self.approver_user_info = UserInfo(user_model) # Parse record type self.record_type = time_off_domain_model['type'] # Parse Duration self.duration = float(time_off_domain_model['duration']) # Parse status self.status = time_off_domain_model['status'] # Parse all dates and times to objects self.start_date_time = self.date_time_service.parse_date_time( time_off_domain_model['startDateTime']) self.request_timestamp = self.date_time_service.parse_date_time( time_off_domain_model['requestTimestamp']) if ('decisionTimestamp' in time_off_domain_model): decision_time_str = time_off_domain_model['decisionTimestamp'] self.decision_timestamp = self.date_time_service.parse_date_time( decision_time_str) @property def requestor_full_name(self): if (self.requestor_user_info is None): return None return self.requestor_user_info.full_name @property def approver_full_name(self): if (self.approver_user_info is None): return None return self.approver_user_info.full_name
def _encode_value(self, value): hash_key_service = HashKeyService() if not hash_key_service.is_encoded(value): return hash_key_service.encode_key(value) return value
class UserByCredentialView(APIView): hash_key_service = HashKeyService() ''' This is the view class to provide the API endpoint for getting user information by providing the username and password of the user. Note: The information got from this end point is simplified. ''' authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication) def post(self, request, format=None): credential = request.DATA email = credential.get('email') password = credential.get('password') if not email or not password: return HttpResponse(status=401) auth_result = AuthenticationService().login(email, password, request) if auth_result.user: # Authentication successful. # Now get the user information result = self._get_user_data(auth_result.user) return Response(result) else: return HttpResponse(status=401) def _get_user_data(self, user): result = {} # User info user_info = {} ## Basic info user_info['user_id'] = user.id user_info[ 'user_id_env_encode'] = self.hash_key_service.encode_key_with_environment( user.id) user_info['account_email'] = user.email ## Person and Compensation Info persons = Person.objects.filter(user=user.id, relationship='self') if (len(persons) > 0): person_model = persons[0] person_data = PersonInfo(person_model) user_info['first_name'] = person_data.first_name user_info['last_name'] = person_data.last_name compensation_info = CompensationService(person_model=person_model) hourly_rate = compensation_info.get_current_hourly_rate() if (hourly_rate): hourly_rate = round(hourly_rate, 2) user_info['hourly_rate'] = hourly_rate result['user_info'] = user_info # Company Info company_info = {} company_users = CompanyUser.objects.filter(user=user.id) company_id = None if (len(company_users) > 0): company_user = company_users[0] company_id = company_user.company_id company_info['company_id'] = company_id company_info[ 'company_id_env_encode'] = self.hash_key_service.encode_key_with_environment( company_user.company_id) if (company_user.company): company_info['company_name'] = company_user.company.name result['company_info'] = company_info # Application Features application_features = None if (company_id): application_feature_service = ApplicationFeatureService() application_features = application_feature_service.get_complete_application_feature_status_by_company( company_id) result['app_features_info'] = application_features # Projects if (application_features and application_features[APP_FEATURE_PROJECTMANAGEMENT]): project_service = ProjectService() result['project_list'] = project_service.get_projects_by_company( company_id, active_only=True) return result