senaite / senaite.jsonapi

RESTful JSON API for SENAITE
https://www.senaite.com
GNU General Public License v2.0
11 stars 19 forks source link

Creating AnalysisService error: 'NoneType' object has no attribute '__getitem__' #44

Open toropok opened 2 years ago

toropok commented 2 years ago

Steps to reproduce

POSTing minimal required message for AS creation:

{
    "title": "title",
    "description": "",
    "portal_type": "AnalysisService",
    "parent_path": "/senaite/bika_setup/bika_analysisservices",
    "Keyword": "TEST_AS",
    "Category": <category uid>,
    "PointOfCapture": "lab"
}

Current behavior

returns error message:

{"_runtime": 0.6848359107971191, "message": "'NoneType' object has no attribute '__getitem__'", "success": false}

The object seems to be created and can be accessed by direct URL, but not seen in AS folder.

If you open object by direct URL and press the save button - everything becomes fine and AS can be found in AS list

Expected behavior

  1. More details in error message;
  2. Create AS properly

Screenshot (optional)

toropok commented 2 years ago

we still digging it and figured out that this error comes from validation routine:

2021-11-29 15:06:14,496 INFO    [senaite.jsonapi:1523][waitress-1] VALIDATE EXCEPTION: 'MaxTimeAllowed' => Traceback (most recent call last):
  File "/home/senaite/senaitelims20/src/senaite.jsonapi/src/senaite/jsonapi/api.py", line 1520, in validate_object
    v = obj.validate(data=data)
  File "/home/senaite/buildout-cache/eggs/cp27mu/Products.Archetypes-1.16.4-py2.7.egg/Products/Archetypes/BaseObject.py", line 517, in validate
    errors=errors, data=data, metadata=metadata)
  File "/home/senaite/buildout-cache/eggs/cp27mu/Products.Archetypes-1.16.4-py2.7.egg/Products/Archetypes/Schema/__init__.py", line 629, in validate
    REQUEST=REQUEST)
  File "/home/senaite/senaitelims20/src/senaite.core/src/senaite/core/browser/fields/record.py", line 379, in validate
    res = self.validate_validators(value, instance, errors, **kwargs)
  File "/home/senaite/senaitelims20/src/senaite.core/src/senaite/core/browser/fields/record.py", line 396, in validate_validators
    **kwargs
  File "/home/senaite/buildout-cache/eggs/cp27mu/Products.validation-2.1.3-py2.7.egg/Products/validation/chain.py", line 137, in __call__
    result = validator(value, *args, **kwargs)
  File "/home/senaite/senaitelims20/src/senaite.core/src/bika/lims/validators.py", line 1006, in __call__
    value = request[fieldname]
KeyError: 'MaxTimeAllowed'

2021-11-29 15:06:14,513 INFO    [senaite.jsonapi:166][waitress-1] RESULTS: [<AnalysisService at /senaite20/bika_setup/bika_analysisservices/analysisservice-109>]

this call starts from validate_object() function in api.py:

1506:def validate_object(brain_or_object, **data):
1507:    """Validate the entire object
1508:
1509:    :param brain_or_object: A single catalog brain or content object
1510:    :type brain_or_object: ATContentType/DexterityContentType/CatalogBrain
1511:    :param data: The sharing dictionary as returned from the API
1512:    :type data: dict
1513:    :returns: invalidity status
1514:    :rtype: dict
1515:    """
1516:    obj = get_object(brain_or_object)
1517:    # Call the validator of AT Content Types
1518:    if is_at_content(obj):
1519:        try:
1520:            v = obj.validate(data=data)
1521:            return v
1522:        except Exception as ex:
1523:            logger.info("VALIDATE EXCEPTION: {} => {}".format(ex, traceback.format_exc()))
1524:        # return obj.validate(data=data)
1525:
1526:    return {}

and call DurationValidator in senaite.core/src/bika/lims/validators.py

991: class DurationValidator:
992:     """Simple stuff - just checking for integer values.
993:     """
994: 
995:     implements(IValidator)
996:     name = "duration_validator"
997: 
998:     def __call__(self, value, *args, **kwargs):
999: 
1000:        instance = kwargs['instance']
1001:        request = kwargs.get('REQUEST', {})
1002:        if not request: request = {}
1003:        fieldname = kwargs['field'].getName()
1004:        translate = getToolByName(instance, 'translation_service').translate
1005:        logger.info("DURATION VALIDATOR: instance = {}, request = {}, fieldname = {}, value = {}".format(instance, request, fieldname, value))
1006:        value = request[fieldname]
1007:        for v in value.values():
1008:            try:
1009:                int(v)
1010:            except:
1011:                return to_utf8(
1012:                    translate(_("Validation failed: Values must be numbers")))
1013:        return True

we're creating dumb object which contains only keyword and title. Why it tries to validate duration field which never being passed there?

maybe we're missing something? @ramonski

blainerb4 commented 2 years ago

Has there been a solution for this? I am having the same issue where it returns that error message. However, it still creates the analysis service as "New Analysis Service" in the UI without the values I had in the payload. See the JSON payload I am sending below:

{
“portal_type”: “AnalysisService”,
“Category”: {
“uid”: “6081d7c72450451fad4dd9128cf979de”
},
“title”: “red blood cell”,
“Keyword”: “red-bc”,
“ScientificName”: true,
“Price”: “15.00”,
“Accredited”: true,
“parent_path”: “/senaite/bika_setup/bika_analysisservices”
}