from otree.api import * from constants import * from utils import display_to_actual_round import random doc = """Post-Experiment Questionnaire and Payment Calculation""" class C(BaseConstants): NAME_IN_URL = 'I_Post_Questionnaire_D' PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 ShowupFee = 3.00 class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): Ana_generation = models.IntegerField() Ana_own_id = models.IntegerField() Ana_family_assignment = models.StringField() Ana_PQ_uyr = models.IntegerField( label="What year in university are you?", choices=[(1, 'Year 1'), (2, 'Year 2'), (3, 'Year 3'), (4, 'Year 4'), (5, 'Year 5'), (6, 'Postgraduate')], widget=widgets.RadioSelectHorizontal) Ana_PQ_gd = models.IntegerField( label="What is your gender?", choices=[(1, 'Female'), (2, 'Male'), (3, 'Nonbinary'), (4, 'Prefer not to say'), (5, 'Other')], widget=widgets.RadioSelectHorizontal) Ana_PQ_race = models.IntegerField( label="What is your race/ethnicity?", choices=[(1, 'Chinese'), (2, 'Malay'), (3, 'Indian'), (4, 'Prefer not to say'), (5, 'Other')], widget=widgets.RadioSelectHorizontal) Ana_PQ_course = models.StringField(label="What is your course of study?") Ana_PQ_hp_token = models.IntegerField( label="If you were to play the Token Grabbing Task, how many of the 10 available tokens would you grab?", blank=False, min=0, max=10) Ana_PQ_hp_coin = models.IntegerField( label="If you were to play the Coin Flipping Task, how many times out of 10 do you think you would get heads?", blank=False, min=0, max=10) Ana_PQ_ust = models.IntegerField( label="Please indicate your level of understanding of the instructions.", choices=[(1, 'Do not understand at all'), (2, ''), (3, ''), (4, ''), (5, 'Completely understand')], widget=widgets.RadioSelect) Ana_PQ_stdpps = models.LongStringField(label="What do you think this experiment was about?") Ana_PQ_wor_coinmst = models.IntegerField( choices=[(1, 'Very Wrong'), (2, ''), (3, ''), (4, ''), (5, 'Very Right')], widget=widgets.RadioSelect) Ana_PQ_wor_coinlst = models.IntegerField( choices=[(1, 'Very Wrong'), (2, ''), (3, ''), (4, ''), (5, 'Very Right')], widget=widgets.RadioSelect) Ana_PQ_wor_tkmst = models.IntegerField( choices=[(1, 'Very Wrong'), (2, ''), (3, ''), (4, ''), (5, 'Very Right')], widget=widgets.RadioSelect) Ana_PQ_wor_tklst = models.IntegerField( choices=[(1, 'Very Wrong'), (2, ''), (3, ''), (4, ''), (5, 'Very Right')], widget=widgets.RadioSelect) Ana_PQ_dsv_coinmst = models.IntegerField( choices=[(1, 'Not deserving at all'), (2, ''), (3, ''), (4, ''), (5, 'Very deserving')], widget=widgets.RadioSelect) Ana_PQ_dsv_coinlst = models.IntegerField( choices=[(1, 'Not deserving at all'), (2, ''), (3, ''), (4, ''), (5, 'Very deserving')], widget=widgets.RadioSelect) Ana_PQ_dsv_tkmst = models.IntegerField( choices=[(1, 'Not deserving at all'), (2, ''), (3, ''), (4, ''), (5, 'Very deserving')], widget=widgets.RadioSelect) Ana_PQ_dsv_tklst = models.IntegerField( choices=[(1, 'Not deserving at all'), (2, ''), (3, ''), (4, ''), (5, 'Very deserving')], widget=widgets.RadioSelect) Ana_PQ_stf_edmt = models.LongStringField( label="Overall, how satisfied were you with the endowment assigned to you and your group members? Why?") Ana_PQ_stf_tmop = models.LongStringField( label="Overall, how satisfied were you with your team outcome for the decision task? Why?") Ana_PQ_sttmt1 = models.IntegerField( choices=[(1, 'Strongly Disagree'), (2, ''), (3, ''), (4, ''), (5, 'Strongly Agree')], widget=widgets.RadioSelect) Ana_PQ_sttmt2 = models.IntegerField( choices=[(1, 'Strongly Disagree'), (2, ''), (3, ''), (4, ''), (5, 'Strongly Agree')], widget=widgets.RadioSelect) Ana_PQ_sttmt3 = models.IntegerField( choices=[(1, 'Strongly Disagree'), (2, ''), (3, ''), (4, ''), (5, 'Strongly Agree')], widget=widgets.RadioSelect) Ana_PQ_sttmt4 = models.IntegerField( choices=[(1, 'Strongly Disagree'), (2, ''), (3, ''), (4, ''), (5, 'Strongly Agree')], widget=widgets.RadioSelect) Ana_PQ_disadv1 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv2 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv3 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv4 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv5 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv6 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv7 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv8 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv9 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_disadv10 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv1 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv2 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv3 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv4 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv5 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv6 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv7 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv8 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv9 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_adv10 = models.IntegerField(choices=[(1, 'Not at all'), (2, ''), (3, ''), (4, ''), (5, 'Exactly')], widget=widgets.RadioSelect) Ana_PQ_unclear_yn = models.BooleanField( label="Was there anything unclear or confusing to you in the study?", choices=[[False, 'No'] , [True, 'Yes']], widget=widgets.RadioSelect) Ana_PQ_unclear = models.LongStringField(label="Please elaborate", blank=True) Ana_PQ_issue_yn = models.BooleanField( label="Did you encounter any technical problems or issues during the study?", choices=[[False, 'No'], [True, 'Yes']], widget=widgets.RadioSelect) Ana_PQ_issue = models.LongStringField(label="Please elaborate", blank=True) selected_round_1 = models.IntegerField() selected_round_2 = models.IntegerField() selected_round_3 = models.IntegerField() selected_round_4 = models.IntegerField() pmt_FirstTask = models.FloatField() pmt_PGG = models.FloatField() pmt_JointTask1 = models.FloatField() pmt_JointTask2 = models.FloatField() final_payment = models.FloatField() pmt_Demo = models.FloatField() class ClosedExit(Page): @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') == "closed") class PQ0_G1(Page): @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ1_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_uyr', 'Ana_PQ_gd', 'Ana_PQ_race', 'Ana_PQ_course'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ3_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_ust', 'Ana_PQ_stdpps'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ4_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_wor_coinmst', 'Ana_PQ_wor_coinlst', 'Ana_PQ_wor_tkmst', 'Ana_PQ_wor_tklst'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ5_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_dsv_coinmst', 'Ana_PQ_dsv_coinlst', 'Ana_PQ_dsv_tkmst', 'Ana_PQ_dsv_tklst'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ6_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_stf_edmt', 'Ana_PQ_stf_tmop'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ7_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_sttmt1', 'Ana_PQ_sttmt2', 'Ana_PQ_sttmt3', 'Ana_PQ_sttmt4'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ8_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_disadv1', 'Ana_PQ_disadv2', 'Ana_PQ_disadv3', 'Ana_PQ_disadv4', 'Ana_PQ_disadv5'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ9_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_disadv6', 'Ana_PQ_disadv7', 'Ana_PQ_disadv8', 'Ana_PQ_disadv9', 'Ana_PQ_disadv10'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ10_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_adv1', 'Ana_PQ_adv2', 'Ana_PQ_adv3', 'Ana_PQ_adv4', 'Ana_PQ_adv5'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) class PQ11_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_adv6', 'Ana_PQ_adv7', 'Ana_PQ_adv8', 'Ana_PQ_adv9', 'Ana_PQ_adv10'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) @staticmethod def before_next_page(player: Player, timeout_happened=False): if 'selected_rounds' not in player.participant.vars: selected_rounds = sorted(random.sample(range(1, 17), 4)) player.participant.vars['selected_rounds'] = selected_rounds else: selected_rounds = player.participant.vars['selected_rounds'] player.selected_round_1 = selected_rounds[0] player.selected_round_2 = selected_rounds[1] player.selected_round_3 = selected_rounds[2] player.selected_round_4 = selected_rounds[3] pgg_payoffs = player.participant.vars.get('pgg_payoffs_by_display_round', {}) pmt_PGG = sum(pgg_payoffs.get(r, 0) for r in selected_rounds) player.pmt_PGG = pmt_PGG pmt_FirstTask = 0 if player.participant.vars.get('Ana_generation') == 1: selected_first_task = random.choice(['token', 'coin']) player.participant.vars['selected_first_task'] = selected_first_task if selected_first_task == 'token': pmt_FirstTask = player.participant.vars.get('N_TokenTake', 0) else: pmt_FirstTask = player.participant.vars.get('N_CoinFlip', 0) player.pmt_FirstTask = pmt_FirstTask pmt_JointTask1 = player.participant.vars.get('joint_task_r1to3_score', 0) player.pmt_JointTask1 = pmt_JointTask1 player.pmt_JointTask2 = 0 if player.participant.vars.get('Ana_generation') == 1: player.final_payment = ConvertRate * ( player.participant.vars.get('DemoRound_Payoff', 0) + pmt_FirstTask + pmt_PGG + pmt_JointTask1) + C.ShowupFee else: player.final_payment = ConvertRate * ( player.participant.vars.get('DemoRound_Payoff', 0) + pmt_PGG + pmt_JointTask1) + C.ShowupFee player.participant.payoff = player.final_payment class PQ12_G1(Page): form_model = 'player' form_fields = ['Ana_PQ_unclear_yn', 'Ana_PQ_unclear', 'Ana_PQ_issue_yn', 'Ana_PQ_issue'] @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) @staticmethod def error_message(player, values): if values['Ana_PQ_unclear_yn'] and not values['Ana_PQ_unclear']: return 'Please elaborate on what was unclear.' if values['Ana_PQ_issue_yn'] and not values['Ana_PQ_issue']: return 'Please elaborate on the technical issue.' class Pmt(Page): @staticmethod def is_displayed(player): return (player.round_number == 1 and player.participant.vars.get('state') not in ("inactive", "closed")) @staticmethod def vars_for_template(player: Player): return { 'Ana_generation': player.participant.vars.get('Ana_generation'), 'DemoRound_Payoff': f"{player.participant.vars.get('DemoRound_Payoff', 0):.2f}", 'pmt_FirstTask': f"{player.pmt_FirstTask:.2f}", 'pmt_PGG': f"{player.pmt_PGG:.2f}", 'pmt_JointTask1': f"{player.pmt_JointTask1:.2f}", 'total_payoff': f"{player.final_payment:.2f}", 'ShowupFee': f"{C.ShowupFee:.2f}", } page_sequence = [ ClosedExit, PQ0_G1, PQ1_G1, PQ12_G1, PQ3_G1, PQ6_G1, PQ4_G1, PQ5_G1, PQ7_G1, PQ8_G1, PQ9_G1, PQ10_G1, PQ11_G1, Pmt, ]