def __init__(self):
        self.integration_provider_service = IntegrationProviderService()
        self.company_personnel_service = CompanyPersonnelService()

        self._data_service_registry = {}
        for integration_provider_type in INTEGRATION_SERVICE_TYPES:
            self._data_service_registry[integration_provider_type] = {}      

        self._register_data_service_classes()
Ejemplo n.º 2
0
class _EmployeeDataContext(object):
    _integration_provider_service = IntegrationProviderService()

    def __init__(self, employee_user_id, company_id, view_model_factory):
        self.employee_user_id = employee_user_id
        self.company_id = company_id

        self.w4_info = view_model_factory.get_employee_w4_data(employee_user_id)
        self.state_tax_info = view_model_factory.get_employee_state_tax_data(employee_user_id)
        self.company_info = view_model_factory.get_company_info()
        self.person_info = view_model_factory.get_employee_person_info(employee_user_id)
        self.employee_profile_info = view_model_factory.get_employee_employment_profile_data(employee_user_id)

        # Employee Number, this comes from the CP system.
        self.employee_number = self._integration_provider_service.get_employee_integration_provider_external_id(
            employee_user_id,
            INTEGRATION_SERVICE_TYPE_PAYROLL,
            INTEGRATION_PAYROLL_CONNECT_PAYROLL)

    def user_completed_onboarding(self):
        if not self.w4_info or not self.w4_info.total_points: 
            return not self.is_new_employee
        return True

    def has_complete_data(self):
        return self.user_completed_onboarding() \
            and (self.w4_info or not self.is_new_employee) \
            and (self.state_tax_info or not self.is_new_employee) \
            and self.company_info \
            and self.person_info \
            and self.employee_profile_info

    @property
    def is_new_employee(self):
        return self.employee_profile_info and self.employee_profile_info.new_employee
    def __init__(self):
        super(ConnectPayrollDataService, self).__init__()
        self.view_model_factory = ReportViewModelFactory()
        self.web_request_service = WebRequestService()
        self.company_personnel_service = CompanyPersonnelService()
        self.integration_provider_service = IntegrationProviderService()

        # Retrieve the api token if available
        setting_service = SystemSettingsService()
        self._cp_api_auth_token = setting_service.get_setting_value_by_name(
            SYSTEM_SETTING_CPAPIAUTHTOKEN)

        # Also construct the API url, if available
        self._cp_api_url = None
        base_uri = setting_service.get_setting_value_by_name(
            SYSTEM_SETTING_CPAPIBASEURI)
        employee_route = setting_service.get_setting_value_by_name(
            SYSTEM_SETTING_CPAPIEMPLOYEEROUTE)
        if (base_uri and employee_route):
            self._cp_api_url = base_uri + employee_route
Ejemplo n.º 4
0
 def __init__(self):
     super(PayrollPeriodExportCsvServiceBase, self).__init__()
     self.time_punch_card_service = TimePunchCardService()
     self.integration_provider_service = IntegrationProviderService()
     self.week_days = 0
Ejemplo n.º 5
0
class PayrollPeriodExportCsvServiceBase(CsvReportServiceBase):
    ''' Big assumptions and TODOs
        * The expectation for this export is weekly
        * Though salary rate exported here is per pay period
        * Personal Leave is the only card type that does not count towards hours reported
        * Company Holiday is counted as 8 hours
        * Only export employee's who is at least partially active in the period
        * The report does not try to prorate if employee was terminated during the period. 
    '''
    def __init__(self):
        super(PayrollPeriodExportCsvServiceBase, self).__init__()
        self.time_punch_card_service = TimePunchCardService()
        self.integration_provider_service = IntegrationProviderService()
        self.week_days = 0

    #########################################
    ## Abstract methods - Begin
    #########################################

    def _get_integration_payroll_service_name(self):
        raise NotImplementedError()

    def _needs_write_header_row(self):
        raise NotImplementedError()

    def _write_headers(self):
        raise NotImplementedError()

    def _get_pay_code(self, earning_type):
        raise NotImplementedError()

    def _get_pay_name(self, earning_type):
        raise NotImplementedError()

    def _write_row(self, row_data):
        raise NotImplementedError()

    def _get_employee_data_rows(self, employee_user_id, person_info,
                                employee_profile_info,
                                employees_reported_hours):
        raise NotImplementedError()

    #########################################
    ## Abstract methods - End
    #########################################

    def get_report(self, company_id, period_start, period_end, outputStream):
        client_id = self._get_client_number(company_id)
        if (not client_id):
            raise ValueError(
                'The company is not properly configured to integrate with Payroll service!'
            )

        if (self._needs_write_header_row()):
            self._write_headers()

        self._write_company(company_id, period_start, period_end)
        self._save(outputStream)

    def _get_client_number(self, company_id):
        service_name = self._get_integration_payroll_service_name()
        return self.integration_provider_service.get_company_integration_provider_external_id(
            company_id, INTEGRATION_SERVICE_TYPE_PAYROLL, service_name)

    def _write_company(self, company_id, period_start, period_end):
        user_ids = self._get_all_employee_user_ids_for_company(company_id)

        # Get the time tracking data for the company, for the date period
        # specified
        employees_reported_hours = self.time_punch_card_service.get_company_users_reported_hours_by_date_range(
            company_id, period_start, period_end)

        # Construct the company specific view model factory
        view_model_factory = CompanyReportViewModelFactory(company_id)

        company_info = view_model_factory.get_company_info()
        company_payroll_id = self._get_client_number(company_id)

        # For each of them, write out his/her information
        for i in range(len(user_ids)):
            employee_user_id = user_ids[i]
            employee_profile_info = view_model_factory.get_employee_employment_profile_data(
                employee_user_id)

            # Only report if the employee was, at least partially, active during the
            # report period.
            if (employee_profile_info and employee_profile_info.
                    is_employee_active_anytime_in_time_period(
                        period_start, period_end)):

                person_info = view_model_factory.get_employee_person_info(
                    employee_user_id)
                self._write_employee(employee_user_id, person_info,
                                     company_info, company_payroll_id,
                                     employee_profile_info,
                                     employees_reported_hours, period_start,
                                     period_end)

    def _write_employee(self, employee_user_id, person_info, company_info,
                        company_payroll_id, employee_profile_info,
                        employees_reported_hours, period_start, period_end):

        self.week_days = self._get_week_day_number(period_start, period_end,
                                                   employee_profile_info)
        rows = self._get_employee_data_rows(employee_user_id, person_info,
                                            company_info, company_payroll_id,
                                            employee_profile_info,
                                            employees_reported_hours)

        for row in rows:
            self._write_row(row)

    def _get_hours_by_earning_type(self, earning_type, employee_hours):
        if (earning_type == EARNING_TYPE_HOURLY):
            if employee_hours:
                return self._normalize_decimal_number(
                    employee_hours.paid_hours)
            else:
                return 0.0
        elif (earning_type == EARNING_TYPE_SALARY):
            salary_hours = SALARY_EMPLOYEE_HOURS_PER_DAY * self.week_days
            if (employee_hours):
                # if we have PTO, Holiday, unpaid_leave or Sick time cards for salary employees, remove those hours
                salary_hours -= employee_hours.paid_time_off_hours
                salary_hours -= employee_hours.holiday_hours
                salary_hours -= employee_hours.sick_time_hours
                salary_hours -= employee_hours.unpaid_hours
            return self._normalize_decimal_number(salary_hours)
        elif (earning_type == EARNING_TYPE_OVERTIME):
            return employee_hours.overtime_hours
        elif (earning_type == EARNING_TYPE_PTO):
            return employee_hours.paid_time_off_hours
        elif (earning_type == EARNING_TYPE_SICK_TIME):
            return employee_hours.sick_time_hours
        elif (earning_type == EARNING_TYPE_HOLIDAY):
            return employee_hours.holiday_hours
        elif (earning_type == EARNING_TYPE_UNPAID_LEAVE):
            return employee_hours.unpaid_hours

    def _get_employee_pay_rate(self, employee_profile_info):
        if (employee_profile_info.pay_type == PAY_TYPE_HOURLY
                and employee_profile_info.current_hourly_rate):
            return employee_profile_info.current_hourly_rate
        return ''

    def _normalize_decimal_number(self, decimal_number):
        result = decimal_number
        if (decimal_number == 0 or decimal_number):
            result = "{:.2f}".format(float(decimal_number))
        return result

    def _get_week_day_number(self, start, end, profile_info):
        # The solution below comes from
        # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-09/3758.html
        dates_start = start
        if profile_info.hire_date:
            dates_start = max(start, profile_info.hire_date)
        dates_end = end
        if profile_info.end_date:
            dates_end = min(end, profile_info.end_date)
        dates = rrule.rruleset()  # create an rrule.rruleset instance
        dates.rrule(
            rrule.rrule(rrule.DAILY, dtstart=dates_start, until=dates_end))
        # this set is INCLUSIVE of alpha and omega
        dates.exrule(
            rrule.rrule(rrule.DAILY,
                        byweekday=(rrule.SA, rrule.SU),
                        dtstart=start))
        # here's where we exclude the weekend dates
        return len(list(dates))  # there's probably a faster way to handle this
Ejemplo n.º 6
0
 def __init__(self):
     self._integration_provider_service = IntegrationProviderService()
Ejemplo n.º 7
0
class IntegrationProviderDataServiceBase(object):
    def __init__(self):
        self._integration_provider_service = IntegrationProviderService()

    #############################################
    ## Abstract members
    #############################################

    def _integration_service_type(self):
        raise NotImplementedError(
            'Concrete implementation needs to specify the integration service type it supports.'
        )

    def _integration_provider_name(self):
        raise NotImplementedError(
            'Concrete implementation needs to specify the name of the service provider it supports.'
        )

    def _internal_sync_employee_data_to_remote(self, employee_user_id):
        pass

    def _internal_generate_and_record_external_employee_number(
            self, employee_user_id):
        pass

    #############################################
    ## Abstract members
    #############################################
    ''' Whether this given employee is supported by this integration service data facility
        i.e. whether the corresponding integration service type and provider is available
        to the given employee
    '''

    def is_supported(self, employee_user_id):
        return self._integration_provider_service.is_integration_service_available_to_employee(
            employee_user_id, self._integration_service_type(),
            self._integration_provider_name())

    ''' Synchronize all appropriate data related to the given
        employee to the external service provider
    '''

    def sync_employee_data_to_remote(self, employee_user_id):
        if (not self.is_supported(employee_user_id)):
            raise ValueError(
                'The operation is not supported for employee: "{0}"'.format(
                    employee_user_id))
        self._internal_sync_employee_data_to_remote(employee_user_id)

    ''' Generate external employee number (normally for a new employee),
        and record that in WBM system.
    '''

    def generate_and_record_external_employee_number(self, employee_user_id):
        if (not self.is_supported(employee_user_id)):
            raise ValueError(
                'The operation is not supported for employee: "{0}"'.format(
                    employee_user_id))
        self._internal_generate_and_record_external_employee_number(
            employee_user_id)

    def _get_employee_external_id(self, employee_user_id, service_type,
                                  provider_name):
        return self._integration_provider_service.get_employee_integration_provider_external_id(
            employee_user_id, service_type, provider_name)

    def _set_employee_external_id(self, employee_user_id, service_type,
                                  provider_name, external_id):
        self._integration_provider_service.set_employee_integration_provider_external_id(
            employee_user_id, service_type, provider_name, external_id)
 def __init__(self):
     super(AdvantagePayrollCompanySetupCsvService, self).__init__()
     self.view_model_factory = ReportViewModelFactory()
     self.integration_provider_service = IntegrationProviderService()
class AdvantagePayrollCompanySetupCsvService(CsvReportServiceBase):
    def __init__(self):
        super(AdvantagePayrollCompanySetupCsvService, self).__init__()
        self.view_model_factory = ReportViewModelFactory()
        self.integration_provider_service = IntegrationProviderService()

    def get_report(self, company_id, outputStream):
        ap_client_id = self._get_ap_client_number(company_id)
        if (not ap_client_id):
            raise ValueError(
                'The company is not properly configured to integrate with Advantage Payroll service!'
            )

        self._write_headers()
        self._write_company(company_id, ap_client_id)
        self._save(outputStream)

    def _get_ap_client_number(self, company_id):
        return self.integration_provider_service.get_company_integration_provider_external_id(
            company_id, INTEGRATION_SERVICE_TYPE_PAYROLL,
            INTEGRATION_PAYROLL_ADVANTAGE_PAYROLL)

    def _write_headers(self):

        # IDs
        self._write_cell('CLTNO')
        self._write_cell('EMPNO')

        # Basic Info
        self._write_cell('FIRSTNAME')
        self._write_cell('LASTNAME')
        self._write_cell('BIRTHDATE')
        self._write_cell('SEX')
        self._write_cell('SSN')
        self._write_cell('ADDR1')
        self._write_cell('ADDR2')
        self._write_cell('CITY')
        self._write_cell('STATE')
        self._write_cell('ZIPCODE')

        # Employment Profile
        self._write_cell('HIREDATE')
        self._write_cell('CYCLE')
        self._write_cell('DEPT')
        self._write_cell('STATUS')
        self._write_cell('WORKSTATE')

        # Compensation
        self._write_cell('SCHEDHRS')
        self._write_cell('PAYCODE')
        self._write_cell('HOURLYRATE')
        self._write_cell('SALARYAMT')
        self._write_cell('RATEDATE')

        # Tax Witholding
        self._write_cell('FITSTATUS')
        self._write_cell('FITEXEMPT')
        self._write_cell('FITAMT')
        self._write_cell('SITSTATUS')
        self._write_cell('SITCODE')

    def _write_company(self, company_id, ap_client_id):
        user_ids = self._get_all_employee_user_ids_for_company(company_id)

        # For each of them, write out his/her information
        for i in range(len(user_ids)):
            self._write_employee(user_ids[i], company_id, ap_client_id)

    def _user_completed_onboarding(self, company_id, user_id, w4_info):
        if not w4_info or not w4_info.total_points:
            comp_user = CompanyUser.objects.get(
                user=user_id,
                company_user_type=USER_TYPE_EMPLOYEE,
                company=company_id)
            return not comp_user.new_employee
        return True

    def _write_employee(self, employee_user_id, company_id, ap_client_id):
        w4_info = self.view_model_factory.get_employee_w4_data(
            employee_user_id)
        if not self._user_completed_onboarding(company_id, employee_user_id,
                                               w4_info):
            return
        company_info = self.view_model_factory.get_company_info(company_id)
        person_info = self.view_model_factory.get_employee_person_info(
            employee_user_id)

        # now start writing the employee row
        self._next_row()

        # Client number, this comes from the AP system
        self._write_cell(ap_client_id)

        # Employee Number, this comes from the AP system.
        ap_employee_number = self.integration_provider_service.get_employee_integration_provider_external_id(
            employee_user_id, INTEGRATION_SERVICE_TYPE_PAYROLL,
            INTEGRATION_PAYROLL_ADVANTAGE_PAYROLL)
        self._write_cell(ap_employee_number)

        # Now write the basic personal info of the employee
        self._write_employee_basic_info(person_info)

        # Now write the employee's employment profile details
        self._write_employee_employment_profile_info(employee_user_id,
                                                     company_info)

        # Noew write the employee's w4/witholding info
        self._write_employee_w4_info(company_info, w4_info)

    def _write_employee_basic_info(self, person_info):
        self._write_cell(person_info.first_name)
        self._write_cell(person_info.last_name)
        self._write_cell(self._get_date_string(person_info.birth_date))
        self._write_cell(person_info.gender)
        self._write_cell(person_info.ssn)
        self._write_cell(person_info.address1)
        self._write_cell(person_info.address2)
        self._write_cell(person_info.city)
        self._write_cell(person_info.state)
        self._write_cell(person_info.zipcode)

    def _write_employee_employment_profile_info(self, user_ids, company_info):
        employee_profile_info = self.view_model_factory.get_employee_employment_profile_data(
            user_ids, company_info.company_id)

        if (not employee_profile_info):
            self._skip_cells(10)
            return

        # Profile
        self._write_cell(self._get_date_string(
            employee_profile_info.hire_date))
        self._write_cell(
            self._get_pay_cycle_code(employee_profile_info.pay_cycle))

        # [TODO]: For now, skip the department info
        self._skip_cells(1)
        self._write_cell(
            self._get_employment_status_code(
                employee_profile_info.employment_status))

        # [TODO]: For now, use the company address state as the employee
        #         work state
        self._write_cell(company_info.state)

        # Compensation
        self._write_cell(
            self._normalize_decimal_number(
                employee_profile_info.projected_hours_per_pay_cycle))
        self._write_cell(
            self._get_employee_pay_type_code(employee_profile_info.pay_type))
        self._write_cell(
            self._normalize_decimal_number(
                employee_profile_info.current_hourly_rate))
        self._write_cell(
            self._get_employee_current_pay_period_salary(
                employee_profile_info))
        self._write_cell(
            self._get_date_string(
                employee_profile_info.compensation_effective_date))

    def _write_employee_w4_info(self, company_info, w4_info):
        if (w4_info):
            status_code = self._get_w4_marriage_status_code(
                w4_info.marriage_status)

            self._write_cell(status_code)
            self._write_cell(w4_info.total_points)
            self._write_cell(w4_info.extra_amount)

            # [TODO]: For now, use the federal w4 info to fill state fields
            # [TODO]: For now, use the company state for the state withold code
            self._write_cell(status_code)
            self._write_cell(company_info.state)

        else:
            self._skip_cells(5)

    def _get_w4_marriage_status_code(self, marriage_status):
        if (marriage_status == W4_MARRIAGE_STATUS_SINGLE):
            return 'S'
        elif (marriage_status == W4_MARRIAGE_STATUS_MARRIED):
            return 'M'
        elif (marriage_status == W4_MARRIAGE_STATUS_MARRIED_HIGH_SINGLE):
            return 'S'
        else:
            return ''

    def _get_pay_cycle_code(self, pay_cycle):
        if (pay_cycle == PERIOD_WEEKLY):
            return 'W'
        elif (pay_cycle == PERIOD_BIWEEKLY):
            return 'B'
        elif (pay_cycle == PERIOD_SEMIMONTHLY):
            return 'S'
        elif (pay_cycle == PERIOD_MONTHLY):
            return 'M'
        else:
            return ''

    def _get_employment_status_code(self, employment_status):
        if (employment_status == EMPLOYMENT_STATUS_ACTIVE):
            return 'A'
        elif (employment_status == EMPLOYMENT_STATUS_TERMINATED):
            return 'T'
        else:
            return ''

    def _get_employee_pay_type_code(self, employee_pay_type):
        if (employee_pay_type == PAY_TYPE_HOURLY):
            return 'H'
        elif (employee_pay_type == PAY_TYPE_SALARY):
            return 'S'
        else:
            return ''

    def _get_employee_current_pay_period_salary(self, employee_profile_info):
        if (employee_profile_info.pay_type == PAY_TYPE_HOURLY):
            return 0
        else:
            return self._normalize_decimal_number(
                employee_profile_info.current_pay_period_salary)

    def _normalize_decimal_number(self, decimal_number):
        result = decimal_number
        if (decimal_number == 0 or decimal_number):
            result = "{:.2f}".format(float(decimal_number))
        return result
Ejemplo n.º 10
0
 def __init__(self):
     super(ConnectPayrollCompanyEmployeeFrontPageCsvService, self).__init__()
     self.integration_provider_service = IntegrationProviderService()
     self.logger = LoggingService()
     self._state_tax_election_adaptor_factory = ConnectPayrollStateTaxElectionAdaptorFactory()
Ejemplo n.º 11
0
class ConnectPayrollCompanyEmployeeFrontPageCsvService(CsvReportServiceBase):

    ########################################################################
    ## Items of further investigations
    ## * [Employement Type] WBM: Only W-2   CP: W-2 and 1099-M
    ## * [W-4 Status] WBM: Married high rate    CP: Head of house hold
    ## * [W-4 withold state] WBM: Company State (correct?). CP: allow more options
    ## * [W-4 additional amount] WBM: additional dollar.  CP: more options
    ## * [I-9 status] WBM does not know F-1/J-1 status
    ## * [Employment Status] Does WBM include terminated employees?
    ## * [New Hire Flag] Does the NewHire flag stands for the same expectation
    ##   on WBM and CP?
    ## * [I-9/W-4 non-new employee] WBM does not have data, what would CP expect?
    ########################################################################

    def __init__(self):
        super(ConnectPayrollCompanyEmployeeFrontPageCsvService, self).__init__()
        self.integration_provider_service = IntegrationProviderService()
        self.logger = LoggingService()
        self._state_tax_election_adaptor_factory = ConnectPayrollStateTaxElectionAdaptorFactory()

    def get_report(self, company_id, outputStream):
        try:
            self.view_model_factory = CompanyReportViewModelFactory(company_id)
            client_id = self._get_client_number(company_id)
            if (not client_id):
                raise ValueError('The company is not properly configured to integrate with Connect Payroll service!')

            self._write_headers()
            self._write_company(company_id, client_id)
            self._save(outputStream)
        except Exception as e:
            self.logger.error('Failed to produce Connect Payroll Employee Front Page export for company "{0}"'.format(company_id))
            self.logger.error(traceback.format_exc())
            raise e

    def _get_client_number(self, company_id):
        return self.integration_provider_service.get_company_integration_provider_external_id(
            company_id,
            INTEGRATION_SERVICE_TYPE_PAYROLL,
            INTEGRATION_PAYROLL_CONNECT_PAYROLL)

    def _write_headers(self):

        # Integration Identifier
        self._write_cell('EmpNumber')
        self._write_cell('Ssn')

        # Organizational Allocation
        self._write_cell('HomeLocation')
        self._write_cell('Division')
        self._write_cell('Department')

        # Employee Name
        self._write_cell('FirstName')
        self._write_cell('MiddleName')
        self._write_cell('LastName')

        # Pay Schedule
        self._write_cell('PayFrequency')
        self._write_cell('ScheduleName')

        # Employee Address
        self._write_cell('AddressLine1')
        self._write_cell('AddressLine2')
        self._write_cell('City')
        self._write_cell('ResidentState')
        self._write_cell('ZipCode')
        self._write_cell('ZipCodeExt')

        # Employment Type
        self._write_cell('EmpType')

        # Federal Tax
        self._write_cell('FedFS')
        self._write_cell('FedExemptions')
        self._write_cell('FedAddl')
        self._write_cell('FedAmt')
        self._write_cell('WorkingIn')
        self._write_cell('WithholdIncomeTaxIn')

        # State Tax
        self._write_cell('StateFS')
        self._write_cell('StateExemptions')
        self._write_cell('StateAddlExemptions')
        self._write_cell('StateAddl')
        self._write_cell('StateAmt')
        self._write_cell('SecondStateFS')
        self._write_cell('SecondStateExemptions')
        self._write_cell('SecondStateAddlExemptions')
        self._write_cell('SecondStateAddl')
        self._write_cell('SecondStateAmt')

        # 1099-M Employee Info
        # [Remark] WBM Non-supported
        self._write_cell('ApplyFedId')

        # Employee HR Info
        self._write_cell('Email')
        self._write_cell('BirthDate')

        # Salary Data
        self._write_cell('Salary')
        self._write_cell('SalaryDate')
        self._write_cell('Rate')
        self._write_cell('RateDate')

        # Other HR Data
        self._write_cell('NewHire')
        self._write_cell('Seasonal')
        self._write_cell('HireDate')
        self._write_cell('Gender')
        self._write_cell('J1F1Visa')
        self._write_cell('VisaDate')
        self._write_cell('Status')
        self._write_cell('StatusDate')
        self._write_cell('StatusReason')

        # Other Tax Data
        # [Remark] WBM Non-supported
        self._write_cell('SsExempt')
        self._write_cell('MedcExempt')
        self._write_cell('FutaExempt')
        self._write_cell('FutaExemptReason')
        self._write_cell('SuiExempt')
        self._write_cell('NonUsAddress')
        self._write_cell('PostalCode1')
        self._write_cell('PostalCode2')
        self._write_cell('PostalCode3')
        self._write_cell('Country')

    def _write_company(self, company_id, client_id):
        user_ids = self._get_all_employee_user_ids_for_company(company_id)

        # For each of them, write out his/her information
        for i in range(len(user_ids)):
            self._write_employee(user_ids[i], company_id, client_id)

    def _write_employee(self, employee_user_id, company_id, client_id):
        employee_data_context = _EmployeeDataContext(employee_user_id, company_id, self.view_model_factory)

        if not employee_data_context.user_completed_onboarding():
            self.logger.warn('Skipping employee "{0}": Onboarding not complete.'.format(employee_user_id))
            return
        if (not employee_data_context.has_complete_data()):
            self.logger.warn('Skipping employee "{0}": Missing necessary information'.format(employee_user_id))
            return

        # now start writing the employee row
        self._next_row()

        self._write_integration_info(employee_data_context)
        self._write_organizational_allocation_info(employee_data_context)
        self._write_employee_name(employee_data_context)
        self._write_employee_pay_schedule(employee_data_context)
        self._write_employee_address(employee_data_context)
        self._write_employment_type(employee_data_context)
        self._write_federal_tax_info(employee_data_context)
        self._write_state_tax_info(employee_data_context)
        self._write_1099M_data(employee_data_context)
        self._write_employee_HR_info(employee_data_context)
        self._write_employee_salary_data(employee_data_context)
        self._write_employee_other_HR_data(employee_data_context)

    def _write_integration_info(self, employee_data_context):
        self._write_cell(employee_data_context.employee_number)
        self._write_cell(employee_data_context.person_info.ssn)

    def _write_organizational_allocation_info(self, employee_data_context):
        # Skippng 'HomeLocation' as it is not used
        self._skip_cells(1)

        employee_profile_info = employee_data_context.employee_profile_info
        
        if (employee_profile_info.division and employee_profile_info.division.code):
            self._write_cell(employee_profile_info.division.code)
        else:
            self._skip_cells(1)

        if (employee_profile_info.department and employee_profile_info.department.code):
            self._write_cell(employee_profile_info.department.code)
        else:
            self._skip_cells(1)

    def _write_employee_name(self, employee_data_context):
        person_info = employee_data_context.person_info

        self._write_cell(person_info.first_name)
        self._write_cell(person_info.middle_name)
        self._write_cell(person_info.last_name)

    def _write_employee_pay_schedule(self, employee_data_context):
        employee_profile_info = employee_data_context.employee_profile_info

        mapped_paycode = self._get_pay_cycle_code(employee_profile_info.pay_cycle)
        if (not mapped_paycode):
            self.logger.warn('[Data Issue] Employee "{0}": has invalid pay-code'.format(employee_data_context.employee_user_id))
            self._skip_cells(1)
        else:
            self._write_cell(mapped_paycode)

        # Skip the 'ScheduleName' field
        self._skip_cells(1)

    def _get_pay_cycle_code(self, pay_cycle):
        if (pay_cycle == PERIOD_WEEKLY):
            return 'Weekly'
        elif(pay_cycle == PERIOD_BIWEEKLY):
            return 'Biweekly'
        elif(pay_cycle == PERIOD_SEMIMONTHLY):
            return 'Semi-Monthly'
        elif(pay_cycle == PERIOD_MONTHLY):
            return 'Monthly'
        else:
            return ''

    def _write_employee_address(self, employee_data_context):
        person_info = employee_data_context.person_info
        self._write_cell(person_info.address1)
        self._write_cell(person_info.address2)
        self._write_cell(person_info.city)
        self._write_cell(person_info.state)

        zip_and_ext = person_info.get_zipcode_and_extension()
        self._write_cell(zip_and_ext[0])
        self._write_cell(zip_and_ext[1])

    def _write_employment_type(self, employee_data_context):
        # [Remark]: We only support W2 employee (?)
        self._write_cell('W2')

    def _write_federal_tax_info(self, employee_data_context):
        w4_info = employee_data_context.w4_info

        if (not w4_info):
            self._skip_cells(6)
        else:
            company_info = employee_data_context.company_info

            status_code = self._get_w4_marriage_status_code(w4_info.marriage_status)

            self._write_cell(status_code)
            self._write_cell(w4_info.total_points)
            self._write_cell('A')
            self._write_cell(w4_info.extra_amount)
            self._write_cell(company_info.state)
            self._write_cell(company_info.state)

    def _get_w4_marriage_status_code(self, marriage_status):
        if (marriage_status == W4_MARRIAGE_STATUS_SINGLE):
            return 'S'
        elif(marriage_status == W4_MARRIAGE_STATUS_MARRIED):
            return 'M'
        elif(marriage_status == W4_MARRIAGE_STATUS_MARRIED_HIGH_SINGLE):
            return 'H'
        else:
            return ''

    def _write_state_tax_info(self, employee_data_context):
        state_tax_info = employee_data_context.state_tax_info

        # This limits how many state elections CP can take and hence
        # we can output
        export_limit = 2
        counter = 0

        if (state_tax_info):
            all_state_elections = state_tax_info.get_all_state_elections()

            for state in all_state_elections:
                if (counter >= export_limit):
                    break
                adaptor = self._state_tax_election_adaptor_factory.get_adaptor(state, all_state_elections[state])
                if (adaptor):
                    self._write_cell(adaptor.get_filing_status())
                    self._write_cell(adaptor.get_total_exemptions())
                    self._write_cell(adaptor.get_additional_exemptions())
                    self._write_cell(adaptor.get_additional_amount_code())
                    self._write_cell(adaptor.get_additional_amount())

                    counter = counter + 1

        # Skip any set of fields that the employee does not have data to fill
        # E.g. secondary state witholding
        self._skip_cells((export_limit - counter) * 5)

    def _write_1099M_data(self, employee_data_context):
        # [Remark]: WBM does not support 1099-M
        self._skip_cells(1)

    def _write_employee_HR_info(self, employee_data_context):
        person_info = employee_data_context.person_info
        self._write_cell(person_info.email)
        self._write_cell(self._get_date_string(person_info.birth_date))

    def _write_employee_salary_data(self, employee_data_context):
        employee_profile_info = employee_data_context.employee_profile_info
        pay_type = employee_profile_info.pay_type
        if (pay_type == PAY_TYPE_HOURLY):
            self._skip_cells(2)
            self._write_cell(self._normalize_decimal_number(employee_profile_info.current_hourly_rate))
            self._write_cell(self._get_date_string(employee_profile_info.compensation_effective_date))
        elif (pay_type == PAY_TYPE_SALARY):
            self._write_cell(self._normalize_decimal_number(employee_profile_info.annual_salary))
            self._write_cell(self._get_date_string(employee_profile_info.compensation_effective_date))
            self._skip_cells(2)
        else:
            self.logger.warn('Skipping data for employee "{0}": Invalid pay type.'.format(employee_data_context.employee_user_id))
            self._skip_cells(4)

    def _write_employee_other_HR_data(self, employee_data_context):
        employee_profile_info = employee_data_context.employee_profile_info
        person_info = employee_data_context.person_info

        self._write_cell(employee_profile_info.new_employee)
        # [Remark]: Seasonal is not supported on WBM and seems to not be used by CP
        self._skip_cells(1)
        self._write_cell(self._get_date_string(employee_profile_info.hire_date))
        self._write_cell(person_info.gender)

        # [Remark]: Skip all J1/F1 Visa 
        self._skip_cells(2)

        code_and_date = self._get_employement_status_code_and_date(employee_profile_info)
        if (not code_and_date):
            self.logger.warn('Skipping data for employee "{0}": Invalid employment status'.format(employee_data_context.employee_user_id))
            self._skip_cells(2)
        else:
            self._write_cell(code_and_date['code'])
            self._write_cell(code_and_date['date'])

        # [Remark]: Skip the status reason
        self._skip_cells(1)

    def _get_employement_status_code_and_date(self, employee_profile_info):
        employment_status = employee_profile_info.employment_status
        if (employment_status == EMPLOYMENT_STATUS_ACTIVE):
            return {
                'code': 'Active',
                'date': self._get_date_string(employee_profile_info.hire_date)
            }
        elif (employment_status == EMPLOYMENT_STATUS_TERMINATED):
            return {
                'code': 'Terminated',
                'date': self._get_date_string(employee_profile_info.end_date)
            }
        else:
            return None

    def _write_other_tax_data(self, employee_data_context):
        # [Remark] WBM Non-supported
        # [Remark] CP does not seem to use 
        self._skip_cells(10)

    def _normalize_decimal_number(self, decimal_number):
        result = decimal_number
        if (decimal_number == 0 or decimal_number):
            result = "{:.2f}".format(float(decimal_number))
        return result
Ejemplo n.º 12
0
 def __init__(self):
     super(AdvantagePayrollDataService, self).__init__()
     self.company_personnel_service = CompanyPersonnelService()
     self.integration_provider_service = IntegrationProviderService()
Ejemplo n.º 13
0
class AdvantagePayrollDataService(IntegrationProviderDataServiceBase):

    def __init__(self):
        super(AdvantagePayrollDataService, self).__init__()
        self.company_personnel_service = CompanyPersonnelService()
        self.integration_provider_service = IntegrationProviderService()

    def _integration_service_type(self):
        return INTEGRATION_SERVICE_TYPE_PAYROLL

    def _integration_provider_name(self):
        return INTEGRATION_PAYROLL_ADVANTAGE_PAYROLL

    def _internal_generate_and_record_external_employee_number(self, employee_user_id):
        # First check whether the said employee already have a number
        # If so, this is an exception state, log it, and skip the operation
        employee_number = self.integration_provider_service.get_employee_integration_provider_external_id(
            employee_user_id,
            self._integration_service_type(),
            self._integration_provider_name())
        if (employee_number):
            logging.error('Invalid Operation: Try to generate external ID for employee (User ID={0}) already has one!'.format(employee_user_id))
            return

        company_id = self.company_personnel_service.get_company_id_by_employee_user_id(employee_user_id)
        next_employee_number = self._get_next_external_employee_number(company_id)
        # Now save the next usable external employee number to the profile
        # of the specified employee
        self._set_employee_external_id(
            employee_user_id,
            self._integration_service_type(),
            self._integration_provider_name(),
            next_employee_number
        )

    def _get_next_external_employee_number(self, company_id):
        employee_number_seed_str = self.integration_provider_service.get_company_integration_provider_employee_external_id_seed(
            company_id,
            self._integration_service_type(),
            self._integration_provider_name())
        employee_number_seed = 0
        if (employee_number_seed_str):
            try: 
                employee_number_seed = int(employee_number_seed_str)
            except ValueError:
                logging.exception('Encountered malformed external employee number seed: "{0}"'.format(employee_number_seed_str))

        max_employee_number = self._get_max_external_employee_number(company_id)
        return max(employee_number_seed, max_employee_number) + 1

    def _get_max_external_employee_number(self, company_id):
        all_employee_data = CompanyUserIntegrationProvider.objects.filter(
                company_user__company=company_id,
                integration_provider__service_type=self._integration_service_type(),
                integration_provider__name=self._integration_provider_name())

        employee_numbers = []
        for employee_data in all_employee_data:
            if (employee_data.company_user_external_id):
                # For AP, it is assumed that all employee numbers 
                # are positive integers. Though just build some 
                # fault tolerence here, to log the exception and
                # let it go, to not block all employee creations
                # if for some reason there is a malformed ID in 
                # system.
                try: 
                    employee_number = int(employee_data.company_user_external_id)
                    employee_numbers.append(employee_number)
                except ValueError:
                    logging.exception('Encountered malformed external employee number: "{0}"'.format(employee_data.company_user_external_id))

        if (len(employee_numbers) > 0):
            return max(employee_numbers)

        return 0
class CompanyIntegrationProviderDataService(object):
    _logger = LoggingService()

    def __init__(self):
        self.integration_provider_service = IntegrationProviderService()
        self.company_personnel_service = CompanyPersonnelService()

        self._data_service_registry = {}
        for integration_provider_type in INTEGRATION_SERVICE_TYPES:
            self._data_service_registry[integration_provider_type] = {}      

        self._register_data_service_classes()

    def _register_data_service_classes(self):
        # Register all data services
        self._data_service_registry[INTEGRATION_SERVICE_TYPE_PAYROLL][INTEGRATION_PAYROLL_CONNECT_PAYROLL] = ConnectPayrollDataService
        self._data_service_registry[INTEGRATION_SERVICE_TYPE_PAYROLL][INTEGRATION_PAYROLL_ADVANTAGE_PAYROLL] = AdvantagePayrollDataService

    def sync_employee_data_to_remote(self, employee_user_id):
        # Enumerate through all the integration providers associated
        # with the company, identify all registered data services, 
        # and invoke them to sync with the remote
        company_id = self.company_personnel_service.get_company_id_by_employee_user_id(employee_user_id)
        if (not company_id):
            return
        return self._enumerate_company_data_services(company_id, lambda data_service: data_service.sync_employee_data_to_remote(employee_user_id))

    def generate_and_record_external_employee_number(self, employee_user_id):
        company_id = self.company_personnel_service.get_company_id_by_employee_user_id(employee_user_id)
        if (not company_id):
            raise ValueError('The given employee user ID "{0}" is not properly linked to a valid company.'.format(employee_user_id))
        return self._enumerate_company_data_services(company_id, lambda data_service: data_service.generate_and_record_external_employee_number(employee_user_id))

    def _enumerate_company_data_services(self, company_id, data_service_action):
        # Record failed actions and report back to caller
        failed_data_service_records = []

        company_integration_providers = self.integration_provider_service.get_company_integration_providers(company_id)
        for service_type in company_integration_providers:
            company_service_type_provider = company_integration_providers[service_type]
            if (company_service_type_provider):
                provider_name = company_service_type_provider['integration_provider']['name']
                # Now we have the service type and the provider name, check whether
                # we have a registered data service class
                if (service_type in self._data_service_registry):
                    service_type_data_services = self._data_service_registry[service_type]
                    if (provider_name in service_type_data_services):
                        # create an instance of the date service, and invoke the action
                        data_service = service_type_data_services[provider_name]()

                        # Collect the current data service specs into a record instance
                        # for logging and anormaly reporting to upstream
                        service_action_record = IntegrationDataServiceActionRecord(
                            company_id=company_id,
                            service_type=service_type,
                            provider_name=provider_name,
                            service_action=data_service_action
                        )

                        try:
                            data_service_action(data_service)
                            self._logger.error('Successfully executed integration data action')
                            self._logger.info(service_action_record)
                        except Exception as e:
                            self._logger.error('Failed to complete integration data action')
                            self._logger.info(service_action_record)
                            failed_data_service_records.append(service_action_record)
                else:
                    self._logger.warning('Unsupported integration service type encoutered: "{0}"'.format(service_type))

        return failed_data_service_records
class ConnectPayrollDataService(IntegrationProviderDataServiceBase):
    _logger = LoggingService()

    def __init__(self):
        super(ConnectPayrollDataService, self).__init__()
        self.view_model_factory = ReportViewModelFactory()
        self.web_request_service = WebRequestService()
        self.company_personnel_service = CompanyPersonnelService()
        self.integration_provider_service = IntegrationProviderService()

        # Retrieve the api token if available
        setting_service = SystemSettingsService()
        self._cp_api_auth_token = setting_service.get_setting_value_by_name(
            SYSTEM_SETTING_CPAPIAUTHTOKEN)

        # Also construct the API url, if available
        self._cp_api_url = None
        base_uri = setting_service.get_setting_value_by_name(
            SYSTEM_SETTING_CPAPIBASEURI)
        employee_route = setting_service.get_setting_value_by_name(
            SYSTEM_SETTING_CPAPIEMPLOYEEROUTE)
        if (base_uri and employee_route):
            self._cp_api_url = base_uri + employee_route

    def _integration_service_type(self):
        return INTEGRATION_SERVICE_TYPE_PAYROLL

    def _integration_provider_name(self):
        return INTEGRATION_PAYROLL_CONNECT_PAYROLL

    def _internal_generate_and_record_external_employee_number(
            self, employee_user_id):
        # First check whether the said employee already have a number
        # If so, this is an exception state, log it, and skip the operation
        employee_number = self.integration_provider_service.get_employee_integration_provider_external_id(
            employee_user_id, self._integration_service_type(),
            self._integration_provider_name())
        if (employee_number):
            logging.error(
                'Invalid Operation: Try to generate external ID for employee (User ID={0}) already has one!'
                .format(employee_user_id))
            return

        company_id = self.company_personnel_service.get_company_id_by_employee_user_id(
            employee_user_id)
        next_employee_number = self._get_next_external_employee_number(
            company_id)
        # Now save the next usable external employee number to the profile
        # of the specified employee
        self._set_employee_external_id(employee_user_id,
                                       self._integration_service_type(),
                                       self._integration_provider_name(),
                                       next_employee_number)

    def _get_next_external_employee_number(self, company_id):
        return 0

    def _internal_sync_employee_data_to_remote(self, employee_user_id):
        # If the Connect Payroll API's auth token is not specified
        # in the environment, consider this feature to be off, and
        # skip all together.
        if (not self._cp_api_auth_token):
            return

        if (not self._cp_api_url):
            return

        # Also check whether the employee belong to a company with
        # the right setup with the remote system. And also skip if
        # this is not the case
        external_company_id = self._get_cp_client_code_by_employee(
            employee_user_id)
        if (not external_company_id):
            return

        try:
            # Populate the data object from the current state of the employee in WBM system
            # Also apply client(WBM) side validation on the data, based on understanding of
            # documentation from ConnectPay
            employee_data_dto = self._get_employee_data_dto(
                employee_user_id, external_company_id)
            issue_list = self._validate_employee_data_dto(employee_data_dto)

            if (issue_list and len(issue_list) > 0):
                raise RuntimeError(
                    'There are problems collecting complete data required to sync to ConnectPay API for employee "{0}"'
                    .format(employee_user_id), issue_list)

            if (employee_data_dto.payrollId):
                # Already exists in CP system, update
                self._logger.info('Updating Employee CP ID: ' +
                                  employee_data_dto.payrollId)
                self._logger.info(employee_data_dto)
                self._update_employee_data_to_remote(employee_data_dto)
            else:
                # Does not yet exist in CP system, new employee addition, create
                self._logger.info(
                    'Creating new employee record on CP system ...')
                self._logger.info(employee_data_dto)
                payroll_id = self._create_employee_data_to_remote(
                    employee_data_dto)
                self._logger.info(
                    'Created Employee CP ID: {0}'.format(payroll_id))

                # Sync the cp ID from the response
                self._set_employee_external_id(
                    employee_user_id, self._integration_service_type(),
                    self._integration_provider_name(), payroll_id)
        except Exception as e:
            self._logger.error(traceback.format_exc())
            raise

    def _get_employee_data_dto(self, employee_user_id, external_company_id):
        # First populate the CP identifiers
        dto = ConnectPayrollEmployeeDto()
        dto.payrollId = self._get_employee_external_id(
            employee_user_id, self._integration_service_type(),
            self._integration_provider_name())
        dto.companyId = external_company_id

        # Now populate other data
        company_id = self.company_personnel_service.get_company_id_by_employee_user_id(
            employee_user_id)
        company_info = self.view_model_factory.get_company_info(company_id)
        person_info = self.view_model_factory.get_employee_person_info(
            employee_user_id)

        # Employee basic data
        dto.ssn = person_info.ssn
        dto.firstName = person_info.first_name
        dto.lastName = person_info.last_name
        dto.dob = self._get_date_string(person_info.birth_date)
        dto.gender = person_info.gender
        dto.address1 = person_info.address1
        dto.address2 = person_info.address2
        dto.city = person_info.city
        dto.country = person_info.country
        dto.state = person_info.state
        dto.zip = person_info.zipcode
        dto.email = person_info.email
        if (len(person_info.phones) > 0):
            dto.phone = person_info.phones[0]['number']

        # Employment data
        employee_profile_info = self.view_model_factory.get_employee_employment_profile_data(
            employee_user_id, company_info.company_id)

        if (employee_profile_info):
            dto.jobTitle = employee_profile_info.job_title
            dto.fullTime = employee_profile_info.is_full_time_employee()
            dto.hireDate = self._get_date_string(
                employee_profile_info.hire_date)
            dto.originalHireDate = self._get_date_string(
                employee_profile_info.hire_date)
            # [TODO]: Needs specification on employee status values
            dto.employeeStatus = '3'
            dto.terminationDate = self._get_date_string(
                employee_profile_info.end_date)

            # Salary data
            dto.payEffectiveDate = self._get_date_string(
                employee_profile_info.compensation_effective_date)
            dto.annualBaseSalary = self._get_decimal_string(
                employee_profile_info.annual_salary)
            dto.baseHourlyRate = self._get_decimal_string(
                employee_profile_info.current_hourly_rate)
            dto.hoursPerWeek = self._get_decimal_string(
                employee_profile_info.projected_hours_per_week)

        # Other
        employee_i9_info = self.view_model_factory.get_employee_i9_data(
            employee_user_id)
        if (employee_i9_info):
            self.usCitizen = employee_i9_info.citizen_data is not None

        return dto

    def _validate_employee_data_dto(self, employee_data_dto):
        issue_list = []

        # System Data
        _DataValidator(employee_data_dto, 'companyId', issue_list) \
            .with_value_exists_check() \
            .with_value_length_check(6, 6) \
            .validate()

        _DataValidator(employee_data_dto, 'payrollId', issue_list) \
            .with_value_valid_integer_check() \
            .validate()

        # Employee bio data and basic info
        _DataValidator(employee_data_dto, 'ssn', issue_list) \
            .with_value_exists_check() \
            .with_value_length_check(9, 9) \
            .validate()

        _DataValidator(employee_data_dto, 'firstName', issue_list) \
            .with_value_exists_check() \
            .with_value_length_check(1, 20) \
            .validate()

        _DataValidator(employee_data_dto, 'middleName', issue_list) \
            .with_value_length_check(0, 20) \
            .validate()

        _DataValidator(employee_data_dto, 'lastName', issue_list) \
            .with_value_exists_check() \
            .with_value_length_check(1, 20) \
            .validate()

        _DataValidator(employee_data_dto, 'dob', issue_list) \
            .with_value_exists_check() \
            .with_value_valid_datetime_check() \
            .validate()

        _DataValidator(employee_data_dto, 'gender', issue_list) \
            .with_value_exists_check() \
            .with_value_in_list_check(['M', 'F']) \
            .validate()

        _DataValidator(employee_data_dto, 'address1', issue_list) \
            .with_value_length_check(0, 30) \
            .validate()

        _DataValidator(employee_data_dto, 'address2', issue_list) \
            .with_value_length_check(0, 30) \
            .validate()

        _DataValidator(employee_data_dto, 'city', issue_list) \
            .with_value_length_check(0, 28) \
            .validate()

        _DataValidator(employee_data_dto, 'state', issue_list) \
            .with_value_exists_check() \
            .with_value_length_check(2, 2) \
            .validate()

        _DataValidator(employee_data_dto, 'zip', issue_list) \
            .with_value_exists_check() \
            .with_value_length_check(5, 10) \
            .validate()

        _DataValidator(employee_data_dto, 'country', issue_list) \
            .with_value_length_check(0, 30) \
            .validate()

        _DataValidator(employee_data_dto, 'email', issue_list) \
            .with_value_exists_check() \
            .with_value_length_check(1, 250) \
            .validate()

        _DataValidator(employee_data_dto, 'phone', issue_list) \
            .with_value_length_check(0, 14) \
            .validate()

        _DataValidator(employee_data_dto, 'phone', issue_list) \
            .with_value_length_check(0, 14) \
            .validate()

        # Employment data
        _DataValidator(employee_data_dto, 'department', issue_list) \
            .with_value_valid_integer_check() \
            .validate()

        _DataValidator(employee_data_dto, 'division', issue_list) \
            .with_value_valid_integer_check() \
            .validate()

        _DataValidator(employee_data_dto, 'union', issue_list) \
            .with_value_type_boolean_check() \
            .validate()

        _DataValidator(employee_data_dto, 'jobTitle', issue_list) \
            .with_value_length_check(0, 30) \
            .validate()

        _DataValidator(employee_data_dto, 'fullTime', issue_list) \
            .with_value_type_boolean_check() \
            .validate()

        _DataValidator(employee_data_dto, 'seasonal', issue_list) \
            .with_value_type_boolean_check() \
            .validate()

        _DataValidator(employee_data_dto, 'hireDate', issue_list) \
            .with_value_exists_check() \
            .with_value_valid_datetime_check() \
            .validate()

        _DataValidator(employee_data_dto, 'originalHireDate', issue_list) \
            .with_value_valid_datetime_check() \
            .validate()

        _DataValidator(employee_data_dto, 'terminationDate', issue_list) \
            .with_value_valid_datetime_check() \
            .validate()

        self.employeeStatus = None

        # Salary data
        _DataValidator(employee_data_dto, 'payEffectiveDate', issue_list) \
            .with_value_valid_datetime_check() \
            .validate()

        _DataValidator(employee_data_dto, 'annualBaseSalary', issue_list) \
            .with_value_valid_decimal_check() \
            .validate()

        _DataValidator(employee_data_dto, 'baseHourlyRate', issue_list) \
            .with_value_valid_decimal_check() \
            .validate()

        return issue_list

    def _update_employee_data_to_remote(self, employee_data_dto):
        data = employee_data_dto.__dict__

        response = self.web_request_service.put(
            self._cp_api_url,
            data_object=data,
            auth_token=self._cp_api_auth_token)

        response.raise_for_status()

    def _create_employee_data_to_remote(self, employee_data_dto):
        data = employee_data_dto.__dict__

        response = self.web_request_service.post(
            self._cp_api_url,
            data_object=data,
            auth_token=self._cp_api_auth_token)

        response.raise_for_status()

        # Also, we really only expect here the below based on CP API behavior
        # * HTTP 200
        # * body contains the resultant ID created
        # So throw if we receive anything else
        if (response.status_code != 200):
            raise RuntimeError(
                'POST to ConnectPay Employee API resulted in a non-200 status: "{0}"'
                .format(response.status_code), response)

        if (not response.text):
            raise RuntimeError(
                'POST to ConnectPay Employee API resulted in empty body, and hence was not able to receive new employee ID.'
            )

        return response.text

    def _get_cp_client_code_by_employee(self, employee_user_id):
        company_id = self.company_personnel_service.get_company_id_by_employee_user_id(
            employee_user_id)

        if (company_id):
            return self.integration_provider_service.get_company_integration_provider_external_id(
                company_id, self._integration_service_type(),
                self._integration_provider_name())

        return None

    def _get_date_string(self, date):
        if date:
            try:
                return date.isoformat()
            except:
                return None
        else:
            return None

    def _get_decimal_string(self, input_value):
        if isinstance(input_value, decimal.Decimal):
            return str(input_value)

        return input_value
Ejemplo n.º 16
0
 def get(self, request, company_id, format=None):
     service = IntegrationProviderService()
     result = service.get_company_integration_providers(company_id)
     return Response(result)