from otree.api import * doc = """ Final allocation decision across all organizations viewed in the evaluation app. """ class C(BaseConstants): NAME_IN_URL = "donation_allocation" PLAYERS_PER_GROUP = None NUM_ROUNDS = 1 BONUS_ENDOWMENT = cu(3) class Subsession(BaseSubsession): pass class Group(BaseGroup): pass class Player(BasePlayer): donation_org_1 = models.CurrencyField(min=0, initial=0) donation_org_2 = models.CurrencyField(min=0, initial=0) donation_org_3 = models.CurrencyField(min=0, initial=0) donation_org_4 = models.CurrencyField(min=0, initial=0) total_donated = models.CurrencyField(initial=0) amount_kept = models.CurrencyField(initial=0) score_org_1 = models.IntegerField(initial=0) score_org_2 = models.IntegerField(initial=0) score_org_3 = models.IntegerField(initial=0) score_org_4 = models.IntegerField(initial=0) def get_allocation_orgs(participant): sequence = participant.vars.get("org_sequence", []) initiative_sequence = participant.vars.get("initiative_sequence", []) condition = participant.vars.get("condition", "Human") org_scores = participant.vars.get("org_scores", {}) org_hashtags = participant.vars.get("org_hashtags", {}) return [ dict( slot=index + 1, field_name=f"donation_org_{index + 1}", org_id=org["org_id"], name=org["name"], condition=condition, condition_class=condition.lower(), score=org_scores.get(org["org_id"], 0), post_image=initiative_sequence[index]["image_by_condition"][condition], post_caption=initiative_sequence[index]["caption_by_condition"][condition], hashtags=org_hashtags.get(org["org_id"], ""), ) for index, org in enumerate(sequence) ] class Allocation(Page): form_model = "player" form_fields = ["donation_org_1", "donation_org_2", "donation_org_3", "donation_org_4"] @staticmethod def vars_for_template(player: Player): orgs = get_allocation_orgs(player.participant) return dict( allocation_orgs=orgs, bonus_endowment=C.BONUS_ENDOWMENT, completionlink=player.session.config["completionlink"], ) @staticmethod def error_message(player: Player, values): fields = ["donation_org_1", "donation_org_2", "donation_org_3", "donation_org_4"] for field in fields: if values[field] > C.BONUS_ENDOWMENT: return "Each donation must be between $0.00 and $3.00." if values[field] < 0: return "Each donation must be between $0 and $3." total = values["donation_org_1"] + values["donation_org_2"] + values["donation_org_3"] + values[ "donation_org_4"] if total > C.BONUS_ENDOWMENT: return f"Your total donations exceed your $3.00 bonus. Please reduce your donations." @staticmethod def before_next_page(player: Player, timeout_happened): total = player.donation_org_1 + player.donation_org_2 + player.donation_org_3 + player.donation_org_4 player.total_donated = total player.amount_kept = C.BONUS_ENDOWMENT - total orgs = get_allocation_orgs(player.participant) for org in orgs: setattr(player, f"score_org_{org['slot']}", org['score']) player.participant.vars["donation_summary"] = dict( bonus_endowment=C.BONUS_ENDOWMENT, total_donated=player.total_donated, amount_kept=player.amount_kept, allocations=[ dict( name=org["name"], condition=player.participant.vars["condition"], amount=getattr(player, org["field_name"]), ) for org in get_allocation_orgs(player.participant) ], ) page_sequence = [Allocation]