-
Notifications
You must be signed in to change notification settings - Fork 171
/
Copy pathbikasetup.py
855 lines (824 loc) · 30.8 KB
/
bikasetup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
# -*- coding: utf-8 -*-
#
# This file is part of Bika LIMS
#
# Copyright 2011-2017 by it's authors.
# Some rights reserved. See LICENSE.txt, AUTHORS.txt.
import sys
from AccessControl import ClassSecurityInfo
from zope.interface import implements
from plone.app.folder import folder
from Products.CMFCore.utils import getToolByName
from Products.ATExtensions.ateapi import RecordsField
from Products.Archetypes.atapi import Schema
from Products.Archetypes.atapi import registerType
from Products.Archetypes.atapi import BooleanField
from Products.Archetypes.atapi import BooleanWidget
from Products.Archetypes.atapi import DecimalWidget
from Products.Archetypes.atapi import FixedPointField
from Products.Archetypes.atapi import IntegerField
from Products.Archetypes.atapi import IntegerWidget
from Products.Archetypes.atapi import LinesField
from Products.Archetypes.atapi import MultiSelectionWidget
from Products.Archetypes.atapi import ReferenceField
from Products.Archetypes.atapi import ReferenceWidget
from Products.Archetypes.atapi import SelectionWidget
from Products.Archetypes.atapi import StringField
from Products.Archetypes.atapi import StringWidget
from Products.Archetypes.atapi import TextAreaWidget
from Products.Archetypes.atapi import TextField
from Products.Archetypes.utils import DisplayList
from Products.Archetypes.utils import IntDisplayList
from Products.Archetypes.references import HoldingReference
from archetypes.referencebrowserwidget import ReferenceBrowserWidget
from bika.lims.browser.fields import DurationField
from bika.lims.browser.widgets import DurationWidget
from bika.lims.browser.widgets import RecordsWidget
from bika.lims.browser.widgets import RejectionSetupWidget
from bika.lims.content.bikaschema import BikaFolderSchema
from bika.lims.interfaces import IBikaSetup
from bika.lims.interfaces import IHaveNoBreadCrumbs
from bika.lims.vocabularies import getStickerTemplates as _getStickerTemplates
from bika.lims.config import ARIMPORT_OPTIONS
from bika.lims.config import ATTACHMENT_OPTIONS
from bika.lims.config import CURRENCIES
from bika.lims.config import DECIMAL_MARKS
from bika.lims.config import DEFAULT_AR_SPECS
from bika.lims.config import MULTI_VERIFICATION_TYPE
from bika.lims.config import PROJECTNAME
from bika.lims.config import SCINOTATION_OPTIONS
from bika.lims.config import WORKSHEET_LAYOUT_OPTIONS
from bika.lims.locales import COUNTRIES
from bika.lims import bikaMessageFactory as _
class PrefixesField(RecordsField):
"""A list of prefixes per portal_type
"""
_properties = RecordsField._properties.copy()
_properties.update({
'type': 'prefixes',
'subfields': ('portal_type', 'prefix', 'separator', 'padding', 'sequence_start'),
'subfield_labels': {'portal_type': 'Portal type',
'prefix': 'Prefix',
'separator': 'Prefix Separator',
'padding': 'Padding',
'sequence_start': 'Sequence Start'},
'subfield_readonly': {'portal_type': False,
'prefix': False,
'padding': False,
'separator': False,
'sequence_start': False},
'subfield_sizes': {'portal_type': 32,
'prefix': 12,
'padding': 12,
'separator': 5,
'sequence_start': 12},
'subfield_types': {'padding': 'int',
'sequence_start': 'int'},
})
security = ClassSecurityInfo()
STICKER_AUTO_OPTIONS = DisplayList((
('None', _('None')),
('register', _('Register')),
('receive', _('Receive')),
))
schema = BikaFolderSchema.copy() + Schema((
IntegerField(
'PasswordLifetime',
schemata="Security",
required=1,
default=0,
widget=IntegerWidget(
label=_("Password lifetime"),
description=_("The number of days before a password expires. 0 disables password expiry"),
)
),
IntegerField(
'AutoLogOff',
schemata="Security",
required=1,
default=0,
widget=IntegerWidget(
label=_("Automatic log-off"),
description=_(
"The number of minutes before a user is automatically logged off. "
"0 disables automatic log-off"),
)
),
BooleanField(
'AllowClerksToEditClients',
schemata="Security",
default=False,
widget=BooleanWidget(
label=_("Allow Lab Clerks to create and edit clients"),
)
),
BooleanField(
'RestrictWorksheetUsersAccess',
schemata="Security",
default=True,
widget=BooleanWidget(
label=_("Allow access to worksheets only to assigned analysts"),
description=_("If unchecked, analysts will have access to all worksheets.")
)
),
BooleanField(
'RestrictWorksheetManagement',
schemata="Security",
default=True,
widget=BooleanWidget(
label=_("Only lab managers can create and manage worksheets"),
description=_("If unchecked, analysts and lab clerks will "
"be able to manage Worksheets, too. If the "
"users have restricted access only to those "
"worksheets for which they are assigned, "
"this option will be checked and readonly.")
)
),
BooleanField(
'ShowNewReleasesInfo',
schemata="Security",
default=True,
widget=BooleanWidget(
label=_("Display an alert on new releases of Bika LIMS"),
)
),
BooleanField(
'ShowPrices',
schemata="Accounting",
default=True,
widget=BooleanWidget(
label=_("Include and display pricing information"),
)
),
StringField(
'Currency',
schemata="Accounting",
required=1,
vocabulary=CURRENCIES,
default='ZAR',
widget=SelectionWidget(
label=_("Currency"),
description=_("Select the currency the site will use to display prices."),
format='select',
)
),
StringField(
'DefaultCountry',
schemata="Accounting",
required=1,
vocabulary='getCountries',
default='',
widget=SelectionWidget(
label=_("Country"),
description=_("Select the country the site will show by default"),
format='select',
)
),
FixedPointField(
'MemberDiscount',
schemata="Accounting",
default='33.33',
widget=DecimalWidget(
label=_("Member discount %"),
description=_(
"The discount percentage entered here, is applied to the prices for clients "
"flagged as 'members', normally co-operative members or associates deserving "
"of this discount"),
)
),
FixedPointField(
'VAT',
schemata="Accounting",
default='14.00',
widget=DecimalWidget(
label=_("VAT %"),
description=_(
"Enter percentage value eg. 14.0. This percentage is applied system wide "
"but can be overwrittem on individual items"),
)
),
StringField(
'DecimalMark',
schemata="Results Reports",
vocabulary=DECIMAL_MARKS,
default=".",
widget=SelectionWidget(
label=_("Default decimal mark"),
description=_("Preferred decimal mark for reports."),
format='select',
)
),
StringField(
'ScientificNotationReport',
schemata="Results Reports",
default='1',
vocabulary=SCINOTATION_OPTIONS,
widget=SelectionWidget(
label=_("Default scientific notation format for reports"),
description=_("Preferred scientific notation format for reports"),
format='select',
)
),
IntegerField(
'MinimumResults',
schemata="Results Reports",
required=1,
default=5,
widget=IntegerWidget(
label=_("Minimum number of results for QC stats calculations"),
description=_(
"Using too few data points does not make statistical sense. "
"Set an acceptable minimum number of results before QC statistics "
"will be calculated and plotted"),
)
),
BooleanField(
'IncludePreviousFromBatch',
schemata="Results Reports",
default=False,
widget=BooleanWidget(
label=_("Include Previous Results From Batch"),
description=_(
"If there are previous results for a service in the "
"same batch of Analysis Requests, they will be displayed "
"in the report.")
)
),
IntegerField(
'BatchEmail',
schemata="Results Reports",
required=1,
default=5,
widget=IntegerWidget(
label=_("Maximum columns per results email"),
description=_(
"Set the maximum number of analysis requests per results email. "
"Too many columns per email are difficult to read for some clients "
"who prefer fewer results per email"),
)
),
TextField(
'ResultFooter',
schemata="Results Reports",
default_content_type='text/plain',
allowed_content_types=('text/plain', ),
default_output_type="text/plain",
default="",
widget=TextAreaWidget(
label=_("Result Footer"),
description=_("This text will be appended to results reports."),
append_only=False,
),
),
# IntegerField('BatchFax',
# schemata = "Results Reports",
# required = 1,
# default = 4,
# widget = IntegerWidget(
# label=_("Maximum columns per results fax"),
# description = "Too many AR columns per fax will see the font size minimised and could "
# "render faxes illegible. 4 ARs maximum per page is recommended",
# )
# ),
# StringField('SMSGatewayAddress',
# schemata = "Results Reports",
# required = 0,
# widget = StringWidget(
# label=_("SMS Gateway Email Address"),
# description = "The email to SMS gateway address. Either a complete email address, "
# "or just the domain, e.g. '@2way.co.za', the contact's mobile phone "
# "number will be prepended to",
# )
# ),
BooleanField(
'SamplingWorkflowEnabled',
schemata="Analyses",
default=False,
widget=BooleanWidget(
label=_("Enable the Sampling workflow"),
description=_("Select this to activate the sample collection workflow steps.")
),
),
BooleanField(
'ScheduleSamplingEnabled',
schemata="Analyses",
default=False,
widget=BooleanWidget(
label=_("Enable the Schedule a Sampling functionality"),
description=_(
"Select this to allow a Sampling Coordinator to" +
" schedule a sampling. This functionality only takes effect" +
" when 'Sampling workflow' is active")
),
),
BooleanField(
'ShowPartitions',
schemata="Analyses",
default=True,
widget=BooleanWidget(
label=_("Display individual sample partitions "),
description=_("Turn this on if you want to work with sample partitions")
),
),
BooleanField(
'CategoriseAnalysisServices',
schemata="Analyses",
default=False,
widget=BooleanWidget(
label=_("Categorise analysis services"),
description=_("Group analysis services by category in the LIMS tables, helpful when the list is long")
),
),
BooleanField(
'EnableARSpecs',
schemata="Analyses",
default=True,
widget=BooleanWidget(
label=_("Enable AR Specifications"),
description=_(
"Analysis specifications which are edited directly on the "
"Analysis Request."),
),
),
StringField(
'DefaultARSpecs',
schemata="Analyses",
default='ar_specs',
vocabulary=DEFAULT_AR_SPECS,
widget=SelectionWidget(
label=_("Default AR Specifications"),
description=_(
"Choose the default specifications used for all AR views "
"to display alerts and notifications. These will also be "
"applied when an AR is published in permanent media, "
"e.g. PDF."),
format='select',
)
),
IntegerField(
'ExponentialFormatThreshold',
schemata="Analyses",
required=1,
default=7,
widget=IntegerWidget(
label=_("Exponential format threshold"),
description=_(
"Result values with at least this number of significant "
"digits are displayed in scientific notation using the "
"letter 'e' to indicate the exponent. The precision can be "
"configured in individual Analysis Services."),
)
),
BooleanField(
'EnableAnalysisRemarks',
schemata="Analyses",
default=False,
widget=BooleanWidget(
label=_("Add a remarks field to all analyses"),
description=_(
"If enabled, a free text field will be displayed close to "
"each analysis in results entry view"
)
),
),
BooleanField(
'SelfVerificationEnabled',
schemata="Analyses",
default=False,
widget=BooleanWidget(
label=_("Allow self-verification of results"),
description=_(
"If enabled, a user who submitted a result will also be able "
"to verify it. This setting only take effect for those users "
"with a role assigned that allows them to verify results "
"(by default, managers, labmanagers and verifiers)."
"This setting can be overrided for a given Analysis in "
"Analysis Service edit view. By default, disabled."),
),
),
IntegerField(
'NumberOfRequiredVerifications',
schemata="Analyses",
default=1,
vocabulary="_getNumberOfRequiredVerificationsVocabulary",
widget=SelectionWidget(
format="select",
label=_("Number of required verifications"),
description=_(
"Number of required verifications before a given result being "
"considered as 'verified'. This setting can be overrided for "
"any Analysis in Analysis Service edit view. By default, 1"),
),
),
StringField(
'TypeOfmultiVerification',
schemata="Analyses",
default='self_multi_enabled',
vocabulary=MULTI_VERIFICATION_TYPE,
widget=SelectionWidget(
label=_("Multi Verification type"),
description=_(
"Choose type of multiple verification for the same user."
"This setting can enable/disable verifying/consecutively verifying"
"more than once for the same user."),
format='select',
)
),
ReferenceField(
'DryMatterService',
schemata="Analyses",
required=0,
vocabulary_display_path_bound=sys.maxint,
allowed_types=('AnalysisService',),
relationship='SetupDryAnalysisService',
vocabulary='getAnalysisServices',
referenceClass=HoldingReference,
widget=ReferenceWidget(
label=_("Dry matter analysis"),
description=_("The analysis to be used for determining dry matter."),
)
),
LinesField(
'ARImportOption',
schemata="Analyses",
vocabulary=ARIMPORT_OPTIONS,
widget=MultiSelectionWidget(
visible=False,
label=_("AR Import options"),
description=_(
"'Classic' indicates importing analysis requests per sample and "
"analysis service selection. With 'Profiles', analysis profile keywords "
"are used to select multiple analysis services together"),
)
),
StringField(
'ARAttachmentOption',
schemata="Analyses",
default='p',
vocabulary=ATTACHMENT_OPTIONS,
widget=SelectionWidget(
format='select',
label=_("AR Attachment Option"),
description=_(
"The system wide default configuration to indicate "
"whether file attachments are required, permitted or not "
"per analysis request"),
)
),
StringField(
'AnalysisAttachmentOption',
schemata="Analyses",
default='p',
vocabulary=ATTACHMENT_OPTIONS,
widget=SelectionWidget(
format='select',
label=_("Analysis Attachment Option"),
description=_(
"Same as the above, but sets the default on analysis services. "
"This setting can be set per individual analysis on its "
"own configuration"),
)
),
DurationField(
'DefaultSampleLifetime',
schemata="Analyses",
required=1,
default={"days": 30, "hours": 0, "minutes": 0},
widget=DurationWidget(
label=_("Default sample retention period"),
description=_(
"The number of days before a sample expires and cannot be analysed "
"any more. This setting can be overwritten per individual sample type "
"in the sample types setup"),
)
),
StringField(
'ResultsDecimalMark',
schemata="Analyses",
vocabulary=DECIMAL_MARKS,
default=".",
widget=SelectionWidget(
label=_("Default decimal mark"),
description=_("Preferred decimal mark for results"),
format='select',
)
),
StringField(
'ScientificNotationResults',
schemata="Analyses",
default='1',
vocabulary=SCINOTATION_OPTIONS,
widget=SelectionWidget(
label=_("Default scientific notation format for results"),
description=_("Preferred scientific notation format for results"),
format='select',
)
),
StringField(
'WorksheetLayout',
schemata="Analyses",
default='1',
vocabulary=WORKSHEET_LAYOUT_OPTIONS,
widget=SelectionWidget(
label=_("Default layout in worksheet view"),
description=_("Preferred layout of the results entry table "
"in the Worksheet view. Classic layout displays "
"the Analysis Requests in rows and the analyses "
"in columns. Transposed layout displays the "
"Analysis Requests in columns and the analyses "
"in rows."),
format='select',
)
),
BooleanField(
'DashboardByDefault',
schemata="Analyses",
default=True,
widget=BooleanWidget(
label=_("Use Dashboard as default front page"),
description=_("Select this to activate the dashboard as a default front page.")
),
),
ReferenceField(
'LandingPage',
schemata="Analyses",
multiValued=0,
allowed_types=('Document', ),
relationship='SetupLandingPage',
widget=ReferenceBrowserWidget(
label=_("Landing Page"),
description=_("The selected landing page is displayed for non-authenticated users "
"and if the Dashboard is not selected as the default front page. "
"If no landing page is selected, the default Bika frontpage is displayed."),
allow_search=1,
allow_browse=1,
startup_directory='/',
force_close_on_insert=1,
default_search_index='SearchableText',
base_query={'review_state': 'published'},
),
),
StringField(
'AutoPrintStickers',
schemata="Stickers",
vocabulary=STICKER_AUTO_OPTIONS,
widget=SelectionWidget(
format='select',
label=_("Automatic sticker printing"),
description=_(
"Select 'Register' if you want stickers to be automatically printed when "
"new ARs or sample records are created. Select 'Receive' to print stickers "
"when ARs or Samples are received. Select 'None' to disable automatic printing"),
)
),
StringField(
'AutoStickerTemplate',
schemata="Stickers",
vocabulary="getStickerTemplates",
widget=SelectionWidget(
format='select',
label=_("Sticker templates"),
description=_("Select which sticker to print when automatic sticker printing is enabled"),
)
),
StringField(
'SmallStickerTemplate',
schemata="Stickers",
vocabulary="getStickerTemplates",
default="Code_128_1x48mm.pt",
widget=SelectionWidget(
format='select',
label=_("Small sticker"),
description=_("Select which sticker should be used as the 'small' sticker by default")
)
),
StringField(
'LargeStickerTemplate',
schemata="Stickers",
vocabulary="getStickerTemplates",
default="Code_128_1x72mm.pt",
widget=SelectionWidget(
format='select',
label=_("Large sticker"),
description=_("Select which sticker should be used as the 'large' sticker by default")
)
),
PrefixesField(
'Prefixes',
schemata="ID Server",
default=[{'portal_type': 'ARImport', 'prefix': 'AI', 'padding': '4', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'AnalysisRequest', 'prefix': 'client', 'padding': '0', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'Client', 'prefix': 'client', 'padding': '0', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'Batch', 'prefix': 'batch', 'padding': '0', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'DuplicateAnalysis', 'prefix': 'DA', 'padding': '0', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'Invoice', 'prefix': 'I', 'padding': '4', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'ReferenceAnalysis', 'prefix': 'RA', 'padding': '4', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'ReferenceSample', 'prefix': 'RS', 'padding': '4', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'SupplyOrder', 'prefix': 'O', 'padding': '3', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'Worksheet', 'prefix': 'WS', 'padding': '4', 'separator': '-', 'sequence_start': '0'},
{'portal_type': 'Pricelist', 'prefix': 'PL', 'padding': '4', 'separator': '-', 'sequence_start': '0'},
],
# fixedSize=8,
widget=RecordsWidget(
label=_("Prefixes"),
description=_(
"Define the prefixes for the unique sequential IDs the system issues for "
"objects. In the 'Padding' field, indicate with how many leading zeros the "
"numbers must be padded. E.g. a prefix of WS for worksheets with padding of "
"4, will see them numbered from WS-0001 to WS-9999. Sequence Start "
"indicates the number from which the next ID should start. This is "
"set only if it is greater than existing id numbers. Note that the "
"gap created by jumping IDs cannot be refilled. NB: Note that samples "
"and analysis requests are prefixed with sample type abbreviations and are "
"not configured in this table - their padding can be set in the specified "
"fields below"),
allowDelete=False,
)
),
BooleanField(
'YearInPrefix',
schemata="ID Server",
default=False,
widget=BooleanWidget(
label=_("Include year in ID prefix"),
description=_("Adds a two-digit year after the ID prefix")
),
),
IntegerField(
'SampleIDPadding',
schemata="ID Server",
required=1,
default=4,
widget=IntegerWidget(
label=_("Sample ID Padding"),
description=_("The length of the zero-padding for Sample IDs"),
)
),
IntegerField(
'SampleIDSequenceStart',
schemata="ID Server",
required=1,
default=0,
widget=IntegerWidget(
label=_("Sample ID Sequence Start"),
description=_(
"The number from which the next id should start. This "
"is set only if it is greater than existing id numbers. "
"Note that the resultant gap between IDs cannot be filled."),
)
),
IntegerField(
'ARIDPadding',
schemata="ID Server",
required=1,
default=2,
widget=IntegerWidget(
label=_("AR ID Padding"),
description=_("The length of the zero-padding for the AR number in AR IDs"),
)
),
BooleanField(
'ExternalIDServer',
schemata="ID Server",
default=False,
widget=BooleanWidget(
label=_("Use external ID server"),
description=_(
"Check this if you want to use a separate ID server. "
"Prefixes are configurable separately in each Bika site")
),
),
StringField(
'IDServerURL',
schemata="ID Server",
widget=StringWidget(
label=_("ID Server URL"),
description=_("The full URL: http://URL/path:port")
),
),
RecordsField(
'RejectionReasons',
schemata="Analyses",
widget=RejectionSetupWidget(
label=_("Enable the rejection workflow"),
description=_("Select this to activate the rejection workflow "
"for Samples and Analysis Requests. A 'Reject' "
"option will be displayed in the actions menu for "
"these objects.")
),
),
BooleanField(
'NotifyOnRejection',
schemata="Notifications",
default=False,
widget=BooleanWidget(
label=_("Email notification on rejection"),
description=_("Select this to activate automatic notifications "
"via email to the Client when a Sample or Analysis "
"Request is rejected.")
),
),
BooleanField(
'NotifyOnARRetract',
schemata="Notifications",
default=True,
widget=BooleanWidget(
label=_("Email notification on AR retract"),
description=_("Select this to activate automatic notifications "
"via email to the Client and Lab Managers when an Analysis "
"Request is retracted.")
),
),
BooleanField(
'AllowDepartmentFiltering',
schemata="Security",
default=False,
widget=BooleanWidget(
label=_("Allow users to filter datas by department."),
)
),
))
schema['title'].validators = ()
schema['title'].widget.visible = False
# Update the validation layer after change the validator in runtime
schema['title']._validationLayer()
class BikaSetup(folder.ATFolder):
"""
"""
implements(IBikaSetup, IHaveNoBreadCrumbs)
schema = schema
security = ClassSecurityInfo()
# needed to access the field for the front-page Portlet for Anonymous, w/o
# making the whole Laboratory viewable by Anonymous.
# Only the permission "Access contents information" is needed
security.declarePublic('getAllowDepartmentFiltering')
def getAttachmentsPermitted(self):
"""Attachments permitted
"""
if self.getARAttachmentOption() in ['r', 'p'] \
or self.getAnalysisAttachmentOption() in ['r', 'p']:
return True
else:
return False
def getStickerTemplates(self):
"""Get the sticker templates
"""
out = [[t['id'], t['title']] for t in _getStickerTemplates()]
return DisplayList(out)
def getARAttachmentsPermitted(self):
"""AR attachments permitted
"""
if self.getARAttachmentOption() == 'n':
return False
else:
return True
def getAnalysisAttachmentsPermitted(self):
"""Analysis attachments permitted
"""
if self.getAnalysisAttachmentOption() == 'n':
return False
else:
return True
def getAnalysisServices(self):
"""
"""
bsc = getToolByName(self, 'bika_setup_catalog')
items = [('', '')] + [(o.UID, o.Title) for o in
bsc(portal_type='AnalysisService',
inactive_state='active')]
items.sort(lambda x, y: cmp(x[1], y[1]))
return DisplayList(list(items))
def getPrefixFor(self, portal_type):
"""Return the prefix for a portal_type.
If not found, simply uses the portal_type itself
"""
prefix = [p for p in self.getPrefixes() if p['portal_type'] == portal_type]
if prefix:
return prefix[0]['prefix']
else:
return portal_type
def getCountries(self):
items = [(x['ISO'], x['Country']) for x in COUNTRIES]
items.sort(lambda x, y: cmp(x[1], y[1]))
return items
def isRejectionWorkflowEnabled(self):
"""Return true if the rejection workflow is enabled (its checkbox is set)
"""
widget = self.getRejectionReasons()
# widget will be something like:
# [{'checkbox': u'on', 'textfield-2': u'b', 'textfield-1': u'c', 'textfield-0': u'a'}]
if len(widget) > 0:
checkbox = widget[0].get('checkbox', False)
return True if checkbox == 'on' and len(widget[0]) > 1 else False
else:
return False
def _getNumberOfRequiredVerificationsVocabulary(self):
"""
Returns a DisplayList with the available options for the
multi-verification list: '1', '2', '3', '4'
:return: DisplayList with the available options for the
multi-verification list
"""
items = [(1, '1'), (2, '2'), (3, '3'), (4, '4')]
return IntDisplayList(list(items))
registerType(BikaSetup, PROJECTNAME)