'Ajax response method, expects a JSON input like:
{l: the PE label (from the input field),
c: boolean to indicate whether to just check
the PE label or to register payments
t: the event type code
@param r: the S3Request instance
@param attr: controller parameters
@return: JSON response, structure:
{l: the actual PE label (to update the input field),
p: the person details,
d: the family details,
f: [{n: the flag name
i: the flag instructions
b: profile picture URL,
i: {<event_code>: [<msg>, <blocked_until_datetime>]},
s: whether the action is permitted or not
e: form error (for label field)
a: error message
w: warning message
m: success message'

def registration_ajax(self, r, **attr):

    T = current.T
    s = r.body
    s.seek(0)
    try:
        data = json.load(s)
    except (ValueError, TypeError):
        r.error(400, current.ERROR.BAD_REQUEST)
    output = {}
    error = None
    alert = None
    message = None
    warning = None
    permitted = False
    flags = []
    pe_label = data.get('l')
    person = self.get_person(pe_label)
    if (person is None):
        error = s3_str(T('No    person    found    with    this    ID    number'))
    else:
        flag_info = dvr_get_flag_instructions(person.id, action='id-check')
        permitted = flag_info['permitted']
        check = data.get('c')
        if check:
            person_details = self.person_details(person)
            profile_picture = self.profile_picture(person)
            output['p'] = s3_str(person_details)
            output['l'] = person.pe_label
            output['b'] = profile_picture
            details = dvr_get_household_size(person.id, dob=person.date_of_birth)
            if details:
                output['d'] = {'d': details}
            info = flag_info['info']
            for (flagname, instructions) in info:
                flags.append({'n': s3_str(T(flagname)), 'i': s3_str(T(instructions))})
            event_types = self.get_event_types()
            blocked = self.get_blocked_events(person.id)
            intervals = {}
            for (type_id, info) in blocked.items():
                event_type = event_types.get(type_id)
                if (not event_type):
                    continue
                code = event_type.code
                (msg, dt) = info
                intervals[code] = (s3_str(msg), ('%sZ' % s3_encode_iso_datetime(dt)))
            output['i'] = intervals
        else:
            type_id = None
            event_code = data.get('t')
            if (not event_code):
                alert = T('No    event    type    specified')
            elif (not permitted):
                alert = T('Event    registration    not    permitted')
            else:
                event_type = self.get_event_type(event_code)
                if (not event_type):
                    alert = (T('Invalid    event    type:    %s') % event_code)
                else:
                    type_id = event_type.id
            if type_id:
                person_id = person.id
                blocked = self.get_blocked_events(person_id, type_id=type_id)
                if (type_id in blocked):
                    alert = blocked[type_id][0]
                else:
                    success = self.register_event(person.id, type_id)
                    if success:
                        message = T('Event    registered')
                    else:
                        alert = T('Could    not    register    event')
    if alert:
        output['a'] = s3_str(alert)
    if error:
        output['e'] = s3_str(error)
    if message:
        output['m'] = s3_str(message)
    if warning:
        output['w'] = s3_str(warning)
    output['s'] = permitted
    output['f'] = flags
    current.response.headers['Content-Type'] = 'application/json'
    return json.dumps(output)
