from otree.api import * doc = """ Rating images (WTP/willingness to pay) """ class Product(ExtraModel): sku = models.StringField() name = models.StringField() image_png = models.StringField() def load_products(): rows = read_csv(__name__ + '/catalog.csv', Product) for row in rows: row['image_path'] = 'product/{}.png'.format(row['image_png']) return rows class C(BaseConstants): NAME_IN_URL = 'image_rating' PLAYERS_PER_GROUP = None PRODUCTS = load_products() NUM_ROUNDS = len(PRODUCTS) SELLER_ROLE = 'Seller' BUYER_ROLE = 'Buyer' class Subsession(BaseSubsession): pass def creating_session(subsession: Subsession): for p in subsession.get_players(): img = get_current_product(p) p.sku = img['sku'] class Group(BaseGroup): deal_price = models.CurrencyField() is_finished = models.BooleanField(initial=False) class Player(BasePlayer): sku = models.StringField() willingness_to_pay = models.CurrencyField(label="", min=0) amount_proposed = models.IntegerField() amount_accepted = models.IntegerField() timeout = models.FloatField() completion_code = models.IntegerField() open_comment = models.StringField(label='Please rate your partner out of 10.') def get_current_product(player: Player): return C.PRODUCTS[player.round_number - 1] class MyPage(Page): form_model = 'player' form_fields = ['willingness_to_pay'] @staticmethod def vars_for_template(player: Player): return dict(product=get_current_product(player)) class Results(Page): @staticmethod def is_displayed(player: Player): return player.round_number == C.NUM_ROUNDS class Bargain(Page): @staticmethod def vars_for_template(player: Player): return dict(other_role=player.get_others_in_group()[0].role) @staticmethod def js_vars(player: Player): return dict(my_id=player.id_in_group) @staticmethod def live_method(player: Player, data): group = player.group [other] = player.get_others_in_group() if 'amount' in data: try: amount = int(data['amount']) except Exception: print('Invalid message received', data) return if data['type'] == 'accept': if amount == other.amount_proposed: player.amount_accepted = amount group.deal_price = amount group.is_finished = True return {0: dict(finished=True)} if data['type'] == 'propose': player.amount_proposed = amount proposals = [] for p in [player, other]: amount_proposed = p.field_maybe_none('amount_proposed') if amount_proposed is not None: proposals.append([p.id_in_group, amount_proposed]) return {0: dict(proposals=proposals)} @staticmethod def error_message(player: Player, values): group = player.group if not group.is_finished: return "Game not finished yet" @staticmethod def is_displayed(player: Player): """Skip this page if a deal has already been made""" group = player.group deal_price = group.field_maybe_none('deal_price') return deal_price is None class MyWaitPage(Page): pass class Rating(Page): form_model = 'player' form_fields = ['open_comment'] page_sequence = [MyWaitPage, MyPage, Bargain, Rating, Results]