def get_workdiaries_by_contract(self, contract_id, date, tz=None): """ Retrieve workdiary snapshots by contract *Parameters:* :contract_id: The Contract ID. :date: The target date in `yyyymmdd` format. :tz: (optional) Time zone to use. Possible values: * 'mine' (default) * 'user' * 'gmt' """ url = 'workdiaries/contracts/{0}/{1}'.format(contract_id, date) data = {} if tz: assert_parameter('tz', tz, self.TZ_CHOICES) data['tz'] = tz result = self.get(url, data) if 'error' in result: return result snapshots = result.get('snapshots', data).get('snapshot', []) if not isinstance(snapshots, list): snapshots = [snapshots] return result['snapshots']['user'], snapshots
def get_workdays_by_contract(self, contract_id, from_date, till_date, tz=None): """ Retrieve workdays by contract *Parameters:* :contract_id: The Contract ID. :from_date: The target start date in `yyyymmdd` format. :end_date: The target end date in `yyyymmdd` format. :tz: (optional) Time zone to use. Possible values: * 'mine' (default) * 'user' * 'gmt' """ url = 'workdays/contracts/{0}/{1},{2}'.format(contract_id, from_date, till_date) data = {} if tz: assert_parameter('tz', tz, self.TZ_CHOICES) data['tz'] = tz result = self.get(url, data) if 'error' in result: return result workdays = result.get('workdays', data) if not isinstance(workdays, list): workdays = {} return workdays
def get_snapshots(self, company_or_team_id, online=None, disabled=None): """ Retrieve team member snapshots. *Parameters:* :company_or_team_id: The Company ID or Team ID :online: (optional) Filter user by work hours. Possible values are (default): * 'now' (default) * 'last_24h' * 'all' :disabled: (optional) Whether disabled users need to be returned in response. Possible values are (default): * 'no' (default) * 'yes' """ url = 'teamrooms/{0}'.format(company_or_team_id) data = {} if online: assert_parameter('online', online, self.ONLINE_CHOICES) data['online'] = online if disabled: assert_parameter('disabled', disabled, self.ONLINE_CHOICES) data['disabled'] = disabled result = self.get(url, data) if 'error' in result: return result if 'teamroom' in result and 'snapshot' in result['teamroom']: snapshots = result['teamroom']['snapshot'] else: snapshots = [] if not isinstance(snapshots, list): snapshots = [snapshots] return snapshots
def get_workdiaries(self, team_id, username, date=None, tz=None): """ Retrieve a team member's workdiaries for given date or today. *Parameters:* :team_id: The Team ID :username: The Team Member's username :date: (optional) A datetime object or a string in yyyymmdd format :tz: (optional) Time zone to use. Possible values: * 'mine' (default) * 'user' * 'gmt' """ url = 'workdiaries/{0}/{1}'.format(team_id, username) if date: url = '{0}/{1}'.format(url, date) result = self.get(url) if 'error' in result: return result data = {} if tz: assert_parameter('tz', tz, self.TZ_CHOICES) data['tz'] = tz snapshots = result.get('snapshots', data).get('snapshot', []) if not isinstance(snapshots, list): snapshots = [snapshots] #not sure we need to return user return result['snapshots']['user'], snapshots
def end_contract(self, contract_reference, reason, would_hire_again, fb_scores=None, fb_comment=None): """ Close the referenced contract. *Parameters:* :contract_reference: The Contract's reference ID :reason: The reason key, e.g. 'API_REAS_HIRED_DIFFERENT'. Possible values are: - 'API_REAS_MISREPRESENTED_SKILLS' - "Contractor misrepresented his/her skills" - 'API_REAS_CONTRACTOR_NOT_RESPONSIVE' - "Contractor not responsive" - 'API_REAS_HIRED_DIFFERENT' - "Hired a different contractor" - 'API_REAS_JOB_COMPLETED_SUCCESSFULLY' - "Job was completed successfully" - 'API_REAS_WORK_NOT_NEEDED' - "No longer need this work completed" - 'API_REAS_UNPROFESSIONAL_CONDUCT' - "Unprofessional conduct" :would_hire_again: Whether you would hire a contractor again. Required if total charge on the contract is $0. Possible values are: ['yes', 'no'] :fb_scores: (optional) Estimate, a dictionary of scores, where id is reference to score description (see example below). The feedback scores are optional, but if present they must be complete: all scores. Below are the possible score reference id values. Feedback on contractor: * ``3`` - "Skills / competency and skills for the job, understanding of specifications/instructions" * ``4`` - "Quality / quality of work deliveries" * ``5`` - "Availability / online presence on a consistent schedule" * ``6`` - "Deadlines / ability to complete tasks on time" * ``7`` - "Communication / communication skills, frequent progress updates, responsiveness" * ``8`` - "Cooperation / cooperation and flexibility, suggestions for improvement" Feedback on employer: * ``9`` - "Skills / competency and skills for the job, understanding of task complexities" * ``10`` - "Quality / quality of specifications/instructions" * ``11`` - "Availability / online presence on a consistent schedule" * ``12`` - "Deadlines / understanding of complexities and trade-offs" * ``13`` - "Communication / communication skills and responsiveness, feedback and guidance" * ``14`` - "Cooperation / cooperation and flexibility, open to suggestions for improvement" Example: {'fb_scores[3]': 5, 'fb_scores[4]': 4, ... , 'fb_scores[8]': 5} :fb_comment: (optional) Feedback comment, some string message. It is optional but if present, then the ``fb_scores`` parameter is also required. """ url = 'contracts/{0}'.format(contract_reference) data = {} assert_parameter('reason', reason, self.CONTRACT_REASON_OPTIONS) data['reason'] = reason assert_parameter('would_hire_again', would_hire_again, self.CONTRACT_WOULD_HIRE_AGAIN_OPTONS) data['would_hire_again'] = would_hire_again if fb_scores: for key, value in fb_scores.items(): data[key] = value if fb_comment: data['fb_comment'] = fb_comment result = self.delete(url, data) return result
def update_job(self, job_id, buyer_team_reference, title, description, visibility, category=None, subcategory=None, budget=None, duration=None, start_date=None, status=None): """ Update a job. *Parameters:* :job_id: Job reference ID :buyer_team_reference: Reference ID of the buyer team that is posting the job, e.g. 34567 :title: Title of the Job :description: The job's description :visibility: The job's visibility, e.g. 'private'. Possible values are: - 'public' jobs are available to all users who search jobs - 'private' job is visible to employer only - 'upwork' jobs appear in search results only for Upwork users who are logged into the service - 'invite-only' jobs do not appear in search and are used for jobs where the buyer wants to control the potential applicants :category: (optional) The category of job, e.g. 'Web Development' (where to get? - see Metadata API) :subcategory: (optional) The subcategory of job, e.g. 'Web Programming' (where to get? - see Metadata API) :budget: (conditionally optional) The budget of the Job, e.g. 100. Is used for 'fixed-price' jobs only. :duration: (conditionally optional) The duration of the job in hours, e.g. 90. Used for 'hourly-jobs' only. :start_date: (optional) The start date of the Job, e.g. 06-15-2011. If start_date is not included the job will default to starting immediately. :status: (required) The status of the job, e.g. 'filled'. Possible values are: - 'open' - 'filled' - 'cancelled' """ url = 'jobs/{0}'.format(job_id) data = {} data['buyer_team__reference'] = buyer_team_reference data['title'] = title data['description'] = description assert_parameter('visibility', visibility, self.JOB_VISIBILITY_OPTIONS) data['visibility'] = visibility data['category'] = category data['subcategory'] = subcategory if budget is None and duration is None: raise ApiValueError('Either one of the ``budget``or ``duration`` ' 'parameters must be specified') if budget: data['budget'] = budget if duration: data['duration'] = duration if start_date: data['start_date'] = start_date if status: assert_parameter('status', status, self.JOB_STATUSES) data['status'] = status else: raise ApiValueError('Missing required parameter "status"') return self.put(url, data)
def post_offer(self, job_reference, provider_team_reference=None, provider_reference=None, profile_key=None, message_from_buyer=None, engagement_title=None, attached_doc=None, fixed_charge_amount_agreed=None, fixed_pay_amount_agreed=None, fixed_price_upfront_payment=None, hourly_pay_rate=None, weekly_salary_charge_amount=None, weekly_salary_pay_amount=None, weekly_stipend_hours=None, weekly_hours_limit=None, start_date=None, keep_open=None): """Make an offer to the provider. *Parameters:* :job_reference: The Job's reference ID :provider_team_reference: (optional) The reference ID of the provider team. If specified, the check is performed whether user you're making offer to belongs to the team :provider_reference: (conditionally optional) The provider's reference. Has the override priority over ``profile_key`` if both specified. :profile_key: (conditionally optional) Unique profile key, used if ``provider_reference`` is absent :message_from_buyer: (optional) Text message :engagement_title: (optional) The engagement title :attached_doc: (optional) Attachment :fixed_charge_amount_agreed: (optional) The amount of agreed charge, required by fixed-price job :fixed_pay_amount_agreed: (optional) The amount of agreed pay :fixed_price_upfront_payment: (optional) The amount of upfront payment :hourly_pay_rate: (optional) Hourly pay rate :weekly_salary_charge_amount: (optional) Salary charge amount per week :weekly_salary_pay_amount: (optional) Salary pay amount per week, required by fixed-price job :weekly_stipend_hours: (optional) Stipend hours per week :weekly_hours_limit: (optional) Limit of hours per week :start_date: (optional) The offer start date :keep_open: (optional, default: 'no') Leave the job opened. Possible values are: 'yes', 'no' When just job and provider reference params are provided in the request then an invitation for an interview should be send to the according provider. Provider can either choose to accept the invitation and start the communication with the user or decline it, in which case communication between client and provider stops. When additionally engagement title and charge amount params are provided in the request, then an actual offer is created for the provider. In this case the provider can either accept the offer and start working or decline the offer. """ url = 'offers' data = {} data['job__reference'] = job_reference if provider_team_reference: data['provider_team__reference'] = provider_team_reference if profile_key is None and provider_reference is None: raise ApiValueError('Either one of the parameters ``profile_key`` ' 'or ``provider_reference`` should be provided') if provider_reference: data['provider__reference'] = provider_reference if profile_key: data['profile_key'] = profile_key if message_from_buyer: data['message_from_buyer'] = message_from_buyer if engagement_title: data['engagement_title'] = engagement_title if attached_doc: data['attached_doc'] = attached_doc if fixed_charge_amount_agreed: data['fixed_charge_amount_agreed'] = fixed_charge_amount_agreed if fixed_pay_amount_agreed: data['fixed_pay_amount_agreed'] = fixed_pay_amount_agreed if fixed_price_upfront_payment: data['fixed_price_upfront_payment'] = fixed_price_upfront_payment if hourly_pay_rate: data['hourly_pay_rate'] = hourly_pay_rate if weekly_salary_charge_amount: data['weekly_salary_charge_amount'] = weekly_salary_charge_amount if weekly_salary_pay_amount: data['weekly_salary_pay_amount'] = weekly_salary_pay_amount if weekly_stipend_hours: data['weekly_stipend_hours'] = weekly_stipend_hours if weekly_hours_limit: data['weekly_hours_limit'] = weekly_hours_limit if start_date: data['start_date'] = start_date if keep_open: assert_parameter('keep_open', keep_open, self.JOB_KEEP_OPEN_OPTIONS) data['keep_open'] = keep_open return self.post(url, data)
def post_job(self, buyer_team_reference, title, job_type, description, visibility, category=None, subcategory=None, budget=None, duration=None, start_date=None, skills=None, subcategory2=None): """ Post a job. *Parameters:* :buyer_team_reference: Reference ID of the buyer team that is posting the job, e.g. 34567 :title: Title of the Job :job_type: Type of posted job, e.g. "hourly" Possible values are: * 'hourly' * 'fixed-price' :description: The job's description :visibility: The job's visibility, e.g. 'private'. Possible values are: - 'public' jobs are available to all users who search jobs - 'private' job is visible to employer only - 'upwork' jobs appear in search results only for Upwork users who are logged into the service - 'invite-only' jobs do not appear in search and are used for jobs where the buyer wants to control the potential applicants :category: (conditionally optional) The category of job, e.g. 'Web Development' (where to get? - see Metadata API) :subcategory: (conditionally optional) The subcategory of job, e.g. 'Web Programming' (where to get? - see Metadata API) :budget: (conditionally optional) The budget of the Job, e.g. 100. Is used for 'fixed-price' jobs only. :duration: (conditionally optional) The duration of the job in hours, e.g. 90. Used for 'hourly-jobs' only. :start_date: (optional) The start date of the Job, e.g. 06-15-2011. If start_date is not included the job will default to starting immediately. :skills: (optional) Skills required for the job. Must be a list or tuple even of one item, e.g. ``['python']`` :subcategory2: (conditionally optional) The subcategory (V2) of job, e.g. 'Web & Mobile Programming' (where to get? - see Metadata API, List Categories (V2)) """ url = 'jobs' data = {} data['buyer_team__reference'] = buyer_team_reference data['title'] = title assert_parameter('job_type', job_type, self.JOB_TYPES) data['job_type'] = job_type data['description'] = description assert_parameter('visibility', visibility, self.JOB_VISIBILITY_OPTIONS) data['visibility'] = visibility if (category is None or subcategory is None) and subcategory2 is None: raise ApiValueError( 'Either one of the sub/category V1 or V2 parameters ' 'must be specified') if category: data['category'] = category if subcategory: data['subcategory'] = subcategory if subcategory2: data['subcategory2'] = subcategory2 if budget is None and duration is None: raise ApiValueError('Either one of the ``budget``or ``duration`` ' 'parameters must be specified') if budget: data['budget'] = budget if duration: data['duration'] = duration if start_date: data['start_date'] = start_date if skills: data['skills'] = ';'.join(skills) result = self.post(url, data) return result
def end_contract(self, contract_reference, reason, would_hire_again, fb_scores=None, fb_comment=None): """ Close the referenced contract. *Parameters:* :contract_reference: The Contract's reference ID :reason: The reason key, e.g. 'API_REAS_HIRED_DIFFERENT'. Possible values are: - 'API_REAS_MISREPRESENTED_SKILLS' - "Contractor misrepresented his/her skills" - 'API_REAS_CONTRACTOR_NOT_RESPONSIVE' - "Contractor not responsive" - 'API_REAS_HIRED_DIFFERENT' - "Hired a different contractor" - 'API_REAS_JOB_COMPLETED_SUCCESSFULLY' - "Job was completed successfully" - 'API_REAS_WORK_NOT_NEEDED' - "No longer need this work completed" - 'API_REAS_UNPROFESSIONAL_CONDUCT' - "Unprofessional conduct" :would_hire_again: Whether you would hire a contractor again. Required if total charge on the contract is $0. Possible values are: ['yes', 'no'] :fb_scores: (optional) Estimate, a dictionary of scores, where id is reference to score description (see example below). The feedback scores are optional, but if present they must be complete: all scores. Below are the possible score reference id values. Feedback on contractor: * ``3`` - "Skills / competency and skills for the job, understanding of specifications/instructions" * ``4`` - "Quality / quality of work deliveries" * ``5`` - "Availability / online presence on a consistent schedule" * ``6`` - "Deadlines / ability to complete tasks on time" * ``7`` - "Communication / communication skills, frequent progress updates, responsiveness" * ``8`` - "Cooperation / cooperation and flexibility, suggestions for improvement" Feedback on employer: * ``9`` - "Skills / competency and skills for the job, understanding of task complexities" * ``10`` - "Quality / quality of specifications/instructions" * ``11`` - "Availability / online presence on a consistent schedule" * ``12`` - "Deadlines / understanding of complexities and trade-offs" * ``13`` - "Communication / communication skills and responsiveness, feedback and guidance" * ``14`` - "Cooperation / cooperation and flexibility, open to suggestions for improvement" Example: {'fb_scores[3]': 5, 'fb_scores[4]': 4, ... , 'fb_scores[8]': 5} :fb_comment: (optional) Feedback comment, some string message. It is optional but if present, then the ``fb_scores`` parameter is also required. """ url = "contracts/{0}".format(contract_reference) data = {} assert_parameter("reason", reason, self.CONTRACT_REASON_OPTIONS) data["reason"] = reason assert_parameter("would_hire_again", would_hire_again, self.CONTRACT_WOULD_HIRE_AGAIN_OPTONS) data["would_hire_again"] = would_hire_again if fb_scores: for key, value in fb_scores.items(): data[key] = value if fb_comment: data["fb_comment"] = fb_comment result = self.delete(url, data) return result
def post_offer( self, job_reference, provider_team_reference=None, provider_reference=None, profile_key=None, message_from_buyer=None, engagement_title=None, attached_doc=None, fixed_charge_amount_agreed=None, fixed_pay_amount_agreed=None, fixed_price_upfront_payment=None, hourly_pay_rate=None, weekly_salary_charge_amount=None, weekly_salary_pay_amount=None, weekly_stipend_hours=None, weekly_hours_limit=None, start_date=None, keep_open=None, ): """Make an offer to the provider. *Parameters:* :job_reference: The Job's reference ID :provider_team_reference: (optional) The reference ID of the provider team. If specified, the check is performed whether user you're making offer to belongs to the team :provider_reference: (conditionally optional) The provider's reference. Has the override priority over ``profile_key`` if both specified. :profile_key: (conditionally optional) Unique profile key, used if ``provider_reference`` is absent :message_from_buyer: (optional) Text message :engagement_title: (optional) The engagement title :attached_doc: (optional) Attachment :fixed_charge_amount_agreed: (optional) The amount of agreed charge, required by fixed-price job :fixed_pay_amount_agreed: (optional) The amount of agreed pay :fixed_price_upfront_payment: (optional) The amount of upfront payment :hourly_pay_rate: (optional) Hourly pay rate :weekly_salary_charge_amount: (optional) Salary charge amount per week :weekly_salary_pay_amount: (optional) Salary pay amount per week, required by fixed-price job :weekly_stipend_hours: (optional) Stipend hours per week :weekly_hours_limit: (optional) Limit of hours per week :start_date: (optional) The offer start date :keep_open: (optional, default: 'no') Leave the job opened. Possible values are: 'yes', 'no' When just job and provider reference params are provided in the request then an invitation for an interview should be send to the according provider. Provider can either choose to accept the invitation and start the communication with the user or decline it, in which case communication between client and provider stops. When additionally engagement title and charge amount params are provided in the request, then an actual offer is created for the provider. In this case the provider can either accept the offer and start working or decline the offer. """ url = "offers" data = {} data["job__reference"] = job_reference if provider_team_reference: data["provider_team__reference"] = provider_team_reference if profile_key is None and provider_reference is None: raise ApiValueError( "Either one of the parameters ``profile_key`` " "or ``provider_reference`` should be provided" ) if provider_reference: data["provider__reference"] = provider_reference if profile_key: data["profile_key"] = profile_key if message_from_buyer: data["message_from_buyer"] = message_from_buyer if engagement_title: data["engagement_title"] = engagement_title if attached_doc: data["attached_doc"] = attached_doc if fixed_charge_amount_agreed: data["fixed_charge_amount_agreed"] = fixed_charge_amount_agreed if fixed_pay_amount_agreed: data["fixed_pay_amount_agreed"] = fixed_pay_amount_agreed if fixed_price_upfront_payment: data["fixed_price_upfront_payment"] = fixed_price_upfront_payment if hourly_pay_rate: data["hourly_pay_rate"] = hourly_pay_rate if weekly_salary_charge_amount: data["weekly_salary_charge_amount"] = weekly_salary_charge_amount if weekly_salary_pay_amount: data["weekly_salary_pay_amount"] = weekly_salary_pay_amount if weekly_stipend_hours: data["weekly_stipend_hours"] = weekly_stipend_hours if weekly_hours_limit: data["weekly_hours_limit"] = weekly_hours_limit if start_date: data["start_date"] = start_date if keep_open: assert_parameter("keep_open", keep_open, self.JOB_KEEP_OPEN_OPTIONS) data["keep_open"] = keep_open return self.post(url, data)
def update_job( self, job_id, buyer_team_reference, title, description, visibility, budget=None, duration=None, start_date=None, status=None, category2=None, subcategory2=None, ): """ Update a job. *Parameters:* :job_id: Job reference ID :buyer_team_reference: Reference ID of the buyer team that is posting the job, e.g. 34567 :title: Title of the Job :description: The job's description :visibility: The job's visibility, e.g. 'private'. Possible values are: - 'public' jobs are available to all users who search jobs - 'private' job is visible to employer only - 'upwork' jobs appear in search results only for Upwork users who are logged into the service - 'invite-only' jobs do not appear in search and are used for jobs where the buyer wants to control the potential applicants :budget: (conditionally optional) The budget of the Job, e.g. 100. Is used for 'fixed-price' jobs only. :duration: (conditionally optional) The duration of the job in hours, e.g. 90. Used for 'hourly-jobs' only. :start_date: (optional) The start date of the Job, e.g. 06-15-2011. If start_date is not included the job will default to starting immediately. :status: (required) The status of the job, e.g. 'filled'. Possible values are: - 'open' - 'filled' - 'cancelled' :category2: (conditionally optional) The category (V2) of job, e.g. 'Development' (where to get? - see Metadata API, List Categories (V2)) :subcategory2: (conditionally optional) The subcategory (V2) of job, e.g. 'Web & Mobile Programming' (where to get? - see Metadata API, List Categories (V2)) """ url = "jobs/{0}".format(job_id) data = {} data["buyer_team__reference"] = buyer_team_reference data["title"] = title data["description"] = description assert_parameter("visibility", visibility, self.JOB_VISIBILITY_OPTIONS) data["visibility"] = visibility data["category2"] = category2 data["subcategory2"] = subcategory2 if budget is None and duration is None: raise ApiValueError("Either one of the ``budget``or ``duration`` " "parameters must be specified") if budget: data["budget"] = budget if duration: data["duration"] = duration if start_date: data["start_date"] = start_date if status: assert_parameter("status", status, self.JOB_STATUSES) data["status"] = status else: raise ApiValueError('Missing required parameter "status"') return self.put(url, data)
def post_job( self, buyer_team_reference, title, job_type, description, visibility, budget=None, duration=None, start_date=None, skills=None, category2=None, subcategory2=None, ): """ Post a job. *Parameters:* :buyer_team_reference: Reference ID of the buyer team that is posting the job, e.g. 34567 :title: Title of the Job :job_type: Type of posted job, e.g. "hourly" Possible values are: * 'hourly' * 'fixed-price' :description: The job's description :visibility: The job's visibility, e.g. 'private'. Possible values are: - 'public' jobs are available to all users who search jobs - 'private' job is visible to employer only - 'upwork' jobs appear in search results only for Upwork users who are logged into the service - 'invite-only' jobs do not appear in search and are used for jobs where the buyer wants to control the potential applicants :budget: (conditionally optional) The budget of the Job, e.g. 100. Is used for 'fixed-price' jobs only. :duration: (conditionally optional) The duration of the job in hours, e.g. 90. Used for 'hourly-jobs' only. :start_date: (optional) The start date of the Job, e.g. 06-15-2011. If start_date is not included the job will default to starting immediately. :skills: (optional) Skills required for the job. Must be a list or tuple even of one item, e.g. ``['python']`` :category2: (conditionally optional) The category (V2) of job, e.g. 'Development' (where to get? - see Metadata API, List Categories (V2)) :subcategory2: (conditionally optional) The subcategory (V2) of job, e.g. 'Web & Mobile Programming' (where to get? - see Metadata API, List Categories (V2)) """ url = "jobs" data = {} data["buyer_team__reference"] = buyer_team_reference data["title"] = title assert_parameter("job_type", job_type, self.JOB_TYPES) data["job_type"] = job_type data["description"] = description assert_parameter("visibility", visibility, self.JOB_VISIBILITY_OPTIONS) data["visibility"] = visibility if category2 is None or subcategory2 is None: raise ApiValueError("sub/category2 parameters must be specified") if category2: data["category2"] = category2 if subcategory2: data["subcategory2"] = subcategory2 if budget is None and duration is None: raise ApiValueError("Either one of the ``budget``or ``duration`` " "parameters must be specified") if budget: data["budget"] = budget if duration: data["duration"] = duration if start_date: data["start_date"] = start_date if skills: data["skills"] = ";".join(skills) result = self.post(url, data) return result