import random import numpy as np from otree.api import * doc = """ JMP """ class C(BaseConstants): NAME_IN_URL = 'study' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 8 TEMPLATE_REPORT = 'trust/profit_report.html' TEMPLATE_RECAP = 'trust/recap_template.html' TEMPLATE_WAIT_PAGE = 'trust/wait_page_template.html' TEMPLATE_MTURK_WAIT_PAGE = 'trust/mturk_wait_page_template.html' TEMPLATE_MTURK_WAIT_PAGE = 'trust/mturk_wait_page_template.html' TEMPLATE_INSTRUCTIONS = 'attention/instructions_template.html' # time allowed per page MAX_PER_PAGE = 120 PROBABILITY_MIN = 2 PROBABILITY_INCREMENT = 1 PROBABILITY_MAX = 7 PROBABILITY_TOTAL = 10 PROBABILITY_DIF = PROBABILITY_MAX - PROBABILITY_MIN SUPERVISOR_ENDOWMENT = cu(400) EMPLOYEE_ENDOWMENT = cu(360) FIXED_PAYMENT_IN_POINTS = cu(250) # this is hardcoded please remember to change BONUS_MAX = cu(200) COST_PER_ROCK = 20 SUPERVISOR_BONUS_LOW = cu(70) SUPERVISOR_BONUS_HIGH = cu(190) COST_MAX_EMPLOYEE = PROBABILITY_DIF * COST_PER_ROCK PROFIT_LOW = "Low" PROFIT_HIGH = "High" class Subsession(BaseSubsession): pass def creating_session(subsession): for p in subsession.get_players(): p.participant.vars["display_none"]=True p.participant.vars["selected_effort"]= False p.participant.vars["selected_profit"] = False if 'g_self' in subsession.session.config: p.participant.vars['self_select_treatment'] = subsession.session.config['g_self']==1 else: p.participant.vars['self_select_treatment'] = False class Group(BaseGroup): effort = models.IntegerField( choices=np.arange( 0, C.PROBABILITY_DIF + 1, C.PROBABILITY_INCREMENT ).tolist(), widget=widgets.RadioSelectHorizontal, ) bonus = models.CurrencyField(min=0, max=C.BONUS_MAX) supervisor_bonus = models.CurrencyField() payoff_supervisor = models.CurrencyField() payoff_employee = models.CurrencyField() profit = models.StringField( choices=["Low", "High"], ) treatment_info = models.IntegerField() random_draw = models.IntegerField() random_period = models.IntegerField() selected_guideline = models.IntegerField( label="Please select which guideline, if any, you want to appear in the performance report for both you and the employee to see.", choices=[ [1, 'Show a guideline: Supervisors will use the bonus decision to reward employees only based on how many winning balls they buy.'], [2, 'Show a guideline: Supervisors will use the bonus decision to reward employees only based on the profit level they generate.'], [0, 'Do not show any guideline.'] ], widget=widgets.RadioSelectHorizontal, ) willDisplayGuideline = models.BooleanField() chose_no_guideline = models.BooleanField() chose_effort_guideline = models.BooleanField() chose_profit_guideline = models.BooleanField() display_effort_guideline = models.BooleanField() display_profit_guideline = models.BooleanField() self_select_treatment = models.BooleanField() class Player(BasePlayer): collegue_left = models.BooleanField() participant_left = models.BooleanField() waited_for_group = models.BooleanField() kicked_out_period = models.IntegerField() # FUNCTIONS def profit_random(group: Group): group.random_draw = random.randrange(1, C.PROBABILITY_TOTAL + 1) return group.random_draw <= C.PROBABILITY_MIN + group.effort def group_by_arrival_time_method(subsession, waiting_players): players = [p for p in waiting_players] if len(players) >= 2: if random.choice([0, 1]): return [players[0], players[1]] else: return [players[1], players[0]] def role(player: Player): return {1: 'Supervisor', 2: 'Employee'}[player.id_in_group] # PAGES def after_timeout(player: Player,timeout_happened): if timeout_happened: player.participant_left = True player.participant.vars["participant_left"] = True # add period other = player.get_others_in_group()[0] other.collegue_left = True other.participant.vars["collegue_left"] = True def kick_after_page(player: Player): if 'participant_left' in player.participant.vars or 'collegue_left' in player.participant.vars: player.participant.vars["kicked_out_period"] = player.subsession.round_number player.kicked_out_period = player.subsession.round_number return "kicked_out" class mtrurk_wait_page(WaitPage): template_name = C.TEMPLATE_MTURK_WAIT_PAGE group_by_arrival_time = True @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def vars_for_template(player: Player): player.waited_for_group = True return dict( is_wrong_role=False, waiting_for_effort=False, waiting_for_bonus=False, waiting_for_confrontation=False, ) class mtrurk_wait_page2(WaitPage): template_name = C.TEMPLATE_MTURK_WAIT_PAGE @staticmethod def is_displayed(player: Player): return player.round_number == 1 @staticmethod def vars_for_template(player: Player): player.waited_for_group = True return dict( is_wrong_role=False, waiting_for_effort=False, waiting_for_bonus=False, waiting_for_confrontation=False, ) class supervisorEffortWaitPage(WaitPage): template_name = C.TEMPLATE_WAIT_PAGE title_text = "Please wait for the employee to decide how many winning balls to buy. " body_text = "" @staticmethod def vars_for_template(player: Player): if player.id_in_group == 2: is_employee = True bold = False else: is_employee = False bold = True return dict( is_wrong_role=is_employee, waiting_for_effort=bold, waiting_for_bonus=False, waiting_for_confrontation=False, ) @staticmethod def app_after_this_page(player: Player, upcoming_apps): return kick_after_page(player) class employeeBonusWaitPage(WaitPage): template_name = C.TEMPLATE_WAIT_PAGE title_text = "Please wait for the supervisor to decide how much bonus to award to you. " body_text = "" @staticmethod def vars_for_template(player: Player): if player.id_in_group == 1: is_supervisor = True bold = False else: is_supervisor = False bold = True return dict( is_wrong_role=is_supervisor, waiting_for_effort=False, waiting_for_bonus=bold, waiting_for_confrontation=False, ) @staticmethod def app_after_this_page(player: Player, upcoming_apps): return kick_after_page(player) # class supervisorConfrontationWaitPage(WaitPage): # template_name = C.TEMPLATE_WAIT_PAGE # title_text = "Please wait for the employee to decide if they will confront you. " # body_text = "" # @staticmethod # def vars_for_template(player: Player): # return dict( # is_wrong_role=False, # waiting_for_effort=False, # waiting_for_bonus=False, # waiting_for_confrontation=True, # ) # @staticmethod # def app_after_this_page(player: Player, upcoming_apps): # return kick_after_page(player) class Intro(Page): timeout_seconds = C.MAX_PER_PAGE @staticmethod def is_displayed(player: Player): return player.subsession.round_number == 1 @staticmethod def vars_for_template(player: Player): player.waited_for_group = False if player.id_in_group == 1: player.participant.vars['role'] = "Supervisor" if player.id_in_group == 2: player.participant.vars['role'] = "Employee" return dict( is_wrong_role=False, waiting_for_effort=False, waiting_for_bonus=False, waiting_for_confrontation=False, ) @staticmethod def before_next_page(player: Player, timeout_happened): after_timeout(player,timeout_happened) class rocks(Page): timeout_seconds = C.MAX_PER_PAGE form_model = 'group' form_fields = ['effort'] @staticmethod def vars_for_template(player: Player): p1 = player.group.get_player_by_id(1) treatment_info = p1.participant.vars['treatment_info'] player.group.treatment_info = treatment_info return dict( effort_label="Please select an amount between 0 to {}:".format( C.PROBABILITY_DIF ) ) @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 @staticmethod def before_next_page(player: Player, timeout_happened): after_timeout(player,timeout_happened) if profit_random(player.group): player.group.profit = "High" player.group.supervisor_bonus = C.SUPERVISOR_BONUS_HIGH else: player.group.profit = "Low" player.group.supervisor_bonus = C.SUPERVISOR_BONUS_LOW class employee_profit_report(Page): timeout_seconds = C.MAX_PER_PAGE @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 @staticmethod def vars_for_template(player: Player): return dict( treatment_info=player.group.treatment_info, profit=player.group.profit, effort=player.group.effort, ) @staticmethod def before_next_page(player: Player, timeout_happened): after_timeout(player,timeout_happened) class bonus(Page): timeout_seconds = C.MAX_PER_PAGE form_model = 'group' form_fields = ['bonus'] @staticmethod def is_displayed(player: Player): return player.id_in_group == 1 @staticmethod def vars_for_template(player: Player): player.group.payoff_supervisor = ( player.group.supervisor_bonus + C.SUPERVISOR_ENDOWMENT ) return dict( treatment_info=player.group.treatment_info, profit=player.group.profit, effort=player.group.effort, chose_but_not_displayed= player.participant.vars["chosen_guideline"]!=0 and player.participant.vars["random_display"]==0 ) @staticmethod def before_next_page(player: Player, timeout_happened): if player.subsession.round_number == C.NUM_ROUNDS: payoff_period = random.randrange(1, C.NUM_ROUNDS + 1, 1) player.group.random_period = payoff_period after_timeout(player,timeout_happened) class employee_bonus_report(Page): timeout_seconds = C.MAX_PER_PAGE @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 @staticmethod def vars_for_template(player: Player): player.group.payoff_employee = ( C.EMPLOYEE_ENDOWMENT + player.group.bonus - player.group.effort * C.COST_PER_ROCK ) return dict( cost_effort=player.group.effort * C.COST_PER_ROCK, ) @staticmethod def before_next_page(player: Player, timeout_happened): if player.subsession.round_number == C.NUM_ROUNDS: player.participant.payoff = player.group.in_round( player.group.random_period ).payoff_employee after_timeout(player,timeout_happened) class supervisor_payoff_report(Page): @staticmethod def get_timeout_seconds(player: Player): if player.subsession.round_number != C.NUM_ROUNDS: return C.MAX_PER_PAGE @staticmethod def is_displayed(player: Player): return player.id_in_group == 1 @staticmethod def vars_for_template(player: Player): current_period = player.subsession.round_number list_periods = [] if current_period == C.NUM_ROUNDS: player.participant.payoff = player.group.in_round( player.group.random_period ).payoff_supervisor list_periods = list(player.group.in_all_rounds()) else: list_periods.append(player.group.in_round(current_period)) return dict( treatment_info=player.group.treatment_info, next_round=player.subsession.round_number + 1, group_periods=list_periods, ) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.payoff = player.participant.payoff - C.FIXED_PAYMENT_IN_POINTS if player.subsession.round_number != C.NUM_ROUNDS: after_timeout(player,timeout_happened) class employee_payoff_report(Page): @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 and player.subsession.round_number == C.NUM_ROUNDS @staticmethod def vars_for_template(player: Player): list_periods = [] list_periods = list(player.group.in_all_rounds()) return dict( treatment_info=player.group.treatment_info, next_round=player.subsession.round_number + 1, group_periods=list_periods, ) @staticmethod def before_next_page(player: Player, timeout_happened): player.participant.payoff = player.participant.payoff - C.FIXED_PAYMENT_IN_POINTS class SupervisorGuideline(Page): @staticmethod def is_displayed(player: Player): return player.id_in_group == 1 and player.subsession.round_number==1 and player.participant.vars['self_select_treatment'] form_model = 'group' form_fields=['selected_guideline'] def before_next_page(player: Player, timeout_happened): player.participant.vars["chosen_guideline"] = player.group.selected_guideline player.get_others_in_group()[0].participant.vars["chosen_guideline"] = player.group.selected_guideline player.group.willDisplayGuideline = random.choice([0, 1]) player.participant.vars["random_display"] = player.group.willDisplayGuideline player.get_others_in_group()[0].participant.vars["random_display"] = player.group.willDisplayGuideline if(player.group.willDisplayGuideline==1 and player.group.selected_guideline==1): player.participant.vars["selected_effort"] = True player.participant.vars["selected_profit"] = False player.participant.vars["display_none"] = False player.get_others_in_group()[0].participant.vars["selected_effort"] = True player.get_others_in_group()[0].participant.vars["selected_profit"] = False player.get_others_in_group()[0].participant.vars["display_none"] = False if(player.group.willDisplayGuideline==1 and player.group.selected_guideline==2): player.participant.vars["selected_profit"] = True player.participant.vars["selected_effort"] = False player.participant.vars["display_none"] = False player.get_others_in_group()[0].participant.vars["selected_profit"] = True player.get_others_in_group()[0].participant.vars["selected_effort"] = False player.get_others_in_group()[0].participant.vars["display_none"] = False if(player.group.willDisplayGuideline==0 or player.group.selected_guideline==0): player.participant.vars["display_none"] = True player.participant.vars["selected_effort"] = False player.participant.vars["selected_profit"] = False player.get_others_in_group()[0].participant.vars["display_none"] = True player.get_others_in_group()[0].participant.vars["selected_effort"] = False player.get_others_in_group()[0].participant.vars["selected_profit"] = False player.group.willDisplayGuideline = player.participant.vars["random_display"] player.group.chose_no_guideline = player.participant.vars["chosen_guideline"]==0 player.group.chose_effort_guideline = player.participant.vars["chosen_guideline"]==1 player.group.chose_profit_guideline = player.participant.vars["chosen_guideline"]==2 player.group.display_effort_guideline = player.participant.vars["selected_effort"] player.group.display_profit_guideline = player.participant.vars["selected_profit"] player.group.self_select_treatment= player.participant.vars['self_select_treatment'] after_timeout(player,timeout_happened) class SupervisorGuidelineReport(Page): @staticmethod def is_displayed(player: Player): return player.id_in_group == 1 and player.subsession.round_number==1 and player.participant.vars['self_select_treatment'] @staticmethod def vars_for_template(player: Player): if player.participant.vars["random_display"]==1: displayOutcome="DISPLAY" displayNo="" if player.participant.vars["random_display"]==0: displayOutcome="DON'T DISPLAY" displayNo=" NOT" display_guideline=(player.participant.vars["chosen_guideline"]!=0) and (player.participant.vars["random_display"]==1) return dict( chose_no_guideline=(player.participant.vars["chosen_guideline"]==0), chose_guideline=(player.participant.vars["chosen_guideline"]!=0), chose_effort_guideline=(player.participant.vars["chosen_guideline"]==1), chose_profit_guideline=(player.participant.vars["chosen_guideline"]==2), display=displayOutcome, displayNo=displayNo, randomDisplay=player.participant.vars["random_display"], display_guideline=display_guideline ) class EmployeeGuidelineReport(Page): @staticmethod def is_displayed(player: Player): return player.id_in_group == 2 and player.subsession.round_number==1 and not player.participant.vars["display_none"] and player.participant.vars['self_select_treatment'] page_sequence = [ mtrurk_wait_page, SupervisorGuideline, mtrurk_wait_page2, SupervisorGuidelineReport, Intro, EmployeeGuidelineReport, rocks, supervisorEffortWaitPage, employee_profit_report, bonus, employeeBonusWaitPage, employee_bonus_report, supervisor_payoff_report, employee_payoff_report, ]