| Conditions | 19 |
| Total Lines | 134 |
| Code Lines | 65 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like bika.lims.utils.analysisrequest.create_analysisrequest() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # -*- coding: utf-8 -*- |
||
| 36 | def create_analysisrequest(client, request, values, analyses=None, |
||
| 37 | partitions=None, specifications=None, prices=None): |
||
| 38 | """This is meant for general use and should do everything necessary to |
||
| 39 | create and initialise an AR and any other required auxilliary objects |
||
| 40 | (Sample, SamplePartition, Analysis...) |
||
| 41 | |||
| 42 | :param client: |
||
| 43 | The container (Client) in which the ARs will be created. |
||
| 44 | :param request: |
||
| 45 | The current Request object. |
||
| 46 | :param values: |
||
| 47 | a dict, where keys are AR|Sample schema field names. |
||
| 48 | :param analyses: |
||
| 49 | Analysis services list. If specified, augments the values in |
||
| 50 | values['Analyses']. May consist of service objects, UIDs, or Keywords. |
||
| 51 | :param partitions: |
||
| 52 | A list of dictionaries, if specific partitions are required. If not |
||
| 53 | specified, AR's sample is created with a single partition. |
||
| 54 | :param specifications: |
||
| 55 | These values augment those found in values['Specifications'] |
||
| 56 | :param prices: |
||
| 57 | Allow different prices to be set for analyses. If not set, prices |
||
| 58 | are read from the associated analysis service. |
||
| 59 | """ |
||
| 60 | # Don't pollute the dict param passed in |
||
| 61 | values = dict(values.items()) |
||
| 62 | |||
| 63 | # Create new sample or locate the existing for secondary AR |
||
| 64 | secondary = False |
||
| 65 | sample = None |
||
| 66 | if not values.get('Sample', False): |
||
| 67 | sample = create_sample(client, request, values) |
||
| 68 | else: |
||
| 69 | sample = get_sample_from_values(client, values) |
||
| 70 | secondary = True |
||
| 71 | |||
| 72 | # Create the Analysis Request |
||
| 73 | ar = _createObjectByType('AnalysisRequest', client, tmpID()) |
||
| 74 | |||
| 75 | # Set some required fields manually before processForm is called |
||
| 76 | ar.setSample(sample) |
||
| 77 | values['Sample'] = sample |
||
| 78 | ar.processForm(REQUEST=request, values=values) |
||
| 79 | ar.edit(RequestID=ar.getId()) |
||
| 80 | |||
| 81 | # Set analysis request analyses. 'Analyses' param are analyses services |
||
| 82 | analyses = analyses if analyses else [] |
||
| 83 | service_uids = get_services_uids( |
||
| 84 | context=client, analyses_serv=analyses, values=values) |
||
| 85 | # processForm already has created the analyses, but here we create the |
||
| 86 | # analyses with specs and prices. This function, even it is called 'set', |
||
| 87 | # deletes the old analyses, so eventually we obtain the desired analyses. |
||
| 88 | ar.setAnalyses(service_uids, prices=prices, specs=specifications) |
||
| 89 | analyses = ar.getAnalyses(full_objects=True) |
||
| 90 | |||
| 91 | # Create sample partitions |
||
| 92 | if not partitions: |
||
| 93 | partitions = values.get('Partitions', |
||
| 94 | [{'services': service_uids}]) |
||
| 95 | |||
| 96 | part_num = 0 |
||
| 97 | prefix = sample.getId() + "-P" |
||
| 98 | if secondary: |
||
| 99 | # Always create new partitions if is a Secondary AR, cause it does |
||
| 100 | # not make sense to reuse the partitions used in a previous AR! |
||
| 101 | sparts = sample.getSamplePartitions() |
||
| 102 | for spart in sparts: |
||
| 103 | spartnum = int(spart.getId().split(prefix)[1]) |
||
| 104 | if spartnum > part_num: |
||
| 105 | part_num = spartnum |
||
| 106 | |||
| 107 | for n, partition in enumerate(partitions): |
||
| 108 | # Calculate partition id |
||
| 109 | partition_id = '%s%s' % (prefix, part_num + 1) |
||
| 110 | partition['part_id'] = partition_id |
||
| 111 | # Point to or create sample partition |
||
| 112 | if partition_id in sample.objectIds(): |
||
| 113 | partition['object'] = sample[partition_id] |
||
| 114 | else: |
||
| 115 | partition['object'] = create_samplepartition( |
||
| 116 | sample, |
||
| 117 | partition, |
||
| 118 | analyses |
||
| 119 | ) |
||
| 120 | part_num += 1 |
||
| 121 | |||
| 122 | # At this point, we have a fully created AR, with a Sample, Partitions and |
||
| 123 | # Analyses, but the state of all them is the initial ("sample_registered"). |
||
| 124 | # We can now transition the whole thing (instead of doing it manually for |
||
| 125 | # each object we created). After and Before transitions will take care of |
||
| 126 | # cascading and promoting the transitions in all the objects "associated" |
||
| 127 | # to this Analysis Request. |
||
| 128 | sampling_workflow_enabled = sample.getSamplingWorkflowEnabled() |
||
| 129 | action = 'no_sampling_workflow' |
||
| 130 | if sampling_workflow_enabled: |
||
| 131 | action = 'sampling_workflow' |
||
| 132 | # Transition the Analysis Request and related objects to "sampled" (if |
||
| 133 | # sampling workflow not enabled) or to "to_be_sampled" statuses. |
||
| 134 | doActionFor(ar, action) |
||
| 135 | |||
| 136 | if secondary: |
||
| 137 | # If secondary AR, then we need to manually transition the AR (and its |
||
| 138 | # children) to fit with the Sample Partition's current state |
||
| 139 | sampleactions = getReviewHistoryActionsList(sample) |
||
| 140 | doActionsFor(ar, sampleactions) |
||
| 141 | # We need a workaround here in order to transition partitions. |
||
| 142 | # auto_no_preservation_required and auto_preservation_required are |
||
| 143 | # auto transitions applied to analysis requests, but partitions don't |
||
| 144 | # have them, so we need to replace them by the sample_workflow |
||
| 145 | # equivalent. |
||
| 146 | if 'auto_no_preservation_required' in sampleactions: |
||
| 147 | index = sampleactions.index('auto_no_preservation_required') |
||
| 148 | sampleactions[index] = 'sample_due' |
||
| 149 | elif 'auto_preservation_required' in sampleactions: |
||
| 150 | index = sampleactions.index('auto_preservation_required') |
||
| 151 | sampleactions[index] = 'to_be_preserved' |
||
| 152 | # We need to transition the partition manually |
||
| 153 | # Transition pre-preserved partitions |
||
| 154 | for partition in partitions: |
||
| 155 | part = partition['object'] |
||
| 156 | doActionsFor(part, sampleactions) |
||
| 157 | |||
| 158 | # Transition pre-preserved partitions |
||
| 159 | for p in partitions: |
||
| 160 | if 'prepreserved' in p and p['prepreserved']: |
||
| 161 | part = p['object'] |
||
| 162 | doActionFor(part, 'preserve') |
||
| 163 | |||
| 164 | # Once the ar is fully created, check if there are rejection reasons |
||
| 165 | reject_field = values.get('RejectionReasons', '') |
||
| 166 | if reject_field and reject_field.get('checkbox', False): |
||
| 167 | doActionFor(ar, 'reject') |
||
| 168 | |||
| 169 | return ar |
||
| 170 | |||
| 444 |