====== Quota ====== In [[panels|collaboration with panel providers]], quoted samples are often booked. The questionnaire is then responsible for the quota stop: If there are enough questionnaires for a demographic group, further participants of this group are sent back to a quota-full address of the panel provider. **Note:** For other forms of recruitment a quota stop is usually __not__ useful. The consequence would be that the majority of interested participants would be rejected -- but at the same time, recruitment would still be necessary to complete the missing demographic groups. **Tip:** Use the debug mode and view the debug information to check the function of the quota stop and if it does not work immediately in the test (e.g. with very small quotas)([[:en:create:filter-solving]]). ====== Functionality ====== The quota limits by demographic groups includes the following steps: - Query the quota characteristics of a person using ''[[:de:create:functions:value]]''. - Counting how many persons with this characteristic value or with this combination of characteristic values have already been surveyed using ''[[:de:create:functions:statistic]]''. - Comparison of the count with a quota table showing how many people are needed per demographic cell. - Rejecting people if there are already enough cases for a demographic cell, using ''[[:de:create:functions:redirect]]''. The term "demographic cell" or "demographic group" means a combination of the characteristics to be quoted (e.g. "male participants between 15 and 25 years" if age and gender are quoted). In principle, unrelated and related quota can be examined. In the case of unrelated quota, the characteristics are checked one after the other ("Are there already enough questionnaires from male participants? Are there already enough questionnaires from young participants?"). Here the marginal sums of the distribution are checked. Accordingly, in the unrelated quota system, it would be possible to fill the quota with young women and old men -- without any young men. In the linked quota system, the demographic cells are checked ("Are there already enough questionnaires from young male participants?"). The linked quota system is thus less susceptible to systematic distortions (conflicting demographic characteristics) -- but more potential participants are also rejected. Please note the interaction between ''statistic()'' and ''redirect()'': The function ''redirect()'' marks the questionnaires of rejected participants as "completed" (FINISHED=1), so that they are counted by ''statistic()''. In order to avoid wrong counts, the variables that were queried in the questionnaire are not counted directly: Instead, with the Complete-Redirect the quota characteristics are copied to [[:de:create:questions:internal|internal variables]] by means of [[:de:create:functions:put]], which can then be counted. Thus, 2 separate PHP codes are required for the quota. - After querying the quota characteristics (on the following page), the value specified by the participant is checked against the number of existing cases. - Directly before the Complete-Redirect, the value of the quota characteristic is copied into an internal variable. If the quota feature has to be recoded first, this PHP code is used in both parts. ===== Technical implementation (unrelated quotas) ==== The technical implementation is done by [[:en:create:php]] and comprises several steps. These are first explained here for the verification of unrelated quotas. In the following two characteristics are quoted as examples: Age (open query in variable "SD01_01") and gender (closed query in variable "SD02"). It is advisable to define quote questions as [[:en:create:checks#response compulsive|mandatory questions]]. ==== Definition of quota ==== First, a list ([[:en:create:array|Array]]) is required, which specifies the desired number of participants for each characteristic value. For unrelated quota, one quota table per feature is required. In the following example, the screenout is integrated directly in the quota check. However, an upstream screenout would also be possible. $quotaAge = [ 2 => 200, // 200 persons in age group 2 (18-30 years) 3 => 250, // 250 persons in age group 3 (31-50 years) 4 => 150 // 150 persons in age group 4 (51-68 years) ]; $quotaGender = [ 1 => 300, // 300 women (code 1) 2 => 300 // 300 men (code 2) ]; Please note that there are no entries in the table for age groups 1 (persons under 18 years) and 5 (persons older than 68 years). The same applies to gender 3 (persons who assign themselves to another gender). This is represented in the screenout (below) by the function ''[[https://www.php.net/manual/de/function.array-key-exists.php|array_key_exists()]]''. ==== Read out and recode characteristics ==== The characteristic value of the current participant is read out using ''value()'' and, if necessary, recoded with an [[:en:create:php-filters#the_keyword_if|IF construction]]. In this case the age (open input) has to be recoded. // Gender is read out directly $gender = value('SD02') // The age is recoded $age = value('SD01_01') if ($age < 18) { $ageGroup = 1; } elseif ($age <= 30) { $ageGroup = 2; } elseif ($age <= 50) { $ageGroup = 3; } elseif ($age <= 68) { $ageGroup = 4; } else { $ageGroup = 5; } ==== Counting the cases in hand === Now the system uses ''statistic()'' to check how many data records with the quota characteristics already exist in the data record. This value is then compared with the quota defined above. **Important:** For the PHP code to work correctly, all parts must be in the same PHP code block. [[:en:create:variables#php-variables|PHP-Variables]] such as ''$quotaAge'' and ''$ageGroup'' are only valid within one code block. In the following code __not__ the variables used to query the quota characteristics ("SD01_01" and "SD02") are counted, but internal variables ("SD03_01" and "SD03_02"). **Important:** The [[:en:create:questions:internal|internal variables]] must be created manually in advance in the **question catalogue**. // Retrieval of the available cases for this characteristic $casesAge = statistic('count', 'SD03_01', $ageGroup); $casesGender = statistic('count', 'SD03_02', $gender); // Screenout if (!array_key_exists($ageGroup, $quotaAge) || !array_key_exists($gender, $quotaGender)) { redirect('https://www.panelanbieter.de/?xyz=screenoutGHIJKI&uid=%reference%'); } // Reading the quota for the specified characteristics $maxPerAge = $quotaAge [$ageGroup]; $maxPerGender = $quotaGender[$gender]; // quota stop if (($casesAge >= $maxPerAge) || ($casesGender >= $maxPerGender)) { redirect('https://www.panelanbieter.de/?xyz=quotaABCDEF&uid=%reference%'); } The Boolean operator ''||'' is an OR operation between the two conditions. So if there are either enough cases for age __or__ enough cases for gender, a QuotaFull redirect is performed. You can get the redirect link from the Panel provider. It is important that you submit the participant ID. The example uses the placeholder ''%reference%''. Details can be found here: [[:en:survey:panels]]. **Important:** The participant's response will not be transmitted to the server until the participant has sent it by clicking "Next". If the questions "SD01" and "SD02" are on page 2 of the questionnaire, ''value()'' and thus the PHP code above can be placed on page 3 at the earliest. ==== Copy quota characteristics ==== Finally, the quota characteristics must be copied to the internal variables. This means directly before the Complete-Redirect, which is usually placed on the penultimate page of the questionnaire. To do this you need __redo__ the PHP code from the section [[#Read_out_and_recode_characteristics|Read out and recode characteristics]] (above) and in the same PHP code block directly below the function ''[[:de:create:functions:put]]'' to set the internal variables. put('SD03_01', $ageGroup); put('SD03_02', $gender); This is usually followed by the Complete redirect. redirect('https://www.panelanbieter.de/?xyz=completeDEFGHI&uid=%reference%'); ===== Related Quota ===== ==== Quota check at the beginning === If you work with linked quota, you must define a larger number of quota: One threshold per demographic cell. With 3 values for age and 2 values for gender, this makes a total of 6 quota. In the following PHP code, a demographic cell is defined by a code of age (2-4) and gender (1-2). For the sake of clarity, the 6 quota are noted in 3 lines with 2 quota each -- technically it makes no difference if the comma is followed by a line break. $quota = [ '2-1' => 100, '2-2' => 100, // 100 persons per gender for age group 1 '3-1' => 125, '3-2' => 125, // 125 persons per gender for age group 2 '4-1' => 75, '4-2' => 75 // 75 persons per gender for age group 3 ]; The readout of the quota-relevant characteristics and the recoding is initially carried out in the same way as for the unrelated quota. // Gender is read out directly $gender = value('SD02') // Age is recoded $age = value('SD01_01') if ($age < 18) { $ageGroup = 1; } elseif ($age <= 30) { $ageGroup = 2; } elseif ($age <= 50) { $ageGroup = 3; } elseif ($age <= 68) { $ageGroup = 4; } else { $ageGroup = 5; } However, an additional variable is defined, which contains the code of the demographic cell. The dot (''.'') is used in PHP to join texts (concatenate strings). // Definition of a variable with age group and gender // 3 and 2 become '3-2' here $demGroup = $ageGroup.'-'.$gender The quota check is now performed for this (combined) characteristic. Again, an internal variable (SD04_01) is used, which must be defined in advance in the **question catalog**. // Retrieval of the available cases for this characteristic $cases = statistic('count', 'SD04_01', $demGroup); // screenout if (!array_key_exists($demGroup, $quota)) { redirect('https://www.panelanbieter.de/?xyz=screenoutGHIJKI&uid=%reference%'); } // Reading the quota for the demographic group $maxPerGroup = $quota [$demGroup]; // quota stop if ($cases >= $maxPerGroup) { redirect('https://www.panelanbieter.de/?xyz=quotaABCDEF&uid=%reference%'); } ==== Saving the cell code ==== Before the Complete-Redirect, the code for the demographic cell must be saved in the internal variable. // Saving the group membership in the internal variable SD04_01 put('SD04_01', $demGroup); In order for this code to work, the quota characteristics must also be retrieved and recoded. And of course they have to be concatenated to the cell code ''$demGroup''. The complete code for the penultimate questionnaire page including Complete-Redirect looks like this // Gender is read out directly $gender = value('SD02') // Age is recoded $age = value('SD01_01') if ($age < 18) { $ageGroup = 1; } elseif ($age <= 30) { $ageGroup = 2; } elseif ($age <= 50) { $ageGroup = 3; } elseif ($age <= 68) { $ageGroup = 4; } else { $ageGroup = 5; } // Definition of a variable with age group and gender // 3 and 2 become '3-2' here $demGroup = $ageGroup.'-'.$gender // Store the group membership in the internal variable SD04_01 put('SD04_01', $demGroup); // Complete-Redirect redirect('https://www.panelanbieter.de/?xyz=completeDEFGHI&uid=%reference%');