from otree.api import * c = cu doc = '' class C(BaseConstants): # built-in constants NAME_IN_URL = 'PainofPaying' PLAYERS_PER_GROUP = 2 NUM_ROUNDS = 1 # user-defined constants NUM_POP_QS = 22 PRICE_STEPS = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) SMILEY_LIKERT_OPTS = (1, 2, 3, 4, 5, 6, 7) AUCTION_INSTRUCTIONS_TEMPLATE = 'PainofPaying/auction_instructions.html' UW_TETON_BG_TEMPLATE = 'PainofPaying/uw_teton_bg.html' UW_TETON_SURVEY_TEMPLATE = 'PainofPaying/uw_teton_survey.html' TWO_COLUMN_FLEX_CONTAINER_TEMPLATE = 'PainofPaying/two_column_flex_container.html' class Subsession(BaseSubsession): pass def after_all_players_arrive(subsession: Subsession): session = subsession.session # pull the matrix you stored in the code‐entry app matrix = subsession.session.vars.get('couple_matrix') if not matrix: # safety check in case someone forgot to run grouping first raise RuntimeError("No couple_matrix in session.vars") # re‐apply it in this app's subsession subsession.set_group_matrix(matrix) class Group(BaseGroup): pass class Player(BasePlayer): pop_self_00 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$0 (Free)', widget=widgets.RadioSelectHorizontal) pop_self_02 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$2', widget=widgets.RadioSelectHorizontal) pop_self_04 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$4', widget=widgets.RadioSelectHorizontal) pop_self_06 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$6', widget=widgets.RadioSelectHorizontal) pop_self_08 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$8', widget=widgets.RadioSelectHorizontal) pop_self_10 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$10', widget=widgets.RadioSelectHorizontal) pop_self_12 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$12', widget=widgets.RadioSelectHorizontal) pop_self_16 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$16', widget=widgets.RadioSelectHorizontal) pop_self_20 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$20', widget=widgets.RadioSelectHorizontal) pop_partner_00 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$0 (Free)', widget=widgets.RadioSelectHorizontal) pop_partner_02 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$2', widget=widgets.RadioSelectHorizontal) pop_partner_04 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$4', widget=widgets.RadioSelectHorizontal) pop_partner_06 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$6', widget=widgets.RadioSelectHorizontal) pop_partner_08 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$8', widget=widgets.RadioSelectHorizontal) pop_partner_10 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$10', widget=widgets.RadioSelectHorizontal) pop_partner_12 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$12', widget=widgets.RadioSelectHorizontal) pop_partner_16 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$16', widget=widgets.RadioSelectHorizontal) pop_partner_20 = models.IntegerField(choices=C.SMILEY_LIKERT_OPTS, label='$20', widget=widgets.RadioSelectHorizontal) def custom_export(players): # Header yield [ 'session_code', 'participant_id_in_session', 'participant_code', 'id_in_group', 'group_number', 'spender', 'pop_self_00', 'pop_self_02', 'pop_self_04', 'pop_self_06', 'pop_self_08', 'pop_self_10', 'pop_self_12', 'pop_self_16', 'pop_self_20', 'pop_partner_00', 'pop_partner_02', 'pop_partner_04', 'pop_partner_06', 'pop_partner_08', 'pop_partner_10', 'pop_partner_12', 'pop_partner_16', 'pop_partner_20', ] # Rows for p in players: pp = p.participant pg = p.group ps = p.session # Pull participant fields spender = p.participant.vars.get('spender', '') yield [ ps.code, pp.id_in_session, pp.code, p.id_in_group, pg.id_in_subsession, spender, p.pop_self_00, p.pop_self_02, p.pop_self_04, p.pop_self_06, p.pop_self_08, p.pop_self_10, p.pop_self_12, p.pop_self_16, p.pop_self_20, p.pop_partner_00, p.pop_partner_02, p.pop_partner_04, p.pop_partner_06, p.pop_partner_08, p.pop_partner_10, p.pop_partner_12, p.pop_partner_16, p.pop_partner_20 ] class GroupingWaitPage(WaitPage): wait_for_all_groups = True after_all_players_arrive = after_all_players_arrive class PainOfPaying(Page): form_model = 'player' form_fields = ['pop_self_00', 'pop_self_02', 'pop_self_04', 'pop_self_06', 'pop_partner_00', 'pop_partner_02', 'pop_partner_04', 'pop_partner_06', 'pop_partner_08', 'pop_partner_10', 'pop_partner_12', 'pop_partner_16', 'pop_partner_20', 'pop_self_08', 'pop_self_10', 'pop_self_12', 'pop_self_16', 'pop_self_20'] # vars_for_template is deprecated in favor of python-based renderers @staticmethod def vars_for_template(player: Player): participant = player.participant # Define the list of items with unique identifiers, their associated image URLs, and a description imgur_urls = [ {'id': 'A', 'url': 'https://i.imgur.com/OfsrPbR.jpeg', 'description': "Coloring book with pencils"}, # Image and description for item A {'id': 'B', 'url': 'https://i.imgur.com/tmBYFwX.jpeg', 'description': "Headphones"}, # Image and description for item B {'id': 'C', 'url': 'https://i.imgur.com/oBfC4Mz.jpeg', 'description': "Moisturizer"}, # Image and description for item C {'id': 'D', 'url': 'https://i.imgur.com/q7bBuv6.jpeg', 'description': "Spa kit"}, # Image and description for item D {'id': 'E', 'url': 'https://i.imgur.com/Zc7vR6m.jpeg', 'description': "Grilling accessories"}, # Image and description for item E {'id': 'F', 'url': 'https://i.imgur.com/YLEoKGI.jpeg', 'description': "Tactical flashlight"}, # Image and description for item F {'id': 'G', 'url': 'https://i.imgur.com/lmMFuFL.jpeg', 'description': "Lip Balm"}, # Image and description for item G {'id': 'H', 'url': 'https://i.imgur.com/5KfUIfj.jpeg', 'description': "Water bottle"}, # Image and description for item H {'id': 'I', 'url': 'https://i.imgur.com/AS1feBP.jpeg', 'description': "Car detailing kit"}, # Image and description for item I {'id': 'J', 'url': 'https://i.imgur.com/SfJ7GmF.jpeg', 'description': "Multi-tool"} # Image and description for item J ] # Fallback defaults for missing items default_image = 'https://miro.medium.com/v2/resize:fit:1100/format:webp/1*MXyMqcEJ6Se0SCWcYCKZTQ.jpeg' default_desc = 'No description available.' # Get the selected item code from participant selected_item = participant.spender_selected_item # Look up the selected entry or fall back to defaults selected = next( (item for item in imgur_urls if item['id'] == selected_item), {'url': default_image, 'description': default_desc} ) # Pass data to template return dict( price_steps=C.PRICE_STEPS, img_url='https://imgur.com/N7q1Rts.png', image_paths=imgur_urls, image_path=selected['url'], description=selected['description'], ) class POPEndPage(WaitPage): wait_for_all_groups = True title_text = 'Please wait for further instructions.' page_sequence = [GroupingWaitPage, PainOfPaying, POPEndPage]