Пример #1
0
    def __call__(self):

        form = self.request.form
        plone.protect.CheckAuthenticator(self.request.form)
        plone.protect.PostOnly(self.request.form)
        came_from = 'came_from' in form and form['came_from'] or 'add'
        wftool = getToolByName(self.context, 'portal_workflow')
        uc = getToolByName(self.context, 'uid_catalog')
        bsc = getToolByName(self.context, 'bika_setup_catalog')

        errors = {}

        form_parts = json.loads(self.request.form['parts'])

        # First make a list of non-empty columns
        columns = []
        for column in range(int(form['col_count'])):
            name = 'ar.%s' % column
            ar = form.get(name, None)
            if ar and 'Analyses' in ar.keys():
                columns.append(column)

        if len(columns) == 0:
            ajax_form_error(errors,
                            message=t(_("No analyses have been selected")))
            return json.dumps({'errors': errors})

        # Now some basic validation
        required_fields = [
            field.getName() for field in AnalysisRequestSchema.fields()
            if field.required
        ]

        for column in columns:
            formkey = "ar.%s" % column
            ar = form[formkey]

            # check that required fields have values
            for field in required_fields:
                # This one is still special.
                if field in ['RequestID']:
                    continue
                # And these are not required if this is a secondary AR
                if ar.get('Sample', '') != '' and field in [
                        'SamplingDate', 'SampleType'
                ]:
                    continue
                if not ar.get(field, ''):
                    ajax_form_error(errors, field, column)
        # Return errors if there are any
        if errors:
            return json.dumps({'errors': errors})

        # Get the prices from the form data
        prices = form.get('Prices', None)
        # Initialize the Anlysis Request collection
        ARs = []
        # if a new profile is created automatically,
        # this flag triggers the status message
        new_profile = None
        # The actual submission
        for column in columns:
            # Get partitions from the form data
            if form_parts:
                partitions = form_parts[str(column)]
            else:
                partitions = []
            # Get the form data using the appropriate form key
            formkey = "ar.%s" % column
            values = form[formkey].copy()
            # resolved values is formatted as acceptable by archetypes
            # widget machines
            resolved_values = {}
            for k, v in values.items():
                # Analyses, we handle that specially.
                if k == 'Analyses':
                    continue
                # Insert the reference *_uid values instead of titles.
                if "_uid" in k:
                    v = values[k]
                    v = v.split(",") if v and "," in v else v
                    fname = k.replace("_uid", "")
                    resolved_values[fname] = v
                    continue
                # we want to write the UIDs and ignore the title values
                if k + "_uid" in values:
                    continue
                resolved_values[k] = values[k]
            # Get the analyses from the form data
            analyses = values["Analyses"]

            # Gather the specifications from the form
            specs = json.loads(form['copy_to_new_specs']).get(str(column), {})
            if not specs:
                specs = json.loads(form['specs']).get(str(column), {})
            if specs:
                specs = dicts_to_dict(specs, 'keyword')
            # Modify the spec with all manually entered values
            for service_uid in analyses:
                min_element_name = "ar.%s.min.%s" % (column, service_uid)
                max_element_name = "ar.%s.max.%s" % (column, service_uid)
                error_element_name = "ar.%s.error.%s" % (column, service_uid)
                service_keyword = bsc(UID=service_uid)[0].getKeyword
                if min_element_name in form:
                    if service_keyword not in specs:
                        specs[service_keyword] = {}
                    specs[service_keyword]["keyword"] = service_keyword
                    specs[service_keyword]["min"] = form[min_element_name]
                    specs[service_keyword]["max"] = form[max_element_name]
                    specs[service_keyword]["error"] = form[error_element_name]

            # Selecting a template sets the hidden 'parts' field to template values.
            # Selecting a profile will allow ar_add.js to fill in the parts field.
            # The result is the same once we are here.
            if not partitions:
                partitions = [{
                    'services': [],
                    'container': None,
                    'preservation': '',
                    'separate': False
                }]
            # Apply DefaultContainerType to partitions without a container
            default_container_type = resolved_values.get(
                'DefaultContainerType', None)
            if default_container_type:
                container_type = bsc(UID=default_container_type)[0].getObject()
                containers = container_type.getContainers()
                for partition in partitions:
                    if not partition.get("container", None):
                        partition['container'] = containers
            # Retrieve the catalogue reference to the client
            client = uc(UID=resolved_values['Client'])[0].getObject()
            # Create the Analysis Request
            ar = create_analysisrequest(client,
                                        self.request,
                                        resolved_values,
                                        analyses=analyses,
                                        partitions=partitions,
                                        specifications=specs.values(),
                                        prices=prices)
            # Add the created analysis request to the list
            ARs.append(ar.getId())
        # Display the appropriate message after creation
        if len(ARs) > 1:
            message = _("Analysis requests ${ARs} were successfully created.",
                        mapping={'ARs': safe_unicode(', '.join(ARs))})
        else:
            message = _("Analysis request ${AR} was successfully created.",
                        mapping={'AR': safe_unicode(ARs[0])})
        self.context.plone_utils.addPortalMessage(message, 'info')
        # Automatic label printing
        # Won't print labels for Register on Secondary ARs
        new_ars = None
        if came_from == 'add':
            new_ars = [ar for ar in ARs if ar[-2:] == '01']
        if 'register' in self.context.bika_setup.getAutoPrintStickers(
        ) and new_ars:
            return json.dumps({
                'success':
                message,
                'stickers':
                new_ars,
                'stickertemplate':
                self.context.bika_setup.getAutoStickerTemplate()
            })
        else:
            return json.dumps({'success': message})
Пример #2
0
    def __call__(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(self.request.form)
        plone.protect.PostOnly(self.request.form)
        uc = getToolByName(self.context, 'uid_catalog')
        bsc = getToolByName(self.context, 'bika_setup_catalog')
        portal_catalog = getToolByName(self.context, 'portal_catalog')

        # Load the form data from request.state.  If anything goes wrong here,
        # put a bullet through the whole process.
        try:
            states = json.loads(form['state'])
        except Exception as e:
            message = t(_('Badly formed state: ${errmsg}',
                          mapping={'errmsg': e.message}))
            ajax_form_error(self.errors, message=message)
            return json.dumps({'errors': self.errors})

        # Validate incoming form data
        required = [field.getName() for field
                    in AnalysisRequestSchema.fields()
                    if field.required] + ["Analyses"]

        # First remove all states which are completely empty; if all
        # required fields are not present, we assume that the current
        # AR had no data entered, and can be ignored
        nonblank_states = {}
        for arnum, state in states.items():
            for key, val in state.items():
                if val \
                        and "%s_hidden" % key not in state \
                        and not key.endswith('hidden'):
                    nonblank_states[arnum] = state
                    break

        # in valid_states, all ars that pass validation will be stored
        valid_states = {}
        for arnum, state in nonblank_states.items():
            # Secondary ARs are a special case, these fields are not required
            if state.get('Sample', ''):
                if 'SamplingDate' in required:
                    required.remove('SamplingDate')
                if 'SampleType' in required:
                    required.remove('SampleType')
            # fields flagged as 'hidden' are not considered required because
            # they will already have default values inserted in them
            for fieldname in required:
                if fieldname + '_hidden' in state:
                    required.remove(fieldname)
            missing = [f for f in required if not state.get(f, '')]
            # If there are required fields missing, flag an error
            if missing:
                msg = t(_('Required fields have no values: '
                          '${field_names}',
                          mapping={'field_names': ', '.join(missing)}))
                ajax_form_error(self.errors, arnum=arnum, message=msg)
                continue
            # This ar is valid!
            valid_states[arnum] = state

        # - Expand lists of UIDs returned by multiValued reference widgets
        # - Transfer _uid values into their respective fields
        for arnum in valid_states.keys():
            for field, value in valid_states[arnum].items():
                if field.endswith('_uid') and ',' in value:
                    valid_states[arnum][field] = value.split(',')
                elif field.endswith('_uid'):
                    valid_states[arnum][field] = value

        if self.errors:
            return json.dumps({'errors': self.errors})

        # Now, we will create the specified ARs.
        ARs = []
        for arnum, state in valid_states.items():
            # Create the Analysis Request
            ar = crar(
                portal_catalog(UID=state['Client'])[0].getObject(),
                self.request,
                state
            )
            ARs.append(ar.Title())

        # Display the appropriate message after creation
        if len(ARs) > 1:
            message = _('Analysis requests ${ARs} were successfully created.',
                        mapping={'ARs': safe_unicode(', '.join(ARs))})
        else:
            message = _('Analysis request ${AR} was successfully created.',
                        mapping={'AR': safe_unicode(ARs[0])})
        self.context.plone_utils.addPortalMessage(message, 'info')
        # Automatic label printing won't print "register" labels for Secondary. ARs
        #This was a hack and is still a hack but will work more widely
        new_ars = [ar for ar in ARs if ar[-1] == '1']
        if 'register' in self.context.bika_setup.getAutoPrintStickers() \
                and new_ars:
            return json.dumps({
                'success': message,
                'stickers': new_ars,
                'stickertemplate': self.context.bika_setup.getAutoStickerTemplate()
            })
        else:
            return json.dumps({'success': message})
Пример #3
0
    def validate_form(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(self.request.form)
        plone.protect.PostOnly(self.request.form)
        uc = getToolByName(self.context, 'uid_catalog')
        bsc = getToolByName(self.context, 'bika_setup_catalog')
        portal_catalog = getToolByName(self.context, 'portal_catalog')

        # Load the form data from request.state.  If anything goes wrong here,
        # put a bullet through the whole process.
        try:
            states = json.loads(form['state'])
        except Exception as e:
            message = t(
                _('Badly formed state: ${errmsg}',
                  mapping={'errmsg': e.message}))
            ajax_form_error(self.errors, message=message)
            return json.dumps({'errors': self.errors})

        # Validate incoming form data
        required = [
            field.getName()
            for field in AnalysisRequestSchema.fields() if field.required
        ] + ["Analyses"]

        # First remove all states which are completely empty; if all
        # required fields are not present, we assume that the current
        # AR had no data entered, and can be ignored
        nonblank_states = {}
        for arnum, state in states.items():
            for key, val in state.items():
                if val \
                        and "%s_hidden" % key not in state \
                        and not key.endswith('hidden'):
                    nonblank_states[arnum] = state
                    break

        # in valid_states, all ars that pass validation will be stored
        self.valid_states = {}
        for arnum, state in nonblank_states.items():
            secondary = False
            # Secondary ARs are a special case, these fields are not required
            if state.get('Sample', ''):
                if 'SamplingDate' in required:
                    required.remove('SamplingDate')
                if 'SampleType' in required:
                    required.remove('SampleType')
                secondary = True
            # If this is not a Secondary AR, make sure that Sample Type UID is valid. This shouldn't
            # happen, but making sure just in case.
            else:
                st_uid = state.get('SampleType', None)
                if not st_uid or not bsc(portal_type='SampleType', UID=st_uid):
                    msg = t(_("Not a valid Sample Type."))
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
            # checking if sampling date is not future
            if state.get('SamplingDate', ''):
                samplingdate = state.get('SamplingDate', '')
                try:
                    samp_date = datetime.datetime.strptime(
                        samplingdate.strip(), "%Y-%m-%d %H:%M")
                except ValueError:
                    print traceback.format_exc()
                    msg = \
                        "Bad time formatting: Getting '{}' but expecting an" \
                        " string with '%Y-%m-%d %H:%M' format." \
                            .format(samplingdate)
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
                today = date.today()
                if not secondary and today > samp_date.date():
                    msg = t(_("Expected Sampling Date can't be in the past"))
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
            # If Sampling Date is not set, we are checking whether it is the user left it empty,
            # or it is because we have Sampling Workflow Disabled
            elif not self.context.bika_setup.getSamplingWorkflowEnabled():
                # Date Sampled is required in this case
                date_sampled = state.get('DateSampled', '')
                if not date_sampled:
                    msg = \
                        "Date Sampled Field is required."
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
                try:
                    date_sampled = datetime.datetime.strptime(
                        date_sampled.strip(), "%Y-%m-%d %H:%M")
                except ValueError:
                    print traceback.format_exc()
                    msg = \
                        "Bad time formatting: Getting '{}' but expecting an" \
                        " string with '%Y-%m-%d %H:%M' format." \
                            .format(date_sampled)
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
            # fields flagged as 'hidden' are not considered required because
            # they will already have default values inserted in them
            for fieldname in required:
                if fieldname + '_hidden' in state:
                    required.remove(fieldname)
            missing = [f for f in required if not state.get(f, '')]
            # If there are required fields missing, flag an error
            if missing:
                msg = t(
                    _('Required fields have no values: '
                      '${field_names}',
                      mapping={'field_names': ', '.join(missing)}))
                ajax_form_error(self.errors, arnum=arnum, message=msg)
                continue
            # This ar is valid!
            self.valid_states[arnum] = state

        # - Expand lists of UIDs returned by multiValued reference widgets
        # - Transfer _uid values into their respective fields
        for arnum in self.valid_states.keys():
            for field, value in self.valid_states[arnum].items():
                if field.endswith('_uid') and ',' in value:
                    self.valid_states[arnum][field] = value.split(',')
                elif field.endswith('_uid'):
                    self.valid_states[arnum][field] = value
Пример #4
0
    def __call__(self):

        form = self.request.form
        plone.protect.CheckAuthenticator(self.request.form)
        plone.protect.PostOnly(self.request.form)
        came_from = 'came_from' in form and form['came_from'] or 'add'
        wftool = getToolByName(self.context, 'portal_workflow')
        uc = getToolByName(self.context, 'uid_catalog')
        bsc = getToolByName(self.context, 'bika_setup_catalog')

        errors = {}

        form_parts = json.loads(self.request.form['parts'])

        # First make a list of non-empty columns
        columns = []
        for column in range(int(form['col_count'])):
            name = 'ar.%s' % column
            ar = form.get(name, None)
            if ar and 'Analyses' in ar.keys():
                columns.append(column)

        if len(columns) == 0:
            ajax_form_error(errors, message=t(_("No analyses have been selected")))
            return json.dumps({'errors':errors})

        # Now some basic validation
        required_fields = [field.getName() for field
                           in AnalysisRequestSchema.fields()
                           if field.required]

        for column in columns:
            formkey = "ar.%s" % column
            ar = form[formkey]
            # Secondary ARs don't have sample fields present in the form data
            # if 'Sample_uid' in ar and ar['Sample_uid']:
            # adapter = getAdapter(self.context, name='getWidgetVisibility')
            #     wv = adapter().get('secondary', {}).get('invisible', [])
            #     required_fields = [x for x in required_fields if x not in wv]
            # check that required fields have values
            for field in required_fields:
                # This one is still special.
                if field in ['RequestID']:
                    continue
                    # And these are not required if this is a secondary AR
                if ar.get('Sample', '') != '' and field in [
                    'SamplingDate',
                    'SampleType'
                ]:
                    continue
                if not ar.get(field, ''):
                    ajax_form_error(errors, field, column)
        # Return errors if there are any
        if errors:
            return json.dumps({'errors': errors})
        # Get the prices from the form data
        prices = form.get('Prices', None)
        # Initialize the Anlysis Request collection
        ARs = []
        # if a new profile is created automatically,
        # this flag triggers the status message
        new_profile = None
        # The actual submission
        for column in columns:
            # Get partitions from the form data
            if form_parts:
                partitions = form_parts[str(column)]
            else:
                partitions = []
            # Get the form data using the appropriate form key
            formkey = "ar.%s" % column
            values = form[formkey].copy()
            # resolved values is formatted as acceptable by archetypes
            # widget machines
            resolved_values = {}
            for k, v in values.items():
                # Analyses, we handle that specially.
                if k == 'Analyses':
                    continue
                if "%s_uid" % k in values:
                    v = values["%s_uid" % k]
                    if v and "," in v:
                        v = v.split(",")
                    resolved_values[k] = values["%s_uid" % k]
                else:
                    resolved_values[k] = values[k]
            # Get the analyses from the form data
            analyses = values["Analyses"]
            # Gather the specifications from the form data
            # no defaults are applied here - the defaults should already be
            # present in the form data
            specifications = {}
            for analysis in analyses:
                for service_uid in analyses:
                    min_element_name = "ar.%s.min.%s"%(column, service_uid)
                    max_element_name = "ar.%s.max.%s"%(column, service_uid)
                    error_element_name = "ar.%s.error.%s"%(column, service_uid)
                    if min_element_name in form:
                        specifications[service_uid] = {
                            "min": form[min_element_name],
                            "max": form[max_element_name],
                            "error": form[error_element_name]
                        }
            # Selecting a template sets the hidden 'parts' field to template values.
            # Selecting a profile will allow ar_add.js to fill in the parts field.
            # The result is the same once we are here.
            if not partitions:
                partitions = [{
                    'services': [],
                    'container': None,
                    'preservation': '',
                    'separate': False
                }]
            # Apply DefaultContainerType to partitions without a container
            default_container_type = resolved_values.get(
                'DefaultContainerType', None
            )
            if default_container_type:
                container_type = bsc(UID=default_container_type)[0].getObject()
                containers = container_type.getContainers()
                for partition in partitions:
                    if not partition.get("container", None):
                        partition['container'] = containers
            # Retrieve the catalogue reference to the client
            client = uc(UID=resolved_values['Client'])[0].getObject()
            # Create the Analysis Request
            ar = create_analysisrequest(
                client,
                self.request,
                resolved_values,
                analyses,
                partitions,
                specifications,
                prices
            )
            # Add the created analysis request to the list
            ARs.append(ar.getId())
        # Display the appropriate message after creation
        if len(ARs) > 1:
            message = _("Analysis requests ${ARs} were successfully created.",
                        mapping={'ARs': safe_unicode(', '.join(ARs))})
        else:
            message = _("Analysis request ${AR} was successfully created.",
                        mapping={'AR': safe_unicode(ARs[0])})
        self.context.plone_utils.addPortalMessage(message, 'info')
        # Automatic label printing
        # Won't print labels for Register on Secondary ARs
        new_ars = None
        if came_from == 'add':
            new_ars = [ar for ar in ARs if ar[-2:] == '01']
        if 'register' in self.context.bika_setup.getAutoPrintLabels() and new_ars:
            return json.dumps({
                'success': message,
                'labels': new_ars,
                'labelsize': self.context.bika_setup.getAutoLabelSize()
            })
        else:
            return json.dumps({'success': message})
Пример #5
0
    def validate_form(self):
        form = self.request.form
        plone.protect.CheckAuthenticator(self.request.form)
        plone.protect.PostOnly(self.request.form)
        uc = getToolByName(self.context, 'uid_catalog')
        bsc = getToolByName(self.context, 'bika_setup_catalog')
        portal_catalog = getToolByName(self.context, 'portal_catalog')

        # Load the form data from request.state.  If anything goes wrong here,
        # put a bullet through the whole process.
        try:
            states = json.loads(form['state'])
        except Exception as e:
            message = t(_('Badly formed state: ${errmsg}',
                          mapping={'errmsg': e.message}))
            ajax_form_error(self.errors, message=message)
            return json.dumps({'errors': self.errors})

        # Validate incoming form data
        required = [field.getName() for field
                    in AnalysisRequestSchema.fields()
                    if field.required] + ["Analyses"]

        # First remove all states which are completely empty; if all
        # required fields are not present, we assume that the current
        # AR had no data entered, and can be ignored
        nonblank_states = {}
        for arnum, state in states.items():
            for key, val in state.items():
                if val \
                        and "%s_hidden" % key not in state \
                        and not key.endswith('hidden'):
                    nonblank_states[arnum] = state
                    break

        # in valid_states, all ars that pass validation will be stored
        self.valid_states = {}
        for arnum, state in nonblank_states.items():
            secondary = False
            # Secondary ARs are a special case, these fields are not required
            if state.get('Sample', ''):
                if 'SamplingDate' in required:
                    required.remove('SamplingDate')
                if 'SampleType' in required:
                    required.remove('SampleType')
                secondary = True
            # If this is not a Secondary AR, make sure that Sample Type UID is valid. This shouldn't
            # happen, but making sure just in case.
            else:
                st_uid = state.get('SampleType', None)
                if not st_uid or not bsc(portal_type='SampleType', UID=st_uid):
                    msg = t(_("Not a valid Sample Type."))
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
            # checking if sampling date is not future
            if state.get('SamplingDate', ''):
                samplingdate = state.get('SamplingDate', '')
                try:
                    samp_date = datetime.datetime.strptime(
                        samplingdate.strip(), "%Y-%m-%d %H:%M")
                except ValueError:
                    print traceback.format_exc()
                    msg = \
                        "Bad time formatting: Getting '{}' but expecting an" \
                        " string with '%Y-%m-%d %H:%M' format." \
                            .format(samplingdate)
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
                today = date.today()
                if not secondary and today > samp_date.date():
                    msg = t(_("Expected Sampling Date can't be in the past"))
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
            # If Sampling Date is not set, we are checking whether it is the user left it empty,
            # or it is because we have Sampling Workflow Disabled
            elif not self.context.bika_setup.getSamplingWorkflowEnabled():
                # Date Sampled is required in this case
                date_sampled = state.get('DateSampled', '')
                if not date_sampled:
                    msg = \
                        "Date Sampled Field is required."
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
                try:
                    date_sampled = datetime.datetime.strptime(
                        date_sampled.strip(), "%Y-%m-%d %H:%M")
                except ValueError:
                    print traceback.format_exc()
                    msg = \
                        "Bad time formatting: Getting '{}' but expecting an" \
                        " string with '%Y-%m-%d %H:%M' format." \
                            .format(date_sampled)
                    ajax_form_error(self.errors, arnum=arnum, message=msg)
                    continue
            # fields flagged as 'hidden' are not considered required because
            # they will already have default values inserted in them
            for fieldname in required:
                if fieldname + '_hidden' in state:
                    required.remove(fieldname)
            missing = [f for f in required if not state.get(f, '')]
            # If there are required fields missing, flag an error
            if missing:
                msg = t(_('Required fields have no values: '
                          '${field_names}',
                          mapping={'field_names': ', '.join(missing)}))
                ajax_form_error(self.errors, arnum=arnum, message=msg)
                continue
            # This ar is valid!
            self.valid_states[arnum] = state

        # - Expand lists of UIDs returned by multiValued reference widgets
        # - Transfer _uid values into their respective fields
        for arnum in self.valid_states.keys():
            for field, value in self.valid_states[arnum].items():
                if field.endswith('_uid') and ',' in value:
                    self.valid_states[arnum][field] = value.split(',')
                elif field.endswith('_uid'):
                    self.valid_states[arnum][field] = value
Пример #6
0
    def __call__(self):

        form = self.request.form
        plone.protect.CheckAuthenticator(self.request.form)
        plone.protect.PostOnly(self.request.form)
        came_from = "came_from" in form and form["came_from"] or "add"
        wftool = getToolByName(self.context, "portal_workflow")
        uc = getToolByName(self.context, "uid_catalog")
        bsc = getToolByName(self.context, "bika_setup_catalog")

        errors = {}

        form_parts = json.loads(self.request.form["parts"])

        # First make a list of non-empty columns
        columns = []
        for column in range(int(form["col_count"])):
            name = "ar.%s" % column
            ar = form.get(name, None)
            if ar and "Analyses" in ar.keys():
                columns.append(column)

        if len(columns) == 0:
            ajax_form_error(errors, message=t(_("No analyses have been selected")))
            return json.dumps({"errors": errors})

        # Now some basic validation
        required_fields = [field.getName() for field in AnalysisRequestSchema.fields() if field.required]

        for column in columns:
            formkey = "ar.%s" % column
            ar = form[formkey]

            # check that required fields have values
            for field in required_fields:
                # This one is still special.
                if field in ["RequestID"]:
                    continue
                    # And these are not required if this is a secondary AR
                if ar.get("Sample", "") != "" and field in ["SamplingDate", "SampleType"]:
                    continue
                if not ar.get(field, ""):
                    ajax_form_error(errors, field, column)
        # Return errors if there are any
        if errors:
            return json.dumps({"errors": errors})

        # Get the prices from the form data
        prices = form.get("Prices", None)
        # Initialize the Anlysis Request collection
        ARs = []
        # if a new profile is created automatically,
        # this flag triggers the status message
        new_profile = None
        # The actual submission
        for column in columns:
            # Get partitions from the form data
            if form_parts:
                partitions = form_parts[str(column)]
            else:
                partitions = []
            # Get the form data using the appropriate form key
            formkey = "ar.%s" % column
            values = form[formkey].copy()
            # resolved values is formatted as acceptable by archetypes
            # widget machines
            resolved_values = {}
            for k, v in values.items():
                # Analyses, we handle that specially.
                if k == "Analyses":
                    continue
                # Insert the reference *_uid values instead of titles.
                if "_uid" in k:
                    v = values[k]
                    v = v.split(",") if v and "," in v else v
                    fname = k.replace("_uid", "")
                    resolved_values[fname] = v
                    continue
                # we want to write the UIDs and ignore the title values
                if k + "_uid" in values:
                    continue
                resolved_values[k] = values[k]
            # Get the analyses from the form data
            analyses = values["Analyses"]

            # Gather the specifications from the form
            specs = json.loads(form["copy_to_new_specs"]).get(str(column), {})
            if not specs:
                specs = json.loads(form["specs"]).get(str(column), {})
            if specs:
                specs = dicts_to_dict(specs, "keyword")
            # Modify the spec with all manually entered values
            for service_uid in analyses:
                min_element_name = "ar.%s.min.%s" % (column, service_uid)
                max_element_name = "ar.%s.max.%s" % (column, service_uid)
                error_element_name = "ar.%s.error.%s" % (column, service_uid)
                service_keyword = bsc(UID=service_uid)[0].getKeyword
                if min_element_name in form:
                    if service_keyword not in specs:
                        specs[service_keyword] = {}
                    specs[service_keyword]["keyword"] = service_keyword
                    specs[service_keyword]["min"] = form[min_element_name]
                    specs[service_keyword]["max"] = form[max_element_name]
                    specs[service_keyword]["error"] = form[error_element_name]

            # Selecting a template sets the hidden 'parts' field to template values.
            # Selecting a profile will allow ar_add.js to fill in the parts field.
            # The result is the same once we are here.
            if not partitions:
                partitions = [{"services": [], "container": None, "preservation": "", "separate": False}]
            # Apply DefaultContainerType to partitions without a container
            default_container_type = resolved_values.get("DefaultContainerType", None)
            if default_container_type:
                container_type = bsc(UID=default_container_type)[0].getObject()
                containers = container_type.getContainers()
                for partition in partitions:
                    if not partition.get("container", None):
                        partition["container"] = containers
            # Retrieve the catalogue reference to the client
            client = uc(UID=resolved_values["Client"])[0].getObject()
            # Create the Analysis Request
            ar = create_analysisrequest(
                client,
                self.request,
                resolved_values,
                analyses=analyses,
                partitions=partitions,
                specifications=specs.values(),
                prices=prices,
            )
            # Add the created analysis request to the list
            ARs.append(ar.getId())
        # Display the appropriate message after creation
        if len(ARs) > 1:
            message = _(
                "Analysis requests ${ARs} were successfully created.", mapping={"ARs": safe_unicode(", ".join(ARs))}
            )
        else:
            message = _("Analysis request ${AR} was successfully created.", mapping={"AR": safe_unicode(ARs[0])})
        self.context.plone_utils.addPortalMessage(message, "info")
        # Automatic label printing
        # Won't print labels for Register on Secondary ARs
        new_ars = None
        if came_from == "add":
            new_ars = [ar for ar in ARs if ar[-2:] == "01"]
        if "register" in self.context.bika_setup.getAutoPrintStickers() and new_ars:
            return json.dumps(
                {
                    "success": message,
                    "stickers": new_ars,
                    "stickertemplate": self.context.bika_setup.getAutoStickerTemplate(),
                }
            )
        else:
            return json.dumps({"success": message})