def execute_employee_organization_setup(self, organization_setup_data, do_validation=True): result = None # Do validation first, and short circuit if failed if (do_validation): result = self.validate_employee_organization_setup_data(organization_setup_data) else: # directly construct the result, skipping validation result = OperationResult(organization_setup_data) # If the operation input info is not valid to begin with # simply short circuit and return it if (result.has_issue()): raise Exception( "Encountered validation issues while executing employee organization setup!") # get employee profile to update employee_profile = organization_setup_data.get_employee_profile() # get manager's profile manager_profile = organization_setup_data.get_manager_profile() # now do the assignment employee_profile.manager = manager_profile employee_profile.save() result.set_output_data(organization_setup_data) return result
def batch_validate_employee_organization_setup_data(self, organization_setup_data_list): result = OperationResult(organization_setup_data_list) if (not organization_setup_data_list): result.append_issue( 'Did not find any employee organization setup to handle' ) else: has_invalid = False validation_results = [] for data in organization_setup_data_list: validate_result = self.validate_employee_organization_setup_data(data) if (validate_result.has_issue()): has_invalid = True validation_results.append(validate_result) if (has_invalid): result.append_issue( 'There are validation issues on some employee organization setup data.' ) result.set_output_data(validation_results) return result
def validate_batch(self, account_creation_data_list): result = OperationResult(account_creation_data_list) if (not account_creation_data_list): result.append_issue('Did not find any account info to handle') else: # Also do some batch level validations exist_emails = [] has_invalid = False account_validation_results = [] # Collect all new account employee names employee_names = [] for account_info in account_creation_data_list: full_name = account_info.first_name + account_info.last_name employee_names.append(full_name) for account_info in account_creation_data_list: account_result = self.validate(account_info) if account_info.email not in exist_emails: exist_emails.append(account_info.email) else: account_result.append_issue( 'The email specificed is also used on another account in this batch' ) # Check whether the account has manager info specified # and if so, check the validity of the manager info if (account_info.manager_first_name and account_info.manager_last_name): manager_full_name = account_info.manager_first_name + account_info.manager_last_name if (manager_full_name not in employee_names): # the specified manager name does not match any of the employees account_result.append_issue( 'Could not locate an employee based on the manager information' ) if (account_result.has_issue()): has_invalid = True account_validation_results.append(account_result) if (has_invalid): result.append_issue( 'There are validation issues on some account info.') result.set_output_data(account_validation_results) return result
def terminate_employee(self, termination_data): result = OperationResult(termination_data) employee_profiles = EmployeeProfile.objects.filter( person=termination_data.person_id, company=termination_data.company_id) if (len(employee_profiles) <= 0): raise Exception( 'Could not locate employee profile for person [%s]' % termination_data.person_id) employee_profile = employee_profiles[0] employee_profile.end_date = termination_data.end_date employee_profile.employment_status = EMPLOYMENT_STATUS_TERMINATED employee_profile.save() result.set_output_data(employee_profile) # Now send termination email self._send_termination_email(employee_profile) return result
def parse_batch_employee_organization_import_raw_data(self, batch_import_raw_data): result = OperationResult(batch_import_raw_data) parsed_org_data_list = [] # check all lines for number of fields # if found bad ones, send the main wrapper back without # construting the individual ones for line in batch_import_raw_data.raw_data.split('\n'): if (not line.strip()): continue tokens = line.split('\t') if (len(tokens) != len(self.REQUIRED_RAW_DATA_FIELDS)): result.append_issue( 'The line [%s] fails to parse properly. Reason: Do not have enough number of fields' % line ) else: # parse the fields into domain object and # construct the DTO needed org_data = { 'company_id': batch_import_raw_data.company_id, 'employee_first_name': self._get_field_value(tokens, self.FIELD_FIRST_NAME), 'employee_last_name': self._get_field_value(tokens, self.FIELD_LAST_NAME), 'manager_first_name': self._get_field_value(tokens, self.FIELD_MANAGER_FIRST_NAME), 'manager_last_name': self._get_field_value(tokens, self.FIELD_MANAGER_LAST_NAME) } # Parse the line into objects # Utilize serializers to perform all the details serializer = EmployeeOrganizationSetupDataPostSerializer(data=org_data) if (not serializer.is_valid()): result.append_issue( 'The line [%s] fails to parse properly. Reasons:[%s]' % (line, serializer.errors) ) else: parsed_org_data_list.append(serializer.object) # Do batch validation, # - Collect batch level issues into the result # - include the list of validated account data as output batch_validation_result = self.batch_validate_employee_organization_setup_data(parsed_org_data_list) batch_validation_result.copy_issues_to(result) result.set_output_data(batch_validation_result.output_data) return result
def parse_raw_data(self, batch_account_raw_data): result = OperationResult(batch_account_raw_data) parsed_account_data_list = [] # check all lines for number of fields # if found bad ones, send the main wrapper back without # construting the individual ones for line in batch_account_raw_data.raw_data.split('\n'): if (not line.strip()): continue tokens = line.split('\t') if (len(tokens) != len(self.REQUIRED_RAW_DATA_FIELDS)): result.append_issue( 'The line [%s] fails to parse properly. Reason: Do not have enough number of fields' % line) else: # try parsing some data first and log errors if found start_date = None try: start_date = datetime.strptime( self._get_field_value(tokens, self.FIELD_START_DATE), '%m/%d/%Y') except: result.append_issue( 'The line [%s] fails to parse properly. Reason: Failed to parse the given employment start date' % (line)) continue benefit_start_date = None try: benefit_start_date = datetime.strptime( self._get_field_value(tokens, self.FIELD_BENEFIT_START_DATE), '%m/%d/%Y') except: result.append_issue( 'The line [%s] fails to parse properly. Reason: Failed to parse the given benefit start date' % (line)) continue # Parse the line into objects # Utilize serializers to perform all the details compensation_data = { 'annual_base_salary': self._get_field_value(tokens, self.FIELD_ANNUAL_BASE_SALARY), 'hourly_rate': self._get_field_value(tokens, self.FIELD_HOURLY_RATE), 'projected_hour_per_month': self._get_field_value(tokens, self.FIELD_PROJECTED_HOUR_PER_MONTH), 'effective_date': start_date } account_data = { 'company_id': batch_account_raw_data.company_id, 'first_name': self._get_field_value(tokens, self.FIELD_FIRST_NAME), 'last_name': self._get_field_value(tokens, self.FIELD_LAST_NAME), 'employment_type': self._get_field_value(tokens, self.FIELD_EMPLOYMENT_TYPE), 'email': self._get_field_value(tokens, self.FIELD_EMAIL), 'password': self._get_field_value(tokens, self.FIELD_PASSWORD), 'employee_number': self._get_field_value(tokens, self.FIELD_EMPLOYEE_NUMBER), 'company_user_type': USER_TYPE_EMPLOYEE, 'send_email': batch_account_raw_data.send_email, 'new_employee': False, 'create_docs': False, 'start_date': start_date, 'benefit_start_date': benefit_start_date, 'group_name': self._get_field_value(tokens, self.FIELD_GROUP_NAME), 'compensation_info': compensation_data, 'manager_first_name': self._get_field_value(tokens, self.FIELD_MANAGER_FIRST_NAME), 'manager_last_name': self._get_field_value(tokens, self.FIELD_MANAGER_LAST_NAME), 'doc_fields': [] } serializer = AccountCreationDataSerializer(data=account_data) if (not serializer.is_valid()): result.append_issue( 'The line [%s] fails to parse properly. Reasons:[%s]' % (line, serializer.errors)) else: parsed_account_data_list.append(serializer.object) # Do batch validation, # - Collect batch level issues into the result # - include the list of validated account data as output batch_validation_result = self.validate_batch(parsed_account_data_list) batch_validation_result.copy_issues_to(result) result.set_output_data(batch_validation_result.output_data) return result
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
def validate(self, account_info): result = OperationResult(account_info) if (not account_info or not account_info.email or not account_info.company_id or not account_info.company_user_type or not account_info.first_name or not account_info.last_name or not account_info.compensation_info): result.append_issue( "Missing necessary information for account creation") account_info.email = account_info.email if (account_info.send_email and account_info.password): result.append_issue( "Password should not be specified if the system is to send registration email" ) if (not account_info.send_email): if (not account_info.password): result.append_issue( "Password must be specified if the system is instructed to not send registration email" ) elif (len(account_info.password) < 8): result.append_issue( "Password must be no shorter than 8 characters") try: Company.objects.get(pk=account_info.company_id) except Company.DoesNotExist: result.append_issue("Specificed company does not exist") company_users = CompanyUser.objects.filter( company=account_info.company_id) for c in company_users: if (c.company_user_type == account_info.company_user_type and c.user.email == account_info.email): result.append_issue("Specified email has already been used") if (not account_info.send_email and not account_info.password): result.append_issue("Missing initial password for the new account") # Now validate the initial compensation record if (account_info.employment_type in [PART_TIME, CONTRACTOR, INTERN, PER_DIEM]): if (not account_info.compensation_info.hourly_rate or not account_info.compensation_info.projected_hour_per_month ): result.append_issue("Compensation record info is incomplete") elif (account_info.employment_type == FULL_TIME): # Full time employee could be on hourly payroll if (not account_info.compensation_info.annual_base_salary and (not account_info.compensation_info.hourly_rate or not account_info.compensation_info.projected_hour_per_month)): result.append_issue("Compensation record info is incomplete") else: result.append_issue( 'The specified employment type [%s] is not valid.' % account_info.employment_type) if not account_info.group_name and not account_info.group_id: result.append_issue('Company group not specified.') # if manager profile id is provided, validate its existence if (account_info.manager_id): try: EmployeeProfile.objects.get(pk=account_info.manager_id) except EmployeeProfile.DoesNotExist: result.append_issue( 'Could not find employee profile based on the manager info provided.' ) result.set_output_data(account_info) return result
def validate_employee_organization_setup_data(self, organization_setup_data): result = OperationResult(organization_setup_data) result.set_output_data(organization_setup_data) if (not organization_setup_data or not organization_setup_data.company_id): result.append_issue( "Missing necessary information for employee organization setup" ) return result if (not organization_setup_data.employee_person_id): result.append_issue( "Could not locate employee profile for the given employee" ) # It is a valid case where manager info is not specified, which # we infer as to not-setup or remove manager for the employee # But it is invalid that the manager info is specified but failed # to resolve to a valid employee profile if (organization_setup_data.has_manager_info_specified and not organization_setup_data.manager_profile_id): result.append_issue( "Could not locate manager's employee profile based on info provided" ) # check the employee and manager belong to the same company employee_profile = organization_setup_data.get_employee_profile() manager_profile = organization_setup_data.get_manager_profile() if (employee_profile and manager_profile): if (employee_profile.company.id != manager_profile.company.id): result.append_issue( "The employee and manager specified do not work in the same company" ) return result