Passed
Push — 2.x ( a653ea...997a25 )
by Ramon
06:42
created

senaite.core.content.samplepoint   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 289
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 17
eloc 178
dl 0
loc 289
rs 10
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A SamplePoint.getLocation() 0 4 1
A SamplePoint.getSampleTypes() 0 4 1
A SamplePoint.setSampleTypes() 0 4 1
A SamplePoint.setLatitude() 0 5 1
A SamplePoint.getElevation() 0 4 1
A SamplePoint.setComposite() 0 4 1
A SamplePoint.getLongitude() 0 7 1
A SamplePoint.getLatitude() 0 7 1
A SamplePoint.setSamplingFrequency() 0 4 1
A SamplePoint.getSamplingFrequency() 0 4 1
A SamplePoint.setLongitude() 0 5 1
A SamplePoint.getComposite() 0 4 1
A SamplePoint.getAttachmentFile() 0 4 1
A SamplePoint.setLocation() 0 4 1
A SamplePoint.getRawSampleTypes() 0 4 1
A SamplePoint.setElevation() 0 4 1
A SamplePoint.setAttachmentFile() 0 4 1
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of SENAITE.CORE.
4
#
5
# SENAITE.CORE is free software: you can redistribute it and/or modify it under
6
# the terms of the GNU General Public License as published by the Free Software
7
# Foundation, version 2.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
# details.
13
#
14
# You should have received a copy of the GNU General Public License along with
15
# this program; if not, write to the Free Software Foundation, Inc., 51
16
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
#
18
# Copyright 2018-2024 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
from AccessControl import ClassSecurityInfo
22
from bika.lims import senaiteMessageFactory as _
23
from bika.lims.interfaces import IDeactivable
24
from plone.autoform import directives
25
from plone.namedfile.field import NamedBlobFile
26
from plone.supermodel import model
27
from Products.CMFCore import permissions
28
from senaite.core.api import geo
29
from senaite.core.catalog import SETUP_CATALOG
30
from senaite.core.content.base import Container
31
from senaite.core.content.mixins import ClientAwareMixin
32
from senaite.core.interfaces import ISamplePoint
33
from senaite.core.schema import DurationField
34
from senaite.core.schema import GPSCoordinatesField
35
from senaite.core.schema import UIDReferenceField
36
from senaite.core.schema.coordinatefield import SUBFIELDS as COORDINATE_FIELDS
37
from senaite.core.z3cform.widgets.uidreference import UIDReferenceWidgetFactory
38
from zope import schema
39
from zope.interface import implementer
40
41
42
class ISamplePointSchema(model.Schema):
43
    """Schema interface
44
    """
45
46
    model.fieldset(
47
        "location",
48
        label=_(u"fieldset_samplepoint_location", default=u"Location"),
49
        fields=[
50
            "location",
51
            "elevation",
52
        ]
53
    )
54
55
    title = schema.TextLine(
56
        title=_(
57
            u"title_samplepoint_title",
58
            default=u"Name"
59
        ),
60
        required=True,
61
    )
62
63
    description = schema.Text(
64
        title=_(
65
            u"title_samplepoint_description",
66
            default=u"Description"
67
        ),
68
        required=False,
69
    )
70
71
    location = GPSCoordinatesField(
72
        title=_(
73
            u"title_samplepoint_location",
74
            default=u"Location",
75
        ),
76
        description=_(
77
            u"description_samplepoint_location",
78
            default=u"The geographical point or area from which samples are "
79
                    u"taken for further analysis. It plays a pivotal role in "
80
                    u"research as it can significantly influence the results "
81
                    u"and conclusions drawn from the study."
82
        ),
83
        required=False,
84
    )
85
86
    elevation = schema.TextLine(
87
        title=_(
88
            u'title_samplepoint_elevation',
89
            default=u"Elevation"
90
        ),
91
        description=_(
92
            u"description_samplepoint_elevation",
93
            default=u"The height or depth at which the sample has to be taken"
94
        ),
95
        required=False,
96
    )
97
98
    sampling_frequency = DurationField(
99
        title=_(
100
            u"title_samplepoint_sampling_frequency",
101
            default=u"Sampling Frequency"
102
        ),
103
        description=_(
104
            u"description_samplepoint_sampling_frequency",
105
            default=u"If a sample is taken periodically at this sample point, "
106
                    u"enter frequency here, e.g. weekly"
107
        ),
108
        required=False,
109
    )
110
111
    directives.widget(
112
        "sample_types",
113
        UIDReferenceWidgetFactory,
114
        catalog=SETUP_CATALOG,
115
        query={
116
            "is_active": True,
117
            "sort_on": "title",
118
            "sort_order": "ascending",
119
        },
120
    )
121
    sample_types = UIDReferenceField(
122
        title=_(
123
            u"title_samplepoint_sampling_sample_types",
124
            default=u"Sample Types"
125
        ),
126
        description=_(
127
            u"description_samplepoint_sampling_sample_types",
128
            default=u"The list of sample types that can be collected "
129
                    u"at this sample point. The field for the selection of "
130
                    u"a sample point in sample creation and edit forms "
131
                    u"will be filtered in accordance. Still, sample points "
132
                    u"that do not have any sample type assigned will "
133
                    u"always be available for selection, regardless of the "
134
                    u"type."
135
        ),
136
        relationship="SamplePointSampleType",
137
        allowed_types=("SampleType", ),
138
        multi_valued=True,
139
        required=False,
140
    )
141
142
    composite = schema.Bool(
143
        title=_(
144
            u"title_samplepoint_composite",
145
            default=u"Composite"
146
        ),
147
        description=_(
148
            u"description_samplepoint_composite",
149
            default=u"Check this box if the samples taken at this point are "
150
                    u"'composite' and put together from more than one sub "
151
                    u"sample, e.g. several surface samples from a dam mixed "
152
                    u"together to be a representative sample for the dam. The "
153
                    u"default, unchecked, indicates 'grab' samples"
154
        ),
155
        required=False,
156
    )
157
158
    attachment_file = NamedBlobFile(
159
        title=_(
160
            u"title_samplepoint_attachment_file",
161
            default=u"Attachment"
162
        ),
163
        required=False,
164
    )
165
166
167
@implementer(ISamplePoint, ISamplePointSchema, IDeactivable)
168
class SamplePoint(Container, ClientAwareMixin):
169
    """Sample point
170
    """
171
    # Catalogs where this type will be catalogued
172
    _catalogs = [SETUP_CATALOG]
173
174
    security = ClassSecurityInfo()
175
176
    @security.protected(permissions.View)
177
    def getLatitude(self):
178
        # mimics the coordinate field accessor
179
        location = self.getLocation()
180
        latitude = location.get("latitude")
181
        default_dms = dict.fromkeys(COORDINATE_FIELDS, "")
182
        return geo.to_latitude_dms(latitude, default=default_dms)
183
184
    @security.protected(permissions.ModifyPortalContent)
185
    def setLatitude(self, value):
186
        location = self.getLocation()
187
        location["latitude"] = value
188
        self.setLocation(location)
189
190
    # BBB: AT schema field property
191
    Latitude = property(getLatitude, setLatitude)
192
193
    @security.protected(permissions.View)
194
    def getLongitude(self):
195
        # mimics the coordinate field accessor
196
        location = self.getLocation()
197
        longitude = location.get("longitude")
198
        default_dms = dict.fromkeys(COORDINATE_FIELDS, "")
199
        return geo.to_longitude_dms(longitude, default=default_dms)
200
201
    @security.protected(permissions.ModifyPortalContent)
202
    def setLongitude(self, value):
203
        location = self.getLocation()
204
        location["longitude"] = value
205
        self.setLocation(location)
206
207
    # BBB: AT schema field property
208
    Longitude = property(getLongitude, setLongitude)
209
210
    @security.protected(permissions.View)
211
    def getLocation(self):
212
        accessor = self.accessor("location")
213
        return accessor(self)
214
215
    @security.protected(permissions.ModifyPortalContent)
216
    def setLocation(self, value):
217
        mutator = self.mutator("location")
218
        mutator(self, value)
219
220
    # BBB: AT schema field property
221
    Location = property(getLocation, setLocation)
222
223
    @security.protected(permissions.View)
224
    def getElevation(self):
225
        accessor = self.accessor("elevation")
226
        return accessor(self)
227
228
    @security.protected(permissions.ModifyPortalContent)
229
    def setElevation(self, value):
230
        mutator = self.mutator("elevation")
231
        mutator(self, value)
232
233
    # BBB: AT schema field property
234
    Elevation = property(getElevation, setElevation)
235
236
    @security.protected(permissions.View)
237
    def getSamplingFrequency(self):
238
        accessor = self.accessor("sampling_frequency")
239
        return accessor(self)
240
241
    @security.protected(permissions.ModifyPortalContent)
242
    def setSamplingFrequency(self, value):
243
        mutator = self.mutator("sampling_frequency")
244
        mutator(self, value)
245
246
    # BBB: AT schema field property
247
    SamplingFrequency = property(getSamplingFrequency, setSamplingFrequency)
248
249
    @security.protected(permissions.View)
250
    def getRawSampleTypes(self):
251
        accessor = self.accessor("sample_types", raw=True)
252
        return accessor(self) or []
253
254
    @security.protected(permissions.View)
255
    def getSampleTypes(self):
256
        accessor = self.accessor("sample_types")
257
        return accessor(self) or []
258
259
    @security.protected(permissions.ModifyPortalContent)
260
    def setSampleTypes(self, value):
261
        mutator = self.mutator("sample_types")
262
        mutator(self, value)
263
264
    @security.protected(permissions.View)
265
    def getComposite(self):
266
        accessor = self.accessor("composite")
267
        return accessor(self)
268
269
    @security.protected(permissions.ModifyPortalContent)
270
    def setComposite(self, value):
271
        mutator = self.mutator("composite")
272
        mutator(self, value)
273
274
    # BBB: AT schema field property
275
    Composite = property(getComposite, setComposite)
276
277
    @security.protected(permissions.View)
278
    def getAttachmentFile(self):
279
        accessor = self.accessor("attachment_file")
280
        return accessor(self)
281
282
    @security.protected(permissions.ModifyPortalContent)
283
    def setAttachmentFile(self, value):
284
        mutator = self.mutator("attachment_file")
285
        mutator(self, value)
286
287
    # BBB: AT schema field property
288
    AttachmentFile = property(getAttachmentFile, setAttachmentFile)
289