from otree.api import ( models, widgets, BaseConstants, BaseSubsession, BaseGroup, BasePlayer, Currency as c, currency_range, ) import math import random author = 'Your name here' doc = """ Your app description """ class Constants(BaseConstants): name_in_url = 'respondi_quotas' players_per_group = None num_rounds = 1 variable_list = ['quota_male', 'quota_female', 'quota_diverse', 'quota_age_18_to_29', 'quota_age_30_to_39', 'quota_age_40_to_49', 'quota_age_50_to_59', 'quota_age_60_to_69', 'quota_income_less_than_1100', 'quota_income_1100_to_1500', 'quota_income_1500_to_2000', 'quota_income_2000_to_2600', 'quota_income_more_than_2600'] class Subsession(BaseSubsession): def creating_session(self): self.session.vars['treatment_list'] = [] for i in range(1, self.session.config['number_of_treatments'] + 1): if self.session.config['include_treatment_' + str(i)]: self.session.vars['treatment_list'].append(i) if len(self.session.vars['treatment_list']) == 0: for i in range(1, self.session.config['number_of_treatments'] + 1): self.session.vars['treatment_list'].append(i) players = self.get_players() num_randomization_treatment = int(math.ceil(len(players) / len(self.session.vars['treatment_list']))) random_treatment_numbers = [] for x in range(0, num_randomization_treatment): random_treatment_numbers.extend(self.session.vars['treatment_list']) self.session.config['treatment_allocation_list'] = random.shuffle(random_treatment_numbers) def set_quota(key, treatment_number): self.session.vars[key + '_' + str(treatment_number)] = self.session.config[key] self.session.vars['actual_' + key + '_' + str(treatment_number)] = 0 for t in self.session.vars['treatment_list']: for v in Constants.variable_list: set_quota(v, t) def vars_for_admin_report(self) -> dict: def get_quota(key, treatment_number): the_key = key + '_' + str(treatment_number) return self.session.vars[the_key] def set_admin_dict(dic, key, treatment): dic[key] = get_quota(key, treatment) dic['actual_' + key] = get_quota('actual_' + key, treatment) treatments = [] for t in self.session.vars['treatment_list']: treatment_dict = {'treatment_number': t} for v in Constants.variable_list: set_admin_dict(treatment_dict, v, t) treatments.append(treatment_dict) return_dict = {'treatments': treatments } return return_dict class Group(BaseGroup): pass class Player(BasePlayer): treatment_number = models.PositiveIntegerField() quotafull = models.BooleanField(initial=False) screenout = models.BooleanField(initial=False) children = models.PositiveIntegerField(label='Wie viele Kinder haben Sie?') householdIncome = models.CurrencyField(label='Wie hoch ist das Einkommen Ihres Haushalts (netto, pro Monat)?') householdSize = models.PositiveIntegerField( label='Mit wie vielen anderen Personen leben Sie in einem Haushalt (wenn Sie alleine leben, geben Sie bitte 0 an)?') childrenInHousehold = models.PositiveIntegerField( label='Wie viele der Personen in Ihrem Haushalt sind Kinder unter 14 Jahren?') # Seite 22 (Soziodemografische Fragen) gender = models.IntegerField(choices=[[0, 'weiblich'], [1, 'männlich'], [2, 'divers']], # blank = True, label='Mit welchem Geschlecht identifizieren Sie sich?') age = models.PositiveIntegerField(label='Wie alt sind Sie (in Jahren)?') net_equivalence_income = models.CurrencyField() def determine_screenout(self): self.screenout |= self.age < 18 or self.age > 69 # self.screenout |= self.check_diverse_quotas() return self.screenout def check_quotafull(self, key, treatment): quota: int = self.session.vars[key + '_' + str(treatment)] actual_quota: int = self.session.vars['actual_' + key + '_' + str(treatment)] if actual_quota >= quota: return True else: return False def determine_quotafull(self): quota_full = False if len(self.get_non_empty_treatment_groups()) == 0: quota_full = True self.quotafull = quota_full return quota_full def increment_quota(self, key, treatment): self.session.vars['actual_' + key + '_' + str(treatment)] += 1 def increment_quotas(self): non_empty_treatments = self.get_non_empty_treatment_groups() if len(non_empty_treatments) > 0: treatment = random.choice(non_empty_treatments) self.participant.vars['treatment_number'] = treatment self.treatment_number = treatment gender = self.gender age = self.age net_equivalence_income = self.net_equivalence_income if self.check_in_range(18, age, 29): self.increment_quota('quota_age_18_to_29', treatment) elif self.check_in_range(30, age, 39): self.increment_quota('quota_age_30_to_39', treatment) elif self.check_in_range(40, age, 49): self.increment_quota('quota_age_40_to_49', treatment) elif self.check_in_range(50, age, 59): self.increment_quota('quota_age_50_to_59', treatment) elif self.check_in_range(60, age, 69): self.increment_quota('quota_age_60_to_69', treatment) if gender == 0: self.increment_quota('quota_female', treatment) elif gender == 1: self.increment_quota('quota_male', treatment) elif gender == 2: self.increment_quota('quota_diverse', treatment) if self.check_in_range(0, net_equivalence_income, 1100): self.increment_quota('quota_income_less_than_1100', treatment) elif self.check_in_range(1100, net_equivalence_income, 1500): self.increment_quota('quota_income_1100_to_1500', treatment) elif self.check_in_range(1500, net_equivalence_income, 2000): self.increment_quota('quota_income_1500_to_2000', treatment) elif self.check_in_range(2000, net_equivalence_income, 2600): self.increment_quota('quota_income_2000_to_2600', treatment) elif self.check_in_range(2600, net_equivalence_income, math.inf): self.increment_quota('quota_income_more_than_2600', treatment) @staticmethod def check_in_range(lower_border, value, upper_border): return lower_border <= value <= upper_border def get_non_empty_treatment_groups(self): gender = self.gender age = self.age net_equivalence_income = self.net_equivalence_income non_empty_treatments = [] for t in self.session.vars['treatment_list']: quota_full = False quota_full |= gender == 0 and self.check_quotafull('quota_female', t) quota_full |= gender == 1 and self.check_quotafull('quota_male', t) quota_full |= gender == 2 and self.check_diverse_quota(t) quota_full |= self.check_in_range(18, age, 29) and self.check_quotafull('quota_age_18_to_29', t) quota_full |= self.check_in_range(30, age, 39) and self.check_quotafull('quota_age_30_to_39', t) quota_full |= self.check_in_range(40, age, 49) and self.check_quotafull('quota_age_40_to_49', t) quota_full |= self.check_in_range(50, age, 59) and self.check_quotafull('quota_age_50_to_59', t) quota_full |= self.check_in_range(60, age, 69) and self.check_quotafull('quota_age_60_to_69', t) quota_full |= self.check_in_range(0, net_equivalence_income, 1100) and self.check_quotafull( 'quota_income_less_than_1100', t) quota_full |= self.check_in_range(1100, net_equivalence_income, 1500) and self.check_quotafull( 'quota_income_1100_to_1500', t) quota_full |= self.check_in_range(1500, net_equivalence_income, 2000) and self.check_quotafull( 'quota_income_1500_to_2000', t) quota_full |= self.check_in_range(2000, net_equivalence_income, 2600) and self.check_quotafull( 'quota_income_2000_to_2600', t) quota_full |= self.check_in_range(2600, net_equivalence_income, math.inf) and self.check_quotafull( 'quota_income_more_than_2600', t) if not quota_full: non_empty_treatments.append(t) return non_empty_treatments def check_diverse_quota(self, treatment): quota = self.session.vars['quota_diverse_' + str(treatment)] actual_quota = self.session.vars['actual_quota_diverse_' + str(treatment)] if actual_quota >= (quota + self.session.config.get("diverse_tolerance", 0)): return True else: return False def check_diverse_quotas(self): diverse_space_exists = False for t in self.session.vars['treatment_list']: diverse_space_exists |= self.check_diverse_quota(t) if diverse_space_exists: break return diverse_space_exists def get_net_equivalence_income(self): return (self.householdIncome / ( 1 + 0.5 * (self.householdSize - self.childrenInHousehold) + 0.3 * self.childrenInHousehold)) def get_timeout_seconds(self): timeout_seconds = self.session.config.get("timeout_hours", 2) * 60 * 60 return timeout_seconds