class SpotCheckFindings(EtoolsDataMartModel): TYPE_SPOT_CHECK = 'sc' TYPES = Choices((TYPE_SPOT_CHECK, _('Spot Check')), ) reference_number = models.CharField(max_length=100, blank=True, null=True) engagement_type = models.CharField( max_length=300, blank=True, null=True, choices=TYPES, db_index=True, ) created = models.DateField(blank=True, null=True) status = models.CharField(max_length=30, blank=True, null=True, choices=AuditEngagementConsts.DISPLAY_STATUSES, db_index=True) # Overview Section auditor = models.CharField(max_length=255, blank=True, null=True) auditor_number = models.CharField(max_length=30, blank=True, null=True) partner = JSONField(blank=True, null=True, default=dict) total_value = models.DecimalField(blank=True, null=True, default=0, decimal_places=2, max_digits=20) amount_refunded = models.DecimalField(blank=True, null=True, default=0, decimal_places=2, max_digits=20) write_off_required = models.DecimalField(blank=True, null=True, default=0, decimal_places=2, max_digits=20) pending_unsupported_amount = models.DecimalField(max_digits=20, decimal_places=2, blank=True, null=True) # Overview Card spotcheck_total_amount_tested = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=20) spotcheck_total_amount_of_ineligible_expenditure = models.DecimalField( null=True, blank=True, decimal_places=2, max_digits=20) additional_supporting_documentation_provided = models.DecimalField( blank=True, null=True, decimal_places=2, max_digits=20) justification_provided_and_accepted = models.DecimalField(blank=True, null=True, decimal_places=2, max_digits=20) sections = models.TextField(blank=True, null=True) sections_data = JSONField(blank=True, null=True, default=dict) # Report Section high_priority_findings = JSONField(blank=True, null=True, default=dict) low_priority_findings = JSONField(blank=True, null=True, default=dict) date_of_field_visit = models.DateField(blank=True, null=True) partner_contacted_at = models.DateField(blank=True, null=True) date_of_draft_report_to_ip = models.DateField(blank=True, null=True) date_of_comments_by_ip = models.DateField(blank=True, null=True) date_of_draft_report_to_unicef = models.DateField(blank=True, null=True) date_of_comments_by_unicef = models.DateField(blank=True, null=True) date_of_report_submit = models.DateField(blank=True, null=True) date_of_final_report = models.DateField(null=True, blank=True) date_of_cancel = models.DateField(blank=True, null=True) # Action Points action_points = JSONField(blank=True, null=True, default=dict) action_points_data = JSONField(blank=True, null=True, default=dict) loader = SpotCheckLoader() class Meta: ordering = ("id", ) class Options: source = AuditSpotcheck sync_deleted_records = lambda a: False depends = (Partner, ) mapping = dict( auditor="agreement.auditor_firm.name", auditor_number="agreement.auditor_firm.vendor_number", spotcheck_total_amount_tested="_impl.total_amount_tested", spotcheck_total_amount_of_ineligible_expenditure= "_impl.total_amount_of_ineligible_expenditure", partner="-", sections="-", pending_unsupported_amount='-', high_priority_findings="-", low_priority_findings="-", action_points='-', action_points_data='i', )
class Application(models.Model): """This model represents an application by a customer to P&W for a single permit, licence/permit, part 5, etc. """ APP_TYPE_CHOICES = Choices( (1, 'permit', ('Permit')), (2, 'licence', ('Licence/permit')), (3, 'part5', ('Part 5 - New Application')), (4, 'emergency', ('Emergency works')), (5, 'part5cr', ('Part 5 - Amendment Request')), (6, 'part5amend', ('Part 5 - Amendment Application')), (7, 'test', ('Test - Application')) ) APP_STATE_CHOICES = Choices( (1, 'draft', ('Draft')), (2, 'with_admin', ('With Admin Officer')), (3, 'with_referee', ('With Referrals')), (4, 'with_assessor', ('With Assessor')), (5, 'with_manager', ('With Manager')), (6, 'issued', ('Issued')), (7, 'issued_with_admin', ('Issued (with admin)')), (8, 'declined', ('Declined')), (9, 'new', ('New')), (10, 'approved', ('Approved')), (11, 'expird', ('Expired')), (12, 'with_director', ('With Director')), (13, 'with_exec', ('With Executive')), (14, 'completed', ('Completed')) ) APP_LOCATION_CHOICES = Choices( (0, 'onland', ('On Land')), (1, 'onwater', ('On Water')), (2, 'both', ('Both')), ) applicant = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='applicant') organisation = models.ForeignKey(Organisation, blank=True, null=True, on_delete=models.PROTECT) app_type = models.IntegerField(choices=APP_TYPE_CHOICES) assignee = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='assignee') state = models.IntegerField(choices=APP_STATE_CHOICES, default=APP_STATE_CHOICES.draft, editable=False) title = models.CharField(max_length=256) description = models.TextField(null=True, blank=True) submit_date = models.DateField() expire_date = models.DateField(blank=True, null=True) proposed_commence = models.DateField(null=True, blank=True) proposed_end = models.DateField(null=True, blank=True) issue_date = models.DateField(null=True, blank=True) cost = models.CharField(max_length=256, null=True, blank=True) project_no = models.CharField(max_length=256, null=True, blank=True) related_permits = models.TextField(null=True, blank=True) over_water = models.BooleanField(default=False) records = models.ManyToManyField(Record, blank=True, related_name='records') vessels = models.ManyToManyField(Vessel, blank=True) purpose = models.ForeignKey(ApplicationPurpose, null=True, blank=True) max_participants = models.IntegerField(null=True, blank=True) proposed_location = models.SmallIntegerField(choices=APP_LOCATION_CHOICES, null=True, blank=True) address = models.TextField(null=True, blank=True) location_route_access = models.ForeignKey(Record, null=True, blank=True, related_name='location_route_access') jetties = models.TextField(null=True, blank=True) jetty_dot_approval = models.NullBooleanField(default=None) jetty_dot_approval_expiry = models.DateField(null=True, blank=True) drop_off_pick_up = models.TextField(null=True, blank=True) food = models.NullBooleanField(default=None) beverage = models.NullBooleanField(default=None) byo_alcohol = models.NullBooleanField(default=None) sullage_disposal = models.TextField(null=True, blank=True) waste_disposal = models.TextField(null=True, blank=True) refuel_location_method = models.TextField(null=True, blank=True) berth_location = models.TextField(null=True, blank=True) anchorage = models.TextField(null=True, blank=True) operating_details = models.TextField(null=True, blank=True) cert_survey = models.ForeignKey(Record, blank=True, null=True, related_name='cert_survey') cert_public_liability_insurance = models.ForeignKey(Record, blank=True, null=True, related_name='cert_public_liability_insurace') risk_mgmt_plan = models.ForeignKey(Record, blank=True, null=True, related_name='risk_mgmt_plan') safety_mgmt_procedures = models.ForeignKey(Record, blank=True, null=True, related_name='safety_mgmt_plan') brochures_itineries_adverts = models.ManyToManyField(Record, blank=True, related_name='brochures_itineries_adverts') land_owner_consent = models.ManyToManyField(Record, blank=True, related_name='land_owner_consent') deed = models.ForeignKey(Record, blank=True, null=True, related_name='deed') submitted_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='Submitted_by') river_lease_require_river_lease = models.NullBooleanField(default=None, null=True, blank=True) river_lease_scan_of_application = models.ForeignKey(Record, null=True, blank=True, related_name='river_lease_scan_of_application') river_lease_reserve_licence = models.NullBooleanField(default=None, null=True, blank=True) river_lease_application_number = models.CharField(max_length=30, null=True, blank=True) proposed_development_current_use_of_land = models.TextField(null=True, blank=True) proposed_development_plans = models.ManyToManyField(Record, blank=True, related_name='proposed_development_plans') proposed_development_description = models.TextField(null=True, blank=True) document_draft = models.ForeignKey(Record, null=True, blank=True, related_name='document_draft') document_new_draft = models.ForeignKey(Record, null=True, blank=True, related_name='document_newdraft') document_new_draft_v3 = models.ForeignKey(Record, null=True, blank=True, related_name='document_newdraftv3') document_draft_signed = models.ForeignKey(Record, null=True, blank=True, related_name='document_draft_signed') document_final = models.ForeignKey(Record, null=True, blank=True, related_name='document_final') document_final_signed = models.ForeignKey(Record, null=True, blank=True, related_name='document_final_signed') document_determination = models.ForeignKey(Record, null=True, blank=True, related_name='document_determination') document_completion = models.ForeignKey(Record, null=True, blank=True, related_name='document_completion') publish_documents = models.DateField(null=True, blank=True) publish_draft_report = models.DateField(null=True, blank=True) publish_final_report = models.DateField(null=True, blank=True) publish_determination_report = models.DateField(null=True, blank=True) routeid = models.CharField(null=True, blank=True, default=1, max_length=4) assessment_start_date = models.DateField(null=True, blank=True) group = models.ForeignKey(Group, null=True, blank=True, related_name='application_group_assignment') swan_river_trust_board_feedback = models.ForeignKey(Record, null=True, blank=True, related_name='document_swan_river_board_feedback') document_memo = models.ForeignKey(Record, null=True, blank=True, related_name='document_memo') document_briefing_note = models.ForeignKey(Record, null=True, blank=True, related_name='document_briefing_note') document_determination_approved = models.ForeignKey(Record, null=True, blank=True, related_name='document_determination_approved') approval_id = models.IntegerField(null=True, blank=True) assessed_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.PROTECT, related_name='assessed_by') def __str__(self): return 'Application {}: {} - {} ({})'.format( self.pk, self.get_app_type_display(), self.title, self.get_state_display()) def get_absolute_url(self): return reverse('application_detail', args=(self.pk,))
class Movimiento(TimeStampedModel): id_movimiento = models.CharField(unique=True, max_length=16) tipo_movimiento = models.ForeignKey(TipoMovimiento) referencia = models.ForeignKey(OrdenCompra, null=True) pedido = models.ForeignKey(Pedido, null=True) tipo_documento = models.ForeignKey(TipoDocumento, null=True) serie = models.CharField(max_length=15, null=True) numero = models.CharField(max_length=10, null=True) fecha_operacion = models.DateTimeField() almacen = models.ForeignKey(Almacen) oficina = models.ForeignKey(Oficina, null=True) trabajador = models.ForeignKey(Trabajador, null=True) productor = models.ForeignKey(Productor, null=True) observaciones = models.TextField(default='') STATUS = Choices( ('ACT', _('ACTIVO')), ('CANC', _('CANCELADA')), ) estado = models.CharField(choices=STATUS, default=STATUS.ACT, max_length=20) history = HistoricalRecords() def anterior(self): try: sig = Movimiento.objects.filter(pk__lt=self.pk).order_by('-pk')[0] except: sig = Movimiento.objects.all().last() return sig.pk def siguiente(self): try: ant = Movimiento.objects.filter(pk__gt=self.pk).order_by('pk')[0] except: ant = Movimiento.objects.all().first() return ant.pk def eliminar_referencia(self): orden = self.referencia requerimiento = None if orden.cotizacion is not None: requerimiento = orden.cotizacion.requerimiento detalles = DetalleMovimiento.objects.filter(movimiento=self) for detalle in detalles: detalle_orden_compra = detalle.detalle_orden_compra if detalle_orden_compra.detalle_cotizacion is not None: detalle_requerimiento = detalle_orden_compra.detalle_cotizacion.detalle_requerimiento detalle_requerimiento.cantidad_atendida = detalle_requerimiento.cantidad_atendida - detalle.cantidad detalle_requerimiento.establecer_estado_atendido() detalle_requerimiento.save() detalle_orden_compra.cantidad_ingresada = detalle_orden_compra.cantidad_ingresada - detalle.cantidad detalle_orden_compra.establecer_estado() detalle_orden_compra.save() orden.establecer_estado() orden.save() if requerimiento is not None: requerimiento.establecer_estado_atendido() requerimiento.save() def eliminar_pedido(self): pedido = self.pedido detalles = DetalleMovimiento.objects.filter(movimiento=self) for detalle in detalles: detalle_pedido = detalle.detalle_pedido detalle_pedido.cantidad_atendida = detalle_pedido.cantidad_atendida - detalle.cantidad detalle_pedido.establecer_estado_atendido() detalle_pedido.save() pedido.establecer_estado_atendido() pedido.save() def eliminar_detalles(self): DetalleMovimiento.objects.filter(movimiento=self).delete() def eliminar_kardex(self): movimiento = self almacen = movimiento.almacen detalle_kardex = Kardex.objects.filter(movimiento=movimiento, almacen=almacen) for kardex in detalle_kardex: control = ControlProductoAlmacen.objects.get( producto=kardex.producto, almacen=almacen) control.stock = control.stock - kardex.cantidad_ingreso control.save() kardex.delete() @property def total(self): total = 0 for detalle in DetalleMovimiento.objects.filter(movimiento=self): total = total + detalle.valor return total class Meta: permissions = ( ('ver_detalle_movimiento', 'Puede ver detalle de Movimiento'), ('ver_tabla_movimientos', 'Puede ver tabla de Movimientos'), ('ver_reporte_movimientos_excel', 'Puede ver Reporte de Movimientos en excel'), ) ordering = ['id_movimiento'] def __str__(self): return self.id_movimiento def save(self, *args, **kwargs): if self.id_movimiento == '': tipo = self.tipo_movimiento anio = self.fecha_operacion.year mov_ant = Movimiento.objects.filter( tipo_movimiento__incrementa=tipo.incrementa, fecha_operacion__year=anio).aggregate(Max('id_movimiento')) id_ant = mov_ant['id_movimiento__max'] if id_ant is None: aux = 1 else: aux = int(id_ant[-7:]) + 1 correlativo = str(aux).zfill(7) codigo = str(tipo.codigo[0:1]) + str(anio) + correlativo self.id_movimiento = codigo self.anio = self.fecha_operacion.year, self.mes = self.fecha_operacion.month, super(Movimiento, self).save()
class Article(StatusModel, AbstractLanguage): STATUS = Choices('verified', 'pending', 'rejected') title = models.CharField(_('title'), max_length=255) content = models.TextField(_('content'), blank=True) status = StatusField(_('status'), default='pending') published = MonitorField(_('published time'), monitor='status', when=['verified']) edited = MonitorField(_('edited time'), monitor='content') author = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('author')) tags = models.ManyToManyField('Tag', verbose_name=_('tags'), blank=True, related_name='articles') mentions = models.ManyToManyField(settings.AUTH_USER_MODEL, verbose_name=_('mentions'), related_name='mentioned_articles', blank=True) attachments = models.ManyToManyField('files.Attachment', verbose_name=_('attachments'), blank=True) is_article = models.BooleanField(_('is_article')) objects = ArticleQuerySet.as_manager() lang_objects = lang_queryset(ArticleQuerySet).as_manager() def reject(self): self.status = 'rejected' self.save() Notice.objects.send( self.author, _('Administrator rejects your article {target.title}.'), target=self, category='verification', keyword=('article', 'reject', self.id)) def accept(self): self.status = 'verified' self.save() Notice.objects.send( self.author, _('Administrator verified your article {target.title}.'), target=self, category='verification', keyword=('article', 'verify', self.id)) def save(self, *args, **kwargs): self.is_article = bool(self.content) return super(Article, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('articles:detail', kwargs={'article_id': self.id}) @property def url(self): return self.get_absolute_url() def article_tag(self): if self.is_article: return format_html('''<a href="#{}">{}</a>''', self.get_absolute_url(), self.title) else: return self.title def __str__(self): return self.title class Meta: permissions = [ ('can_verify', 'Can verify'), ] ordering = ('-published', '-edited') verbose_name = _('article') verbose_name_plural = _('articles')
class Plan(models.Model): objects = PlanManager() class INTERVALS(object): DAY = 'day' WEEK = 'week' MONTH = 'month' YEAR = 'year' INTERVAL_CHOICES = Choices( (INTERVALS.DAY, _('Day')), (INTERVALS.WEEK, _('Week')), (INTERVALS.MONTH, _('Month')), (INTERVALS.YEAR, _('Year'))) name = models.CharField(max_length=200, help_text='Display name of the plan.', db_index=True) interval = models.CharField( choices=INTERVAL_CHOICES, max_length=12, default=INTERVALS.MONTH, help_text='The frequency with which a subscription should be billed.') interval_count = models.PositiveIntegerField( help_text='The number of intervals between each subscription billing') amount = models.DecimalField( max_digits=19, decimal_places=4, validators=[MinValueValidator(0.0)], help_text='The amount in the specified currency to be charged on the ' 'interval specified.') currency = models.CharField( choices=currencies, max_length=4, default='USD', help_text='The currency in which the subscription will be charged.') trial_period_days = models.PositiveIntegerField( null=True, blank=True, help_text='Number of trial period days granted when subscribing a ' 'customer to this plan.', verbose_name='Trial days') generate_documents_on_trial_end = models.NullBooleanField( help_text= "If this is set to True, then billing documents will be generated when the " "subscription trial ends, instead of waiting for the end of the billing cycle." ) separate_cycles_during_trial = models.NullBooleanField( help_text= "If this is set to True, then the trial period cycle will be split if it spans " "across multiple billing intervals.") prebill_plan = models.NullBooleanField( help_text= "If this is set to True, then the plan base amount will be billed at the" "beginning of the billing cycle rather than after the end.") metered_features = models.ManyToManyField( 'MeteredFeature', blank=True, help_text="A list of the plan's metered features.") generate_after = models.PositiveIntegerField( default=0, help_text='Number of seconds to wait after current billing cycle ends ' 'before generating the invoice. This can be used to allow ' 'systems to finish updating feature counters.') cycle_billing_duration = models.DurationField( null=True, blank=True, help_text= "This can be used to ensure that the billing date doesn't pass a certain date.\n" "For example if this field is set to 2 days, for a monthly subscription, the " "billing date will never surpass the 2nd day of the month. Billing documents can " "still be generated after that day during the billing cycle, but their billing " "date will appear to be the end of the cycle billing duration.") enabled = models.BooleanField(default=True, help_text='Whether to accept subscriptions.') private = models.BooleanField(default=False, help_text='Indicates if a plan is private.') product_code = models.ForeignKey( 'ProductCode', help_text='The product code for this plan.') provider = models.ForeignKey( 'Provider', related_name='plans', help_text='The provider which provides the plan.') class Meta: ordering = ('name', ) @staticmethod def validate_metered_features(metered_features): product_codes = dict() for mf in metered_features: if product_codes.get(mf.product_code.value, None): err_msg = 'A plan cannot have two or more metered features ' \ 'with the same product code. (%s, %s)' \ % (mf.name, product_codes.get(mf.product_code.value)) raise ValidationError(err_msg) product_codes[mf.product_code.value] = mf.name def __str__(self): return self.name @property def provider_flow(self): return self.provider.flow
class AbstractLink(OrgMixin, TimeStampedEditableModel): """ NetJSON NetworkGraph Link Object implementation """ topology = models.ForeignKey(swapper.get_model_name( 'topology', 'Topology'), on_delete=models.CASCADE) source = models.ForeignKey( swapper.get_model_name('topology', 'Node'), related_name='source_link_set', on_delete=models.CASCADE, ) target = models.ForeignKey( swapper.get_model_name('topology', 'Node'), related_name='target_link_set', on_delete=models.CASCADE, ) cost = models.FloatField() cost_text = models.CharField(max_length=24, blank=True) STATUS = Choices('up', 'down') status = StatusField() properties = JSONField( default=dict, blank=True, load_kwargs={'object_pairs_hook': OrderedDict}, dump_kwargs={ 'indent': 4, 'cls': JSONEncoder }, ) status_changed = models.DateTimeField(auto_now=True) class Meta: abstract = True def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._initial_status = self.status def save(self, *args, **kwargs): super().save(*args, **kwargs) if self.status != self._initial_status: self.send_status_changed_signal() self.status_changed = now() self._initial_status = self.status def __str__(self): return '{0} - {1}'.format(self.source.name, self.target.name) def clean(self): if self.source == self.target or self.source_id == self.target_id: raise ValidationError(_('source and target must not be the same')) if self.properties is None: self.properties = {} def json(self, dict=False, **kwargs): """ returns a NetJSON NetworkGraph Link object """ netjson = OrderedDict(( ('source', self.source.netjson_id), ('target', self.target.netjson_id), ('cost', self.cost), ('cost_text', self.cost_text or ''), )) # properties contain status by default properties = OrderedDict((('status', self.status), )) if self.properties: properties.update(self.properties) properties['created'] = self.created properties['modified'] = self.modified properties['status_changed'] = self.status_changed netjson['properties'] = properties if dict: return netjson return json.dumps(netjson, cls=JSONEncoder, **kwargs) def send_status_changed_signal(self): link_status_changed.send(sender=self.__class__, link=self) @classmethod def get_from_nodes(cls, source, target, topology): """ Find link between source and target, (or vice versa, order is irrelevant). Source and target nodes must already exist. :param source: string :param target: string :param topology: Topology instance :returns: Link object or None """ source = '"{}"'.format(source) target = '"{}"'.format(target) q = Q(source__addresses__contains=source, target__addresses__contains=target) | Q( source__addresses__contains=target, target__addresses__contains=source) return cls.objects.filter(q).filter(topology=topology).first() @classmethod def delete_expired_links(cls): """ deletes links that have been down for more than ``NETJSONGRAPH_LINK_EXPIRATION`` days """ LINK_EXPIRATION = app_settings.LINK_EXPIRATION if LINK_EXPIRATION not in [False, None]: expiration_date = now() - timedelta(days=int(LINK_EXPIRATION)) expired_links = cls.objects.filter(status='down', modified__lt=expiration_date) expired_links_length = len(expired_links) if expired_links_length: print_info( 'Deleting {0} expired links'.format(expired_links_length)) for link in expired_links: link.delete()
from django import forms from model_utils import Choices from ckeditor.fields import RichTextFormField from aristotle_mdr.widgets.bootstrap import BootstrapDateTimePicker # Type choices presented when creating a custom field type_choices = Choices(('int', 'Integer'), ('str', 'Text'), ('html', 'Rich Text'), ('date', 'Date'), ('enum', 'Choice')) # Form field used when creating a custom value of the specified type type_field_mapping = { 'int': { 'field': forms.IntegerField, }, 'str': { 'field': forms.CharField, 'args': { 'widget': forms.widgets.Textarea } }, 'date': { 'field': forms.DateField, 'args': { 'widget': BootstrapDateTimePicker(options={'format': 'YYYY-MM-DD'}) } }, 'html': { 'field': RichTextFormField },
class Result(MTModel): """A result of a User running a RunCaseVersion in an Environment.""" STATUS = Choices("assigned", "started", "passed", "failed", "invalidated", "blocked", "skipped") REVIEW = Choices("pending", "reviewed") ALL_STATES = STATUS._full PENDING_STATES = [STATUS.assigned, STATUS.started] COMPLETED_STATES = [ STATUS.passed, STATUS.failed, STATUS.invalidated, STATUS.blocked ] FAILED_STATES = [STATUS.failed, STATUS.blocked] tester = models.ForeignKey(User, related_name="results") runcaseversion = models.ForeignKey(RunCaseVersion, related_name="results") environment = models.ForeignKey(Environment, related_name="results") status = models.CharField(max_length=50, db_index=True, choices=STATUS, default=STATUS.assigned) comment = models.TextField(blank=True) is_latest = models.BooleanField(default=True) review = models.CharField(max_length=50, db_index=True, choices=REVIEW, default=REVIEW.pending) reviewed_by = models.ForeignKey(User, related_name="reviews", blank=True, null=True) def __unicode__(self): """Return unicode representation.""" return "%s, run by %s in %s: %s" % (self.runcaseversion, self.tester, self.environment, self.status) class Meta: permissions = [("review_results", "Can review/edit test results.")] def bug_urls(self): """Returns set of bug URLs associated with this result.""" return set( self.stepresults.exclude(bug_url="").values_list( "bug_url", flat=True).distinct()) def save(self, *args, **kwargs): if self.pk is None: self.set_latest() super(Result, self).save(*args, **kwargs) def set_latest(self): """ Set this result to latest, and unset all others with this env/user/rcv """ Result.objects.filter( tester=self.tester, runcaseversion=self.runcaseversion, environment=self.environment, is_latest=True, ).exclude(pk=self.pk).update(is_latest=False) self.is_latest = True
class Award(TimeStampedModel): """ Award Model. The specific award conferred by a Group. """ id = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False, ) name = models.CharField( help_text="""Award Name.""", max_length=255, ) STATUS = Choices( ( -10, 'inactive', 'Inactive', ), ( 0, 'new', 'New', ), ( 10, 'active', 'Active', ), ) status = FSMIntegerField( help_text= """DO NOT CHANGE MANUALLY unless correcting a mistake. Use the buttons to change state.""", choices=STATUS, default=STATUS.new, ) KIND = Choices( (32, 'chorus', "Chorus"), (41, 'quartet', "Quartet"), ) kind = models.IntegerField(choices=KIND, ) GENDER = Choices( (10, 'male', "Male"), (20, 'female', "Female"), (30, 'mixed', "Mixed"), ) gender = models.IntegerField( help_text=""" The gender to which the award is restricted. If unselected, this award is open to all combinations. """, choices=GENDER, null=True, blank=True, ) LEVEL = Choices( (10, 'championship', "Championship"), (30, 'qualifier', "Qualifier"), (45, 'representative', "Representative"), (50, 'deferred', "Deferred"), (60, 'manual', "Manual"), (70, 'raw', "Improved - Raw"), (80, 'standard', "Improved - Standard"), ) level = models.IntegerField(choices=LEVEL, ) SEASON = Choices( ( 1, 'summer', 'Summer', ), ( 2, 'midwinter', 'Midwinter', ), ( 3, 'fall', 'Fall', ), ( 4, 'spring', 'Spring', ), ) season = models.IntegerField(choices=SEASON, ) is_single = models.BooleanField( help_text="""Single-round award""", default=False, ) threshold = models.FloatField( help_text=""" The score threshold for automatic qualification (if any.) """, null=True, blank=True, ) minimum = models.FloatField( help_text=""" The minimum score required for qualification (if any.) """, null=True, blank=True, ) advance = models.FloatField( help_text=""" The score threshold to advance to next round (if any) in multi-round qualification. """, null=True, blank=True, ) spots = models.IntegerField( help_text="""Number of top spots which qualify""", null=True, blank=True, ) description = models.TextField( help_text=""" The Public description of the award.""", blank=True, max_length=1000, ) notes = models.TextField( help_text=""" Private Notes (for internal use only).""", blank=True, ) DIVISION = Choices( (10, 'evgd1', 'EVG Division I'), (20, 'evgd2', 'EVG Division II'), (30, 'evgd3', 'EVG Division III'), (40, 'evgd4', 'EVG Division IV'), (50, 'evgd5', 'EVG Division V'), (60, 'fwdaz', 'FWD Arizona'), (70, 'fwdne', 'FWD Northeast'), (80, 'fwdnw', 'FWD Northwest'), (90, 'fwdse', 'FWD Southeast'), (100, 'fwdsw', 'FWD Southwest'), (110, 'lol10l', 'LOL 10000 Lakes'), (120, 'lolone', 'LOL Division One'), (130, 'lolnp', 'LOL Northern Plains'), (140, 'lolpkr', 'LOL Packerland'), (150, 'lolsw', 'LOL Southwest'), # (160, 'madatl', 'MAD Atlantic'), (170, 'madcen', 'MAD Central'), (180, 'madnth', 'MAD Northern'), (190, 'madsth', 'MAD Southern'), # (200, 'madwst', 'MAD Western'), (210, 'nedgp', 'NED Granite and Pine'), (220, 'nedmtn', 'NED Mountain'), (230, 'nedpat', 'NED Patriot'), (240, 'nedsun', 'NED Sunrise'), (250, 'nedyke', 'NED Yankee'), (260, 'swdne', 'SWD Northeast'), (270, 'swdnw', 'SWD Northwest'), (280, 'swdse', 'SWD Southeast'), (290, 'swdsw', 'SWD Southwest'), ) division = models.IntegerField( choices=DIVISION, null=True, blank=True, ) AGE = Choices( ( 10, 'seniors', 'Seniors', ), ( 20, 'novice', 'Novice', ), ( 30, 'youth', 'Youth', ), ) age = models.IntegerField( choices=AGE, null=True, blank=True, ) is_novice = models.BooleanField(default=False, ) SIZE = Choices( ( 100, 'p1', 'Plateau 1', ), ( 110, 'p2', 'Plateau 2', ), ( 120, 'p3', 'Plateau 3', ), ( 130, 'p4', 'Plateau 4', ), ( 140, 'pa', 'Plateau A', ), ( 150, 'paa', 'Plateau AA', ), ( 160, 'paaa', 'Plateau AAA', ), ( 170, 'paaaa', 'Plateau AAAA', ), ( 180, 'pb', 'Plateau B', ), ( 190, 'pi', 'Plateau I', ), ( 200, 'pii', 'Plateau II', ), ( 210, 'piii', 'Plateau III', ), ( 220, 'piv', 'Plateau IV', ), ( 230, 'small', 'Small', ), ) size = models.IntegerField( choices=SIZE, null=True, blank=True, ) size_range = IntegerRangeField( null=True, blank=True, ) SCOPE = Choices( ( 100, 'p1', 'Plateau 1', ), ( 110, 'p2', 'Plateau 2', ), ( 120, 'p3', 'Plateau 3', ), ( 130, 'p4', 'Plateau 4', ), ( 140, 'pa', 'Plateau A', ), ( 150, 'paa', 'Plateau AA', ), ( 160, 'paaa', 'Plateau AAA', ), ( 170, 'paaaa', 'Plateau AAAA', ), ( 175, 'paaaaa', 'Plateau AAAAA', ), ) scope = models.IntegerField( choices=SCOPE, null=True, blank=True, ) scope_range = FloatRangeField( null=True, blank=True, ) # Denormalizations tree_sort = models.IntegerField( unique=True, blank=True, null=True, editable=False, ) # FKs group = models.ForeignKey( 'bhs.group', related_name='awards', on_delete=models.CASCADE, ) parent = models.ForeignKey( 'self', help_text="""If a qualifier, this is the award qualifying for.""", related_name='children', null=True, blank=True, db_index=True, on_delete=models.SET_NULL, ) # Internals objects = AwardManager() class Meta: ordering = [ 'tree_sort', ] class JSONAPIMeta: resource_name = "award" def __str__(self): return self.name def clean(self): if self.level == self.LEVEL.qualifier and not self.threshold: raise ValidationError({'level': 'Qualifiers must have thresholds'}) # if self.level != self.LEVEL.qualifier and self.threshold: # raise ValidationError( # {'level': 'Non-Qualifiers must not have thresholds'} # ) # Award Permissions @staticmethod @allow_staff_or_superuser @authenticated_users def has_read_permission(request): return True @allow_staff_or_superuser @authenticated_users def has_object_read_permission(self, request): return True @staticmethod @allow_staff_or_superuser @authenticated_users def has_write_permission(request): return any([ request.user.person.officers.filter( office__lt=200, status__gt=0, ), ]) @allow_staff_or_superuser @authenticated_users def has_object_write_permission(self, request): return any([ request.user.person.officers.filter( office__lt=200, status__gt=0, ), ]) # Transitions @fsm_log_by @transition(field=status, source='*', target=STATUS.active) def activate(self, *args, **kwargs): """Activate the Award.""" return @fsm_log_by @transition(field=status, source='*', target=STATUS.inactive) def deactivate(self, *args, **kwargs): """Deactivate the Award.""" return
# -*- coding: utf-8 -*- ''' Created on 25.9.2011 @author: xaralis ''' from model_utils import Choices SEXES = Choices((1, 'FEMALE', u'žena'), (2, 'MALE', u'muž')) NATIONALITIES = Choices((1, 'CZ', u'Česká republika'), (2, 'EU', u'Jiné - EU'), (3, 'NON_EU', u'Jiné - non-EU'), (4, 'UNKNOWN', u'Neznámo')) ETHNIC_ORIGINS = Choices((1, 'NON_GYPSY', u'Ne-romská'), (2, 'GYPSY', u'Romská'), (3, 'NOT_MONITORED', u'Nesledováno')) LIVING_CONDITIONS = Choices( (1, 'ALONE', u'Sám'), (2, 'WITH_FAMILY', u'S rodiči/rodinou'), (3, 'WITH_FRIENDS', u'S přáteli'), (4, 'WITH_PARTNER', u'S partnerem'), (5, 'WITH_PARTNER_AND_CHILDREN', u'S partnerem a dítětem'), (6, 'ALONE_WITH_CHILDREN', u'Sám s dítětem'), (7, 'UNKNOWN', u'Není známo')) ACCOMODATION_TYPES = Choices( (1, 'WITH_PARENTS', u'Doma (u rodičů)'), (2, 'OWN_FLAT', u'Vlastní byt (i pronajatý)'), (3, 'FOREIGN_FLAT', u'Cizí byt'), (4, 'PUBLIC_ACCOMODATION', u'Ubytovna'), (5, 'SQUAT', u'Squat'), (6, 'BARRACKS', u'Kasárna'), (7, 'HOMELESS', u'Bez domova, na ulici'), (8, 'UNKNOWN', u'Není známo')) EMPLOYMENT_TYPES = Choices( (1, 'REGULAR', u'Pravidelné zam.'), (2, 'SCHOOL', u'Škola'), (3, 'OCCASIONAL_WORK', u'Příležitostná práce'), (4, 'REGISTERED_ON_EB', u'Registrován na ÚP'),
class AbstractNotification(models.Model): """ Action model describing the actor acting out a verb (on an optional target). Nomenclature based on http://activitystrea.ms/specs/atom/1.0/ Generalized Format:: <actor> <verb> <time> <actor> <verb> <target> <time> <actor> <verb> <action_object> <target> <time> Examples:: <justquick> <reached level 60> <1 minute ago> <brosner> <commented on> <pinax/pinax> <2 hours ago> <washingtontimes> <started follow> <justquick> <8 minutes ago> <mitsuhiko> <closed> <issue 70> on <mitsuhiko/flask> <about 2 hours ago> Unicode Representation:: justquick reached level 60 1 minute ago mitsuhiko closed issue 70 on mitsuhiko/flask 3 hours ago HTML Representation:: <a href="http://oebfare.com/">brosner</a> commented on <a href="http://github.com/pinax/pinax">pinax/pinax</a> 2 hours ago # noqa """ LEVELS = Choices('success', 'info', 'warning', 'error') level = models.CharField(choices=LEVELS, default=LEVELS.info, max_length=20) recipient = models.ManyToManyField( settings.AUTH_USER_MODEL, blank=True, related_name='notifications', ) actor_content_type = models.ForeignKey(ContentType, related_name='notify_actor', on_delete=models.CASCADE) actor_object_id = models.CharField(max_length=255) actor = GenericForeignKey('actor_content_type', 'actor_object_id') verb = models.CharField(max_length=255) description = models.TextField(blank=True, null=True) target_content_type = models.ForeignKey(ContentType, related_name='notify_target', blank=True, null=True, on_delete=models.CASCADE) target_object_id = models.CharField(max_length=255, blank=True, null=True) target = GenericForeignKey('target_content_type', 'target_object_id') action_object_content_type = models.ForeignKey( ContentType, blank=True, null=True, related_name='notify_action_object', on_delete=models.CASCADE) action_object_object_id = models.CharField(max_length=255, blank=True, null=True) action_object = GenericForeignKey('action_object_content_type', 'action_object_object_id') timestamp = models.DateTimeField(default=timezone.now, db_index=True) public = models.BooleanField(default=True, db_index=True) deleted = models.BooleanField(default=False, db_index=True) emailed = models.BooleanField(default=False, db_index=True) data = JSONField(blank=True, null=True) objects = NotificationQuerySet.as_manager() class Meta: abstract = True ordering = ('-timestamp', ) def __str__(self): ctx = { 'actor': self.actor, 'verb': self.verb, 'action_object': self.action_object, 'target': self.target, 'timesince': self.timesince() } if self.target: if self.action_object: return u'%(actor)s %(verb)s %(action_object)s on %(target)s %(timesince)s ago' % ctx return u'%(actor)s %(verb)s %(target)s %(timesince)s ago' % ctx if self.action_object: return u'%(actor)s %(verb)s %(action_object)s %(timesince)s ago' % ctx return u'%(actor)s %(verb)s' % ctx def timesince(self, now=None): """ Shortcut for the ``django.utils.timesince.timesince`` function of the current timestamp. """ from django.utils.timesince import timesince as timesince_ return timesince_(self.timestamp, now) @property def slug(self): return id2slug(self.id)
class EnrollmentGrading(models.Model): EXAM_RESULT = Choices( ('na', _('n/a')), ('graduated', _('Graduated')), ('failed', _('Failed')), ('uncompleted', _('Uncompleted')), ) exam_result_arabic = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Arabic')) exam_result_language = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Foreign language')) exam_result_education = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Education')) exam_result_geo = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Geography')) exam_result_history = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('History')) exam_result_math = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Math')) exam_result_science = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Science')) exam_result_physic = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Physic')) exam_result_chemistry = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Chemistry')) exam_result_bio = models.CharField(max_length=6, blank=True, null=True, verbose_name=_('Biology')) exam_result_linguistic_ar = models.CharField( max_length=6, blank=True, null=True, default=None, verbose_name=_('Linguistic field/Arabic')) exam_result_linguistic_en = models.CharField( max_length=6, blank=True, null=True, default=None, verbose_name=_('Linguistic field/Foreign language')) exam_result_sociology = models.CharField(max_length=6, blank=True, null=True, default=None, verbose_name=_('Sociology field')) exam_result_physical = models.CharField(max_length=6, blank=True, null=True, default=None, verbose_name=_('Physical field')) exam_result_artistic = models.CharField(max_length=6, blank=True, null=True, default=None, verbose_name=_('Artistic field')) exam_result_mathematics = models.CharField( max_length=6, blank=True, null=True, default=None, verbose_name=_('Scientific domain/Mathematics')) exam_result_sciences = models.CharField( max_length=6, blank=True, null=True, default=None, verbose_name=_('Scientific domain/Sciences')) exam_total = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Total Grade')) exam_result = models.CharField(max_length=50, blank=True, null=True, choices=EXAM_RESULT, verbose_name=_('Student status')) exam_term = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('Term')) enrollment = models.ForeignKey(Enrollment, blank=False, null=False, related_name='enrollment_gradings', on_delete=models.CASCADE) class Meta: ordering = ['id'] @property def enrollment_student(self): return self.enrollment.student_fullname @property def enrollment_school_name(self): return self.enrollment.school.name @property def enrollment_school_number(self): return self.enrollment.school.number @property def enrollment_classroom_name(self): return self.enrollment.classroom.name @property def enrollment_section_name(self): return self.enrollment.section.name @property def exam_term_name(self): if self.exam_term: return { '1': _('Term1'), '2': _('Term2'), '3': _('Term3'), '4': _('Term4'), }[str(self.exam_term)] return '' def __unicode__(self): return str(self.id)
class Enrollment(TimeStampedModel): """ Captures the details of the child in the cash pilot """ ENROLLMENT_TYPE = Choices( ('no', _('No')), ('second', _('Yes - in 2nd shift')), ('first', _('Yes - in 1st shift')), ('private', _('Yes - in private school')), ('other', _('Yes - in another type of school')), ) RESULT = Choices(('na', 'n/a'), ('graduated', _('Graduated')), ('failed', _('Failed'))) EXAM_RESULT = Choices( ('na', _('n/a')), ('graduated', _('Graduated')), ('failed', _('Failed')), ('uncompleted', _('Uncompleted')), ) YES_NO = Choices( ('yes', _('Yes')), ('no', _('No')), ) SCHOOL_TYPE = Choices( ('na', 'n/a'), ('out_the_country', _('School out of the country')), ('public_in_country', _('Public school in the country')), ('private_in_country', _('Private school in the country')), ) SCHOOL_SHIFT = Choices( ('na', 'n/a'), ('first', _('First shift')), ('second', _('Second shift')), # ('alp', _('ALP')), ) CURRENT_YEAR = datetime.datetime.now().year YEARS = ((str(x), x) for x in range(2016, CURRENT_YEAR)) EDUCATION_YEARS = list( (str(x - 1) + '/' + str(x), str(x - 1) + '/' + str(x)) for x in range(2001, 2050)) EDUCATION_YEARS.append(('na', 'N/A')) student = models.ForeignKey( Student, blank=False, null=True, related_name='student_enrollment', ) enrolled_last_year = models.CharField(max_length=50, blank=True, null=True, choices=ENROLLMENT_TYPE) enrolled_last_year_school = models.ForeignKey( School, blank=True, null=True, related_name='+', ) enrolled_last_year_location = models.ForeignKey( Location, blank=True, null=True, related_name='+', ) school = models.ForeignKey(School, blank=False, null=True, related_name='ndshift_school', verbose_name=_('School')) section = models.ForeignKey(Section, blank=True, null=True, related_name='+', verbose_name=_('Current Section')) classroom = models.ForeignKey(ClassRoom, blank=True, null=True, related_name='+', verbose_name=_('Current Class')) education_year = models.ForeignKey(EducationYear, blank=True, null=True, related_name='+', verbose_name=_('Education year')) owner = models.ForeignKey(settings.AUTH_USER_MODEL, blank=False, null=True, related_name='+', verbose_name=_('Created by')) status = models.BooleanField(blank=True, default=True) age_min_restricted = models.BooleanField(blank=True, default=False) age_max_restricted = models.BooleanField(blank=True, default=False) out_of_school_two_years = models.BooleanField(blank=True, default=False) related_to_family = models.BooleanField(blank=True, default=False) enrolled_in_this_school = models.BooleanField(blank=True, default=True) registered_in_unhcr = models.CharField(max_length=50, blank=True, null=True, choices=YES_NO) number_in_previous_school = models.CharField( max_length=200, blank=True, null=True, verbose_name=_('Serial number in previous school')) last_education_level = models.ForeignKey( ClassRoom, blank=True, null=True, related_name='+', verbose_name=_('Last Education level')) last_education_year = models.CharField( max_length=10, blank=True, null=True, choices=EDUCATION_YEARS, verbose_name=_('Last Education year')) last_year_result = models.CharField( max_length=50, blank=True, null=True, choices=RESULT, verbose_name=_('Last Education result')) result = models.CharField(max_length=50, blank=True, null=True, choices=RESULT) participated_in_alp = models.CharField( max_length=50, blank=True, null=True, choices=Choices( ('na', 'n/a'), ('yes', _('Yes')), ('no', _('No')), ), verbose_name=_('Participated in ALP')) last_informal_edu_level = models.ForeignKey( EducationLevel, blank=True, null=True, related_name='+', verbose_name=_('Last informal education level')) last_informal_edu_year = models.CharField( max_length=10, blank=True, null=True, choices=((str(x - 1) + '/' + str(x), str(x - 1) + '/' + str(x)) for x in range(2001, CURRENT_YEAR)), verbose_name=_('Last informal education year')) last_informal_edu_result = models.CharField( max_length=50, blank=True, null=True, choices=RESULT, verbose_name=_('Last informal education result')) last_informal_edu_round = models.ForeignKey( ALPRound, blank=True, null=True, related_name='+', verbose_name=_('Last informal education round'), ) last_informal_edu_final_result = models.ForeignKey( ClassLevel, blank=True, null=True, related_name='+', verbose_name=_('Last informal education status'), ) last_school_type = models.CharField( max_length=50, blank=True, null=True, choices=SCHOOL_TYPE, verbose_name=_('Last school type'), ) last_school_shift = models.CharField( max_length=50, blank=True, null=True, choices=SCHOOL_SHIFT, verbose_name=_('Last school shift'), ) last_school = models.ForeignKey( School, blank=True, null=True, related_name='+', verbose_name=_('Last school'), ) exam_result_arabic = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Arabic')) exam_result_language = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Foreign Language')) exam_result_education = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Education')) exam_result_geo = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Geography')) exam_result_history = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('History')) exam_result_math = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Math')) exam_result_science = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Science')) exam_result_physic = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Physic')) exam_result_chemistry = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Chemistry')) exam_result_bio = models.CharField(max_length=4, blank=True, null=True, verbose_name=_('Biology')) exam_result_linguistic_ar = models.CharField( max_length=4, blank=True, null=True, default=None, verbose_name=_('Linguistic field/Arabic')) exam_result_linguistic_en = models.CharField( max_length=4, blank=True, null=True, default=None, verbose_name=_('Linguistic field/Foreign language')) exam_result_sociology = models.CharField(max_length=4, blank=True, null=True, default=None, verbose_name=_('Sociology field')) exam_result_physical = models.CharField(max_length=4, blank=True, null=True, default=None, verbose_name=_('Physical field')) exam_result_artistic = models.CharField(max_length=4, blank=True, null=True, default=None, verbose_name=_('Artistic field')) exam_result_mathematics = models.CharField( max_length=4, blank=True, null=True, default=None, verbose_name=_('Scientific domain/Mathematics')) exam_result_sciences = models.CharField( max_length=4, blank=True, null=True, default=None, verbose_name=_('Scientific domain/Sciences')) exam_total = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Final Grade')) exam_result = models.CharField(max_length=50, blank=True, null=True, choices=EXAM_RESULT, verbose_name=_('Student status')) exam_result_arabic_cmplt = models.CharField(max_length=4, blank=True, null=True, default=None, verbose_name=_('Arabic')) exam_result_language_cmplt = models.CharField( max_length=4, blank=True, null=True, default=None, verbose_name=_('Foreign Language')) exam_result_math_cmplt = models.CharField(max_length=4, blank=True, null=True, default=None, verbose_name=_('Math')) exam_total_cmplt = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Final Grade')) exam_result_final = models.CharField( max_length=50, blank=True, null=True, choices=EXAM_RESULT, verbose_name=_('Final Student status')) deleted = models.BooleanField(blank=True, default=False, verbose_name=_('deleted')) disabled = models.BooleanField(blank=True, default=False, verbose_name=_('Disabled?')) last_attendance_date = models.DateField(blank=True, null=True) last_absent_date = models.DateField(blank=True, null=True) dropout_status = models.BooleanField(blank=True, default=False, verbose_name=_('Dropout?')) moved = models.BooleanField(blank=True, default=False, verbose_name=_('Moved?')) outreach_barcode = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('Outreach barcode')) new_registry = models.CharField(max_length=50, blank=True, null=True, choices=Choices(('yes', _("Yes")), ('no', _("No"))), verbose_name=_('First time registered?')) student_outreached = models.CharField( max_length=50, blank=True, null=True, choices=Choices(('yes', _("Yes")), ('no', _("No"))), verbose_name=_('Student outreached?')) have_barcode = models.CharField(max_length=50, blank=True, null=True, choices=Choices(('yes', _("Yes")), ('no', _("No"))), verbose_name=_('Have barcode with him?')) registration_date = models.DateField(blank=True, null=True, verbose_name=_('Registration date')) last_moved_date = models.DateField(blank=True, null=True, verbose_name=_('Last moved date')) objects = EnrollmentManager() drop_objects = EnrollmentDropoutManager() disabled_objects = EnrollmentDisabledManager() @property def student_fullname(self): if self.student: return self.student.full_name return '' @property def student_birthday(self): return self.student.birthday @property def student_sex(self): if self.student: return self.student.sex return '' @property def student_age(self): if self.student: return self.student.age return 0 @property def student_nationality(self): if self.student and self.student.nationality: return self.student.nationality return '' @property def student_id_type(self): return self.student.id_type @property def student_id_number(self): return self.student.id_number @property def student_mother_fullname(self): if self.student: return self.student.mother_fullname return '' @property def student_mother_nationality(self): return self.student.mother_nationality @property def student_phone_number(self): return self.student.phone_number @property def student_address(self): return self.student.address @property def cycle(self): if self.classroom_id in [2, 3, 4]: return 'Cycle 1' if self.classroom_id in [5, 6, 7]: return 'Cycle 2' if self.classroom_id in [8, 9, 10]: return 'Cycle 3' return '' def grading(self, term): if self.enrollment_gradings.count(): return self.enrollment_gradings.get(exam_term=term).id return 0 @property def grading_term1(self): return self.grading(1) @property def grading_term2(self): return self.grading(2) @property def final_grading(self): return self.grading(3) @property def last_year_grading_result(self): if self.enrollment_gradings.count(): return self.enrollment_gradings.get(exam_term=3).exam_result return '' @property def incomplete_grading(self): return self.grading(4) @property def pass_to_incomplete_exam(self): return False def get_absolute_url(self): return '/enrollments/edit/%d/' % self.pk class Meta: ordering = ['-student__first_name'] def __unicode__(self): if self.student: return self.student.__unicode__() return str(self.id)
class AssessmentWorkflow(TimeStampedModel, StatusModel): """Tracks the open-ended assessment status of a student submission. It's important to note that although we track the status as an explicit field here, it is not the canonical status. This is because the determination of what we need to do in order to be "done" is specified by the OpenAssessmentBlock problem definition and can change. So every time we are asked where the student is, we have to query the peer, self, and later other assessment APIs with the latest requirements (e.g. "number of submissions you have to assess = 5"). The "status" field on this model is an after the fact recording of the last known state of that information so we can search easily. """ STEPS = ASSESSMENT_API_DICT.keys() STATUSES = [ "waiting", # User has done all necessary assessment but hasn't been # graded yet -- we're waiting for assessments of their # submission by others. "done", # Complete "cancelled" # User submission has been cancelled. ] STATUS_VALUES = STEPS + STATUSES STATUS = Choices(*STATUS_VALUES) # implicit "status" field # For now, we use a simple scoring mechanism: # Once a student has completed all assessments, # we search assessment APIs # in priority order until one of the APIs provides a score. # We then use that score as the student's overall score. # This Django setting is a list of assessment steps (defined in `settings.ORA2_ASSESSMENTS`) # in descending priority order. DEFAULT_ASSESSMENT_SCORE_PRIORITY = ['peer', 'self'] ASSESSMENT_SCORE_PRIORITY = getattr( settings, 'ORA2_ASSESSMENT_SCORE_PRIORITY', DEFAULT_ASSESSMENT_SCORE_PRIORITY ) STAFF_ANNOTATION_TYPE = "staff_defined" submission_uuid = models.CharField(max_length=36, db_index=True, unique=True) uuid = models.UUIDField(db_index=True, unique=True, default=uuid4) # These values are used to find workflows for a particular item # in a course without needing to look up the submissions for that item. # Because submissions are immutable, we can safely duplicate the values # here without violating data integrity. course_id = models.CharField(max_length=255, blank=False, db_index=True) item_id = models.CharField(max_length=255, blank=False, db_index=True) class Meta: ordering = ["-created"] # TODO: In migration, need a non-unique index on (course_id, item_id, status) app_label = "workflow" def __init__(self, *args, **kwargs): super(AssessmentWorkflow, self).__init__(*args, **kwargs) if 'staff' not in AssessmentWorkflow.STEPS: new_list = ['staff'] new_list.extend(AssessmentWorkflow.STEPS) AssessmentWorkflow.STEPS = new_list AssessmentWorkflow.STATUS_VALUES = AssessmentWorkflow.STEPS + AssessmentWorkflow.STATUSES AssessmentWorkflow.STATUS = Choices(*AssessmentWorkflow.STATUS_VALUES) if 'staff' not in AssessmentWorkflow.ASSESSMENT_SCORE_PRIORITY: new_list = ['staff'] new_list.extend(AssessmentWorkflow.ASSESSMENT_SCORE_PRIORITY) AssessmentWorkflow.ASSESSMENT_SCORE_PRIORITY = new_list @classmethod @transaction.atomic def start_workflow(cls, submission_uuid, step_names, on_init_params): """ Start a new workflow. Args: submission_uuid (str): The UUID of the submission associated with this workflow. step_names (list): The names of the assessment steps in the workflow. on_init_params (dict): The parameters to pass to each assessment module on init. Keys are the assessment step names. Returns: AssessmentWorkflow Raises: SubmissionNotFoundError SubmissionRequestError SubmissionInternalError DatabaseError Assessment-module specific errors """ submission_dict = sub_api.get_submission_and_student(submission_uuid) staff_auto_added = False if 'staff' not in step_names: staff_auto_added = True new_list = ['staff'] new_list.extend(step_names) step_names = new_list # Create the workflow and step models in the database # For now, set the status to waiting; we'll modify it later # based on the first step in the workflow. workflow = cls.objects.create( submission_uuid=submission_uuid, status=AssessmentWorkflow.STATUS.waiting, course_id=submission_dict['student_item']['course_id'], item_id=submission_dict['student_item']['item_id'] ) workflow_steps = [ AssessmentWorkflowStep.objects.create( workflow=workflow, name=step, order_num=i ) for i, step in enumerate(step_names) ] workflow.steps.add(*workflow_steps) # Initialize the assessment APIs has_started_first_step = False for step in workflow_steps: api = step.api() if api is not None: # Initialize the assessment module # We do this for every assessment module on_init_func = getattr(api, 'on_init', lambda submission_uuid, **params: None) on_init_func(submission_uuid, **on_init_params.get(step.name, {})) # If we auto-added a staff step, it is optional and should be marked complete immediately if step.name == "staff" and staff_auto_added: step.assessment_completed_at = now() step.save() # For the first valid step, update the workflow status # and notify the assessment module that it's being started if not has_started_first_step: # Update the workflow workflow.status = step.name workflow.save() # Notify the assessment module that it's being started on_start_func = getattr(api, 'on_start', lambda submission_uuid: None) on_start_func(submission_uuid) # Remember that we've already started the first step has_started_first_step = True # Update the workflow (in case some of the assessment modules are automatically complete) # We do NOT pass in requirements, on the assumption that any assessment module # that accepts requirements would NOT automatically complete. workflow.update_from_assessments(None) # Return the newly created workflow return workflow @property def score(self): """Latest score for the submission we're tracking. Returns: score (dict): The latest score for this workflow, or None if the workflow is incomplete. """ score = None if self.status == self.STATUS.done: score = sub_api.get_latest_score_for_submission(self.submission_uuid) return score def status_details(self): """ Returns workflow status in the form of a dictionary. Each step in the workflow is a key, and each key maps to a dictionary defining whether the step is complete (submitter requirements fulfilled) and graded (the submission has been assessed). """ status_dict = {} steps = self._get_steps() for step in steps: status_dict[step.name] = { "complete": step.is_submitter_complete(), "graded": step.is_assessment_complete(), } return status_dict def get_score(self, assessment_requirements, step_for_name): """Iterate through the assessment APIs in priority order and return the first reported score. Args: assessment_requirements (dict): Dictionary passed to the assessment API. This defines the requirements for each assessment step; the APIs can refer to this to decide whether the requirements have been met. Note that the requirements could change if the author updates the problem definition. step_for_name (dict): a key value pair for step name: step Returns: score dict. """ score = None for assessment_step_name in self.ASSESSMENT_SCORE_PRIORITY: # Check if the problem contains this assessment type assessment_step = step_for_name.get(assessment_step_name) # Query the corresponding assessment API for a score # If we find one, then stop looking if assessment_step is not None: # Check if the assessment API defines a score function at all get_score_func = getattr(assessment_step.api(), 'get_score', None) if get_score_func is not None: if assessment_requirements is None: step_requirements = None else: step_requirements = assessment_requirements.get(assessment_step_name, {}) score = get_score_func(self.submission_uuid, step_requirements) if assessment_step_name == self.STATUS.staff and score == None: if step_requirements and step_requirements.get('required', False): break # A staff score was not found, and one is required. Return None continue # A staff score was not found, but it is not required, so try the next type of score break return score def update_from_assessments(self, assessment_requirements, override_submitter_requirements=False): """Query assessment APIs and change our status if appropriate. If the status is done, we do nothing. Once something is done, we never move back to any other status. If an assessment API says that our submitter's requirements are met, then move to the next assessment. For example, in peer assessment, if the submitter we're tracking has assessed the required number of submissions, they're allowed to continue. If the submitter has finished all the assessments, then we change their status to `waiting`. If we're in the `waiting` status, and an assessment API says it can score this submission, then we record the score in the submissions API and move our `status` to `done`. By convention, if `assessment_requirements` is `None`, then assessment modules that need requirements should automatically say that they're incomplete. This allows us to update the workflow even when we don't know the current state of the problem. For example, if we're updating the workflow at the completion of an asynchronous call, we won't necessarily know the current state of the problem, but we would still want to update assessments that don't have any requirements. Args: assessment_requirements (dict): Dictionary passed to the assessment API. This defines the requirements for each assessment step; the APIs can refer to this to decide whether the requirements have been met. Note that the requirements could change if the author updates the problem definition. override_submitter_requirements (bool): If True, the presence of a new staff score will cause all of the submitter's requirements to be fulfilled, moving the workflow to DONE and exposing their grade. """ if self.status == self.STATUS.cancelled: return # Update our AssessmentWorkflowStep models with the latest from our APIs steps = self._get_steps() step_for_name = {step.name: step for step in steps} new_staff_score = self.get_score(assessment_requirements, {'staff': step_for_name.get('staff', None)}) if new_staff_score: # new_staff_score is just the most recent staff score, it may already be recorded in sub_api old_score = sub_api.get_latest_score_for_submission(self.submission_uuid) if ( # Does a prior score exist? Is it a staff score? Do the points earned match? not old_score or not self.STAFF_ANNOTATION_TYPE in [ annotation['annotation_type'] for annotation in old_score['annotations'] ] or old_score['points_earned'] != new_staff_score['points_earned'] ): # Set the staff score using submissions api, and log that fact self.set_staff_score(new_staff_score) self.save() logger.info(( u"Workflow for submission UUID {uuid} has updated score using staff assessment." ).format(uuid=self.submission_uuid)) # Update the assessment_completed_at field for all steps # All steps are considered "assessment complete", as the staff score will override all for step in steps: common_now = now() step.assessment_completed_at = common_now if override_submitter_requirements: step.submitter_completed_at = common_now step.save() if self.status == self.STATUS.done: return # Go through each step and update its status. for step in steps: step.update(self.submission_uuid, assessment_requirements) # Fetch name of the first step that the submitter hasn't yet completed. new_status = next( (step.name for step in steps if step.submitter_completed_at is None), self.STATUS.waiting # if nothing's left to complete, we're waiting ) # If the submitter is beginning the next assessment, notify the # appropriate assessment API. new_step = step_for_name.get(new_status) if new_step is not None: on_start_func = getattr(new_step.api(), 'on_start', None) if on_start_func is not None: on_start_func(self.submission_uuid) # If the submitter has done all they need to do, let's check to see if # all steps have been fully assessed (i.e. we can score it). if ( new_status == self.STATUS.waiting and all(step.assessment_completed_at for step in steps) ): score = self.get_score(assessment_requirements, step_for_name) # If we found a score, then we're done if score is not None: # Only set the score if it's not a staff score, in which case it will have already been set above if score.get("staff_id") is None: self.set_score(score) new_status = self.STATUS.done # Finally save our changes if the status has changed if self.status != new_status: self.status = new_status self.save() logger.info(( u"Workflow for submission UUID {uuid} has updated status to {status}" ).format(uuid=self.submission_uuid, status=new_status)) def _get_steps(self): """ Simple helper function for retrieving all the steps in the given Workflow. """ # A staff step must always be available, to allow for staff overrides try: self.steps.get(name=self.STATUS.staff) except AssessmentWorkflowStep.DoesNotExist: for step in list(self.steps.all()): step.order_num += 1 staff_step, _ = AssessmentWorkflowStep.objects.get_or_create( name=self.STATUS.staff, order_num=0, assessment_completed_at=now(), workflow=self, ) self.steps.add( staff_step ) # Do not return steps that are not recognized in the AssessmentWorkflow. steps = list(self.steps.filter(name__in=AssessmentWorkflow.STEPS)) if not steps: # If no steps exist for this AssessmentWorkflow, assume # peer -> self for backwards compatibility, with an optional staff override self.steps.add( AssessmentWorkflowStep(name=self.STATUS.staff, order_num=0, assessment_completed_at=now()), AssessmentWorkflowStep(name=self.STATUS.peer, order_num=1), AssessmentWorkflowStep(name=self.STATUS.self, order_num=2) ) steps = list(self.steps.all()) return steps def set_staff_score(self, score, reason=None): """ Set a staff score for the workflow. Allows for staff scores to be set on a submission, with annotations to provide an audit trail if needed. This method can be used for both required staff grading, and staff overrides. Args: score (dict): A dict containing 'points_earned', 'points_possible', and 'staff_id'. is_override (bool): Optionally True if staff is overriding a previous score. reason (string): An optional parameter specifying the reason for the staff grade. A default value will be used in the event that this parameter is not provided. """ if reason is None: reason = "A staff member has defined the score for this submission" sub_dict = sub_api.get_submission_and_student(self.submission_uuid) sub_api.reset_score( sub_dict['student_item']['student_id'], self.course_id, self.item_id, emit_signal=False ) sub_api.set_score( self.submission_uuid, score["points_earned"], score["points_possible"], annotation_creator=score["staff_id"], annotation_type=self.STAFF_ANNOTATION_TYPE, annotation_reason=reason ) def set_score(self, score): """ Set a score for the workflow. Scores are persisted via the Submissions API, separate from the Workflow Data. Score is associated with the same submission_uuid as this workflow Args: score (dict): A dict containing 'points_earned' and 'points_possible'. """ if not self.staff_score_exists(): sub_api.set_score( self.submission_uuid, score["points_earned"], score["points_possible"] ) def staff_score_exists(self): """ Check if a staff score exists for this submission. """ steps = self._get_steps() step_for_name = {step.name: step for step in steps} staff_step = step_for_name.get("staff") if staff_step is not None: get_latest_func = getattr(staff_step.api(), 'get_latest_assessment', None) if get_latest_func is not None: staff_assessment = get_latest_func(self.submission_uuid) if staff_assessment is not None: return True return False def cancel(self, assessment_requirements): """ Cancel workflow for all steps. Set the points earned to 0 and workflow status to cancelled. Args: assessment_requirements (dict): Dictionary that currently looks like: `{"peer": {"must_grade": <int>, "must_be_graded_by": <int>}}` `must_grade` is the number of assessments a student must complete. `must_be_graded_by` is the number of assessments a submission must receive to be scored. `must_grade` should be greater than `must_be_graded_by` to ensure that everyone will get scored. The intention is to eventually pass in more assessment sequence specific requirements in this dict. """ steps = self._get_steps() step_for_name = {step.name: step for step in steps} # Cancel the workflow for each step. for step in steps: on_cancel_func = getattr(step.api(), 'on_cancel', None) if on_cancel_func is not None: on_cancel_func(self.submission_uuid) try: score = self.get_score(assessment_requirements, step_for_name) except AssessmentError as exc: logger.info("TNL-5799, exception in get_score during cancellation. {}".format(exc)) score = None # Set the points_earned to 0. if score is not None: score['points_earned'] = 0 self.set_score(score) # Save status if it is not cancelled. if self.status != self.STATUS.cancelled: self.status = self.STATUS.cancelled self.save() logger.info( u"Workflow for submission UUID {uuid} has updated status to {status}".format( uuid=self.submission_uuid, status=self.STATUS.cancelled ) ) @classmethod def cancel_workflow(cls, submission_uuid, comments, cancelled_by_id, assessment_requirements): """ Add an entry in AssessmentWorkflowCancellation table for a AssessmentWorkflow. AssessmentWorkflow which has been cancelled is no longer included in the peer grading pool. Args: submission_uuid (str): The UUID of the workflow's submission. comments (str): The reason for cancellation. cancelled_by_id (str): The ID of the user who cancelled the peer workflow. assessment_requirements (dict): Dictionary that currently looks like: `{"peer": {"must_grade": <int>, "must_be_graded_by": <int>}}` `must_grade` is the number of assessments a student must complete. `must_be_graded_by` is the number of assessments a submission must receive to be scored. `must_grade` should be greater than `must_be_graded_by` to ensure that everyone will get scored. The intention is to eventually pass in more assessment sequence specific requirements in this dict. """ try: workflow = cls.objects.get(submission_uuid=submission_uuid) AssessmentWorkflowCancellation.create(workflow=workflow, comments=comments, cancelled_by_id=cancelled_by_id) # Cancel the related step's workflow. workflow.cancel(assessment_requirements) except (cls.DoesNotExist, cls.MultipleObjectsReturned): error_message = u"Error finding workflow for submission UUID {}.".format(submission_uuid) logger.exception(error_message) raise AssessmentWorkflowError(error_message) except DatabaseError: error_message = u"Error creating assessment workflow cancellation for submission UUID {}.".format( submission_uuid) logger.exception(error_message) raise AssessmentWorkflowInternalError(error_message) @classmethod def get_by_submission_uuid(cls, submission_uuid): """ Retrieve the Assessment Workflow associated with the given submission UUID. Args: submission_uuid (str): The string representation of the UUID belonging to the associated Assessment Workflow. Returns: workflow (AssessmentWorkflow): The most recent assessment workflow associated with this submission UUID. Raises: AssessmentWorkflowError: Thrown when no workflow can be found for the associated submission UUID. This should always exist before a student is allow to request submissions for peer assessment. """ try: return cls.objects.get(submission_uuid=submission_uuid) except cls.DoesNotExist: return None except DatabaseError as exc: message = u"Error finding workflow for submission UUID {} due to error: {}.".format(submission_uuid, exc) logger.exception(message) raise AssessmentWorkflowError(message) @property def is_cancelled(self): """ Check if assessment workflow is cancelled. Returns: True/False """ return self.cancellations.exists()
from model_utils import Choices, FieldTracker from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import (GenericForeignKey, GenericRelation) from django.core.exceptions import ValidationError MODES = Choices(('off', 'Off'), ('fan', 'Fan'), ('auto', 'Auto'), ('cool', 'Cool'), ('heat', 'Heat')) STATE = Choices(('on', 'On'), ('off', 'Off')) TYPE = Choices( ('State', 'State'), ('Temperature', 'Temperature'), ('Mode', 'Mode'), ('Temperature set point', 'Temperature set point'), ) class NameBaseModel(models.Model): """ Base model with common fields. """ name = models.CharField(max_length=200, help_text='Name') created = models.DateTimeField( auto_now_add=True, help_text="Date and time this object was created.") modified = models.DateTimeField( auto_now=True, help_text="Date and time this object was last modified.")
class Assignment(TimeStampedModel): id = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False, ) STATUS = Choices( ( -10, 'inactive', 'Inactive', ), ( 0, 'new', 'New', ), ( 10, 'active', 'Active', ), ) status = FSMIntegerField( help_text= """DO NOT CHANGE MANUALLY unless correcting a mistake. Use the buttons to change state.""", choices=STATUS, default=STATUS.active, ) KIND = Choices( (10, 'official', 'Official'), (20, 'practice', 'Practice'), (30, 'observer', 'Observer'), ) kind = models.IntegerField(choices=KIND, ) CATEGORY = Choices( (5, 'drcj', 'DRCJ'), (10, 'ca', 'CA'), (30, 'music', 'Music'), (40, 'performance', 'Performance'), (50, 'singing', 'Singing'), ) category = models.IntegerField( choices=CATEGORY, null=True, blank=True, ) # FKs convention = models.ForeignKey( 'Convention', related_name='assignments', on_delete=models.CASCADE, ) person = models.ForeignKey( 'bhs.person', related_name='assignments', null=True, blank=True, on_delete=models.SET_NULL, ) # Relations statelogs = GenericRelation( StateLog, related_query_name='assignments', ) # Internals class JSONAPIMeta: resource_name = "assignment" def __str__(self): return str(self.id) # Permissions @staticmethod @allow_staff_or_superuser @authenticated_users def has_read_permission(request): return True @allow_staff_or_superuser @authenticated_users def has_object_read_permission(self, request): return True @staticmethod @allow_staff_or_superuser @authenticated_users def has_write_permission(request): return any([ request.user.person.officers.filter( office__lt=200, status__gt=0, ), ]) @allow_staff_or_superuser @authenticated_users def has_object_write_permission(self, request): return any([ request.user.person.officers.filter( office__lt=200, status__gt=0, ), ]) # Transitions @fsm_log_by @transition(field=status, source='*', target=STATUS.active) def activate(self, *args, **kwargs): """Activate the Assignment.""" return @fsm_log_by @transition(field=status, source='*', target=STATUS.inactive) def deactivate(self, *args, **kwargs): """Withdraw the Assignment.""" return
from model_utils import Choices INGREDIENT_STATUS_CHOICES = Choices("empty", "low", "full")
class Convention(TimeStampedModel): id = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False, ) name = models.CharField( max_length=255, default='Convention', ) district = models.CharField( max_length=255, null=True, blank=True, ) legacy_name = models.CharField( max_length=255, unique=True, null=True, blank=True, ) legacy_selection = models.CharField( max_length=255, null=True, blank=True, ) legacy_complete = models.CharField( max_length=255, null=True, blank=True, ) legacy_venue = models.CharField( max_length=255, null=True, blank=True, ) STATUS = Choices( ( -25, 'manual', 'Manual', ), ( -20, 'incomplete', 'Incomplete', ), ( -15, 'imported', 'Imported', ), ( -10, 'inactive', 'Inactive', ), ( 0, 'new', 'New', ), ( 5, 'built', 'Built', ), ( 10, 'active', 'Active', ), ) status = FSMIntegerField( help_text= """DO NOT CHANGE MANUALLY unless correcting a mistake. Use the buttons to change state.""", choices=STATUS, default=STATUS.new, ) SEASON = Choices( # (1, 'summer', 'Summer',), # (2, 'midwinter', 'Midwinter',), ( 3, 'fall', 'Fall', ), ( 4, 'spring', 'Spring', ), ) season = models.IntegerField(choices=SEASON, ) PANEL = Choices( (1, 'single', "Single"), (2, 'double', "Double"), (3, 'triple', "Triple"), (4, 'quadruple', "Quadruple"), (5, 'quintiple', "Quintiple"), ) panel = models.IntegerField( choices=PANEL, null=True, blank=True, ) YEAR_CHOICES = [] for r in reversed(range(1939, (datetime.datetime.now().year + 2))): YEAR_CHOICES.append((r, r)) year = models.IntegerField(choices=YEAR_CHOICES, ) open_date = models.DateField( null=True, blank=True, ) close_date = models.DateField( null=True, blank=True, ) start_date = models.DateField( null=True, blank=True, ) end_date = models.DateField( null=True, blank=True, ) location = models.CharField( help_text=""" The general location in the form "City, State".""", max_length=255, default='', blank=True, ) timezone = TimeZoneField( help_text=""" The local timezone of the convention.""", null=True, blank=True, ) image = models.ImageField( upload_to=ImageUploadPath(), null=True, blank=True, ) description = models.TextField( help_text=""" A general description field; usually used for hotel and venue info.""", blank=True, max_length=1000, ) DIVISION = Choices( ('EVG', [ (10, 'evgd1', 'EVG Division I'), (20, 'evgd2', 'EVG Division II'), (30, 'evgd3', 'EVG Division III'), (40, 'evgd4', 'EVG Division IV'), (50, 'evgd5', 'EVG Division V'), ]), ('FWD', [ (60, 'fwdaz', 'FWD Arizona'), (70, 'fwdne', 'FWD Northeast'), (80, 'fwdnw', 'FWD Northwest'), (90, 'fwdse', 'FWD Southeast'), (100, 'fwdsw', 'FWD Southwest'), ]), ('LOL', [ (110, 'lol10l', 'LOL 10000 Lakes'), (120, 'lolone', 'LOL Division One'), (130, 'lolnp', 'LOL Northern Plains'), (140, 'lolpkr', 'LOL Packerland'), (150, 'lolsw', 'LOL Southwest'), ]), ( 'MAD', [ # (160, 'madatl', 'MAD Atlantic'), (170, 'madcen', 'MAD Central'), (180, 'madnth', 'MAD Northern'), (190, 'madsth', 'MAD Southern'), # (200, 'madwst', 'MAD Western'), ]), ('NED', [ (210, 'nedgp', 'NED Granite and Pine'), (220, 'nedmtn', 'NED Mountain'), (230, 'nedpat', 'NED Patriot'), (240, 'nedsun', 'NED Sunrise'), (250, 'nedyke', 'NED Yankee'), ]), ('SWD', [ (260, 'swdne', 'SWD Northeast'), (270, 'swdnw', 'SWD Northwest'), (280, 'swdse', 'SWD Southeast'), (290, 'swdsw', 'SWD Southwest'), ]), ) divisions = DivisionsField( help_text= """Only select divisions if required. If it is a district-wide convention do not select any.""", base_field=models.IntegerField(choices=DIVISION, ), default=list, blank=True, ) KINDS = Choices( (32, 'chorus', "Chorus"), (41, 'quartet', "Quartet"), (42, 'mixed', "Mixed"), (43, 'senior', "Senior"), (44, 'youth', "Youth"), (45, 'unknown', "Unknown"), (46, 'vlq', "VLQ"), ) kinds = DivisionsField( help_text="""The session kind(s) created at build time.""", base_field=models.IntegerField(choices=KINDS, ), default=list, blank=True, ) # FKs venue = models.ForeignKey( 'stage.venue', related_name='conventions', help_text=""" The specific venue for the convention (if available.)""", on_delete=models.SET_NULL, null=True, blank=True, ) group = models.ForeignKey( 'bhs.group', related_name='conventions', on_delete=models.CASCADE, ) # Relations statelogs = GenericRelation( StateLog, related_query_name='conventions', ) # Internals class Meta: unique_together = (( 'year', 'season', 'name', 'group', ), ) class JSONAPIMeta: resource_name = "convention" def __str__(self): if self.district == 'BHS': return " ".join([ self.district, str(self.year), self.name, ]) return " ".join([ self.district, self.get_season_display(), str(self.year), self.name, ]) def clean(self): if self.group.kind > self.group.KIND.district: raise ValidationError( {'group': 'Owning group must be at least district'}) # Methods def get_drcj_emails(self): Assignment = apps.get_model('cmanager.assignment') assignments = self.assignments.filter( status=Assignment.STATUS.active, category=Assignment.CATEGORY.drcj, person__email__isnull=False, ).order_by( 'kind', 'category', 'person__last_name', 'person__first_name', ) seen = set() result = [ "{0} ({1} {2}) <{3}>".format( assignment.person.common_name, assignment.get_kind_display(), assignment.get_category_display(), assignment.person.email, ) for assignment in assignments if not ("{0} ({1} {2}) <{3}>".format( assignment.person.common_name, assignment.get_kind_display(), assignment.get_category_display(), assignment.person.email, ) in seen or seen.add("{0} ({1} {2}) <{3}>".format( assignment.person.common_name, assignment.get_kind_display(), assignment.get_category_display(), assignment.person.email, ))) ] return result def get_ca_emails(self): Assignment = apps.get_model('cmanager.assignment') assignments = self.assignments.filter( status=Assignment.STATUS.active, category=Assignment.CATEGORY.ca, person__email__isnull=False, ).order_by( 'kind', 'category', 'person__last_name', 'person__first_name', ) seen = set() result = [ "{0} ({1} {2}) <{3}>".format( assignment.person.common_name, assignment.get_kind_display(), assignment.get_category_display(), assignment.person.email, ) for assignment in assignments if not ("{0} ({1} {2}) <{3}>".format( assignment.person.common_name, assignment.get_kind_display(), assignment.get_category_display(), assignment.person.email, ) in seen or seen.add("{0} ({1} {2}) <{3}>".format( assignment.person.common_name, assignment.get_kind_display(), assignment.get_category_display(), assignment.person.email, ))) ] return result # Convention Permissions @staticmethod @allow_staff_or_superuser @authenticated_users def has_read_permission(request): return True @allow_staff_or_superuser @authenticated_users def has_object_read_permission(self, request): return True @staticmethod @allow_staff_or_superuser @authenticated_users def has_write_permission(request): return any([ request.user.person.officers.filter( office__lt=200, status__gt=0, ), ]) @allow_staff_or_superuser @authenticated_users def has_object_write_permission(self, request): return any([ request.user.person.officers.filter( office__lt=200, status__gt=0, ), ]) # Convention Transition Conditions def can_reset(self): if self.status <= self.STATUS.built: return True return False def can_build(self): if self.kinds and self.panel: return True return False def can_activate(self): try: return all([ self.open_date, self.close_date, self.start_date, self.end_date, self.open_date < self.close_date, self.close_date < self.start_date, self.start_date <= self.end_date, self.location, self.timezone, self.sessions.count() > 0, ]) except TypeError: return False return False def can_deactivate(self): return all([ not self.sessions.exclude( status=self.sessions.model.STATUS.finished) ]) # Convention Transitions @fsm_log_by @transition( field=status, source='*', target=STATUS.new, conditions=[can_reset], ) def reset(self, *args, **kwargs): assignments = self.assignments.all() sessions = self.sessions.all() assignments.delete() sessions.delete() return @fsm_log_by @transition( field=status, source=STATUS.new, target=STATUS.built, conditions=[can_build], ) def build(self, *args, **kwargs): """Build convention and related sessions.""" # Reset for indempodence self.reset() # Assignment = apps.get_model('cmanager.assignment') Officer = apps.get_model('bhs.officer') scjcs = Officer.objects.filter( Q(office=Officer.OFFICE.scjc_chair) | Q(office=Officer.OFFICE.scjc_admin), status__gt=0, ) for scjc in scjcs: self.assignments.create( category=Assignment.CATEGORY.drcj, status=Assignment.STATUS.active, kind=Assignment.KIND.observer, person=scjc.person, ) drcjs = self.group.officers.filter( office=Officer.OFFICE.drcj, status__gt=0, ) for drcj in drcjs: self.assignments.create( category=Assignment.CATEGORY.drcj, status=Assignment.STATUS.active, kind=Assignment.KIND.official, person=drcj.person, ) ca_specialists = Officer.objects.filter( office=Officer.OFFICE.scjc_ca, status__gt=0, ) for ca_specialist in ca_specialists: self.assignments.create( category=Assignment.CATEGORY.ca, status=Assignment.STATUS.active, kind=Assignment.KIND.observer, person=ca_specialist.person, ) cas = ceil((self.panel + 1) / 2) while cas > 0: self.assignments.create( category=Assignment.CATEGORY.ca, status=Assignment.STATUS.active, kind=Assignment.KIND.official, ) cas -= 1 judges = self.panel while judges > 0: self.assignments.create( category=Assignment.CATEGORY.music, status=Assignment.STATUS.active, kind=Assignment.KIND.official, ) self.assignments.create( category=Assignment.CATEGORY.performance, status=Assignment.STATUS.active, kind=Assignment.KIND.official, ) self.assignments.create( category=Assignment.CATEGORY.singing, status=Assignment.STATUS.active, kind=Assignment.KIND.official, ) judges -= 1 for kind in list(self.kinds): self.sessions.create(kind=kind, ) return @fsm_log_by @transition( field=status, source=STATUS.built, target=STATUS.active, conditions=[can_activate], ) def activate(self, *args, **kwargs): """Activate convention.""" return @fsm_log_by @transition( field=status, source=STATUS.active, target=STATUS.inactive, conditions=[can_deactivate], ) def deactivate(self, *args, **kwargs): """Archive convention and related sessions.""" return
from model_utils import Choices SPONSOR_TYPES = Choices( ('diamond', 'DIAMOND', 'Diamond Sponsor'), ('lanyard', 'LANYARD', 'Lanyard Sponsor'), ('track', 'TRACK', 'Track Sponsor'), ('foodanddrinks', 'FOOD_AND_DRINKS', 'Food & Drinks Sponsor'), ('standard', 'STANDARD', 'Standard Sponsor'), ('supporter', 'SUPPORTER', 'Supporter Sponsor'), ('mainmedia', 'MAIN_MEDIA', 'Main Media Sponsor'), ('media', 'MEDIA', 'Media sponsors'), ('video', 'VIDEO', 'Video sponsors'), )
class EntePartecipatoCronologia(models.Model): TIPOLOGIA = Choices( ('AL', 'amministrazionilocali', u'Amministrazioni Locali'), ('AR', 'amministrazioniregionali', u'Amministrazioni Regionali'), ('IL', 'impresepubblichelocali', u'Imprese pubbliche locali'), ) FATTURATO_CLUSTERS = [ {'to': 100000}, {'from': 100000, 'to': 1000000}, {'from': 1000000, 'to': 10000000}, {'from': 10000000, 'to': 100000000}, {'from': 100000000}, ] ente_partecipato = models.ForeignKey(EntePartecipato, related_name='cronologia') anno_riferimento = models.CharField(max_length=4) tipologia = models.CharField(max_length=2, choices=TIPOLOGIA, db_index=True) categoria = models.ForeignKey(EntePartecipatoCategoria, related_name='enti_partecipati_cronologia') sottotipo = models.ForeignKey(EntePartecipatoSottotipo, related_name='enti_partecipati_cronologia') fatturato = models.DecimalField(max_digits=14, decimal_places=2, null=True) indice_performance = models.DecimalField(max_digits=5, decimal_places=2, null=True) indice2 = models.DecimalField(max_digits=14, decimal_places=2, null=True, help_text='Risultato finanziario') indice3 = models.DecimalField(max_digits=5, decimal_places=2, null=True, help_text='Partecipazione PA') indice4 = models.DecimalField(max_digits=5, decimal_places=2, null=True, help_text='Spese Investimento') indice5 = models.DecimalField(max_digits=5, decimal_places=2, null=True, help_text='Spese Personale') risultato_finanziario = models.ForeignKey(EntePartecipatoRisultatoFinanziario, null=True, related_name='enti_partecipati_cronologia') quota_pubblica = models.DecimalField(max_digits=5, decimal_places=2, null=True) quote_stimate = models.BooleanField(default=False) note_indicatori = models.TextField(null=True) altri_soci_noti = models.DecimalField(max_digits=5, decimal_places=2, null=True) altri_soci_noti_pubblici = models.DecimalField(max_digits=5, decimal_places=2, null=True) altri_soci_noti_privati = models.DecimalField(max_digits=5, decimal_places=2, null=True) altri_soci_non_noti = models.DecimalField(max_digits=5, decimal_places=2, null=True) settori = models.ManyToManyField(EntePartecipatoSettore, through='EntePartecipatoCronologiaRegioneSettore', related_name='enti_partecipati_cronologia') regioni = models.ManyToManyField(Territorio, through='EntePartecipatoCronologiaRegioneSettore', related_name='enti_partecipati_cronologia') objects = EntePartecipatoCronologiaQuerySet.as_manager() @cached_property def fatturato_cluster(self): for cluster in self.FATTURATO_CLUSTERS: if 'to' in cluster and self.fatturato <= cluster['to']: return cluster return self.FATTURATO_CLUSTERS[-1] @property def altri_soci(self): return [{ 'id': attrname, 'denominazione': self._meta.get_field(attrname).verbose_name.upper(), 'quota': getattr(self, attrname), } for attrname in ('altri_soci_noti_pubblici', 'altri_soci_noti_privati', 'altri_soci_non_noti') if getattr(self, attrname)] def __unicode__(self): return u'{}'.format(self.ente_partecipato_id) class Meta: ordering = ['ente_partecipato', 'anno_riferimento'] unique_together = ('ente_partecipato', 'anno_riferimento') index_together = [ ['ente_partecipato', 'anno_riferimento'], ]
from django.db import models from model_utils import Choices from ssm.core.models import BaseModel STATUS = Choices('pending', 'processing', 'stopped', 'failed', 'completed') BUSY = [STATUS.pending, STATUS.processing] DONE = [STATUS.completed] class Report(BaseModel): uid = models.CharField('Unique ID', max_length=64, null=True) name = models.CharField('Name', max_length=128) description = models.TextField(null=True, blank=True) class Meta: app_label = 'reports' verbose_name_plural = 'Reports' ordering = ['name'] def __str__(self): return f'{self.name} (report {self.id})' def launch(self, start_date, end_date): from ssm.reports.configs import REPORTS params = {'start_date': start_date, 'end_date': end_date} return History.launch(REPORTS[self.uid], params=params, **{'report': self})
from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from model_utils import Choices from PIL import Image AGE_CHOICES = Choices( (0, 'kids', 'kids'), (1, 'teens', 'teens'), (2, 'adults', 'adults'), ) class Genre(models.Model): name = models.CharField(max_length=20, unique=True) age_limit = models.IntegerField(null=True, blank=True, choices=AGE_CHOICES) def __str__(self): return self.name class Director(models.Model): name = models.CharField(max_length=20) last_name = models.CharField(max_length=20) class Meta: unique_together = ('name', 'last_name') def __str__(self): return f"{self.name} {self.last_name}"
from django.db import models from django.utils import timezone from django.db.models import Q from model_utils import Choices ORDER_COLUMN_CHOICES = Choices( ('0', 'id'), ('1', 'rwe_type'), ('2', 'rwe_closure_type'), ('3', 'rwe_status'), ('4', 'rwe_start_dt'), ('5', 'rwe_end_dt'), ('6', 'rwe_publish_text'), ('7', 'subject_pref_rdname'), ('8', 'traffic_delay'), ('9', 'speed_limit'), ('10', 'lanes_affected')) # create data table for road construction information class road_construction(models.Model): rwe_type = models.TextField(max_length=50, null=True) rwe_closure_type = models.TextField(max_length=50, null=True) rwe_status = models.TextField(max_length=50, null=True) rwe_start_dt = models.TextField(max_length=50, null=True) rwe_end_dt = models.TextField(max_length=50, null=True) rwe_publish_text = models.TextField(max_length=500, null=True) subject_pref_rdname = models.TextField(max_length=50, null=True) traffic_delay = models.TextField(max_length=200, null=True) speed_limit = models.TextField(max_length=50, null=True) lanes_affected = models.TextField(max_length=50, null=True) class Meta: db_table = "road" # search and query function to process the kwargs from ajax def query_road_by_args(**kwargs):
from . import moderation from .constants import (MODERATION_READY_STATE, MODERATION_DRAFT_STATE, MODERATION_STATUS_REJECTED, MODERATION_STATUS_APPROVED, MODERATION_STATUS_PENDING) from .diff import get_changes_between_models from .fields import SerializedObjectField from .managers import ModeratedObjectManager from .signals import post_moderation, pre_moderation from .utils import django_19 import datetime import uuid MODERATION_STATES = Choices( (MODERATION_READY_STATE, 'ready', _('Ready for moderation')), (MODERATION_DRAFT_STATE, 'draft', _('Draft')), ) STATUS_CHOICES = Choices( (MODERATION_STATUS_REJECTED, 'rejected', _("Rejected")), (MODERATION_STATUS_APPROVED, 'approved', _("Approved")), (MODERATION_STATUS_PENDING, 'pending', _("Pending")), ) class ModeratedObject(models.Model): content_type = models.ForeignKey(ContentType, null=True, blank=True, editable=False, on_delete=models.SET_NULL)
from django.db import models from model_utils import Choices ISSUE_STATUS = Choices('New', 'Ongoing', 'Resolved') SITE_OPTIONS = Choices('src_site', 'dst_site', 'unknown') # class IssueCause(models.Model): # """ # Rucio IssueCause object. # """ # # cause = models.CharField(max_length=128, unique=True) # last_modified = models.DateTimeField(auto_now=True) # # def __str__(self): # return self.cause class IssueCategory(models.Model): """ Rucio IssueCategory object. """ regex = models.CharField(max_length=512) # cause = models.ForeignKey(IssueCause, null=True, on_delete=models.PROTECT) last_modified = models.DateTimeField(auto_now=True) class Meta: unique_together = (('regex'), ) def __str__(self):
class Project(G3WProjectMixins, G3WACLModelMixins, TimeStampedModel): """A QGIS project.""" QUERY_TYPE = Choices(('single', _('Single')), ('multiple', _('Multiple'))) CLIENT_TOC_TABS = Choices(('layers', _('Layers')), ('baselayers', _('Base layers')), ('legend', _('Legend'))) CLIENT_TOC_LAYERS_INIT_STATUS = Choices( ('collapsed', _('Collapsed')), ('not_collapsed', _('Not collapsed'))) CLIENT_MAP_THEMES_INIT_STATUS = Choices( ('collapsed', _('Collapsed')), ('not_collapsed', _('Not collapsed'))) CLIENT_LEGEND_POSITION = Choices(('tab', _('In a separate TAB')), ('toc', _('Into TOC layers'))) # Project file qgis_file = models.FileField(_('QGIS project file'), max_length=400, upload_to=get_project_file_path, storage=QgisFileOverwriteStorage()) # General info title = models.CharField(_('Title'), max_length=255) title_ur = models.CharField(_('Public title'), max_length=255, null=True, blank=True) description = models.TextField(_('Description'), blank=True, null=True) slug = AutoSlugField(_('Slug'), populate_from='title', unique=True, always_update=True) is_active = models.BooleanField(_('Is active'), default=1) # Thumbnail thumbnail = models.ImageField(_('Thumbnail'), blank=True, null=True) # Group group = models.ForeignKey(Group, related_name='qdjango_project', verbose_name=_('Group'), on_delete=models.CASCADE) # Extent initial_extent = models.CharField(_('Initial extent'), max_length=255) max_extent = models.CharField(_('Max extent'), max_length=255, null=True, blank=True) # Qgis version project qgis_version = models.CharField(_('Qgis project version'), max_length=255, default='') # LayersTree project structure layers_tree = models.TextField(_('Layers tree structure'), blank=True, null=True) # BaseLayer baselayer = models.ForeignKey(BaseLayer, verbose_name=_('Base Layer'), related_name='qdjango_project_baselayer', null=True, blank=True, on_delete=models.DO_NOTHING) # possible layer relations relations = models.TextField(_('Layer relations'), blank=True, null=True) # WMSUseLayerIDs wms_use_layer_ids = models.BooleanField(_('WMS use layer ids'), default=False) original_name = models.CharField(_('Qgis project original name'), max_length=256, default='', editable=False) # client options: # ============================================ feature_count_wms = models.IntegerField(_('Max feature to get for query'), default=5) multilayer_query = models.CharField(_('Query control mode'), max_length=20, choices=QUERY_TYPE, default='multiple') multilayer_querybybbox = models.CharField(_('Query by bbox control mode'), max_length=20, choices=QUERY_TYPE, default='multiple') multilayer_querybypolygon = models.CharField( _('Query by polygon control mode'), max_length=20, choices=QUERY_TYPE, default='multiple') context_base_legend = models.BooleanField( _('Context base legend'), default=False, help_text= 'Show only the symbols for the features falling into the requested area' ) toc_tab_default = models.CharField( _("Tab's TOC active as default"), choices=CLIENT_TOC_TABS, max_length=40, default='layers', help_text="Set tab's TOC open by default on init client") toc_layers_init_status = models.CharField( _("Tab's TOC layer initial status"), choices=CLIENT_TOC_LAYERS_INIT_STATUS, max_length=40, default='not_collapsed', help_text="Set tab's TOC layers initials state: 'Collapsed (close)'" "or 'Not collapsed (open)'") toc_themes_init_status = models.CharField( _("Map themes list initial status"), choices=CLIENT_MAP_THEMES_INIT_STATUS, max_length=40, default='collapsed', help_text="Set map themes list initials state: 'Collapsed (close)'" "or 'Not collapsed (open)'") legend_position = models.CharField( _("Legend position rendering"), choices=CLIENT_LEGEND_POSITION, max_length=20, default='tab', help_text="Set legend position rendering") autozoom_query = models.BooleanField( _('Automatic zoom to query result features'), default=False, help_text='Automatic zoom on query result features for only one layer') layouts = models.TextField(_('Project layouts'), null=True, blank=True) use_map_extent_as_init_extent = models.BooleanField( _('User QGIS project map start extent as webgis init extent'), default=False) is_dirty = models.BooleanField(_( 'The project has been modified by the G3W-Suite application after it was uploaded.' ), editable=False, default=False) is_locked = models.BooleanField(_( 'Mutex to lock the project when it is being written by the G3W-Suite application. This field is used internally by the suite through a context manager' ), editable=False, default=False) order = models.PositiveIntegerField(_('Fields to se order'), default=0, blank=True, null=True) class Meta: verbose_name = _('Project') verbose_name_plural = _('Projects') unique_together = (('title', 'group')) def __str__(self): return self.title @property def qgis_project(self): """Returns the QgsProject instance corresponding to this Project, or None in case of errors :return: the QgsProject instance :rtype: QgsProject or None """ from qdjango.apps import get_qgs_project return get_qgs_project(self.qgis_file.path) def update_qgis_project(self): """Updates the QGIS project associated with the G3W-Suite project instance and sets the "dirty" flag. WARNING: to prevent concurrent writes to the same project from different processes use QgisProjectFileLocker mutex. :return: True on success :rtype: bool """ if self.qgis_project.write(): self.is_dirty = True # Update layers tree self.layers_tree = str( buildLayerTreeNodeObject(self.qgis_project.layerTreeRoot())) self.save() return True else: return False def _permissionsToEditor(self, user, mode='add'): setPermissionUserObject( user, self, permissions=['change_project', 'delete_project', 'view_project'], mode=mode) # if editor not has permission on group give permission only view on parent group if not user.has_perm('core.view_group', self.group): setPermissionUserObject(user, self.group, permissions=['core.view_group'], mode=mode) layerAction = 'addPermissionsToEditor' if mode == 'add' else 'removePermissionsToEditor' layers = self.layer_set.all() for layer in layers: getattr(layer, layerAction)(user) def _permissionsToViewers(self, users_id, mode='add'): for user_id in users_id: user = User.objects.get(pk=user_id) setPermissionUserObject(user, self, permissions='view_project', mode=mode) layerAction = 'addPermissionsToViewers' if mode == 'add' else 'removePermissionsToViewers' layers = self.layer_set.all() for layer in layers: getattr(layer, layerAction)(users_id) def _permissions_to_user_groups_editor(self, groups_id, mode='add'): for group_id in groups_id: auth_group = AuthGroup.objects.get(pk=group_id) setPermissionUserObject(auth_group, self, permissions=[ 'change_project', 'delete_project', 'view_project' ], mode=mode) # if viewer not has permission on group give permission only view on parent group if 'view_group' not in get_perms(auth_group, self.group): setPermissionUserObject(auth_group, self.group, permissions=['core.view_group'], mode=mode) layerAction = 'add_permissions_to_editor_user_groups' if mode == 'add' \ else 'remove_permissions_to_editor_user_groups' layers = self.layer_set.all() for layer in layers: getattr(layer, layerAction)(groups_id) def _permissions_to_user_groups_viewer(self, groups_id, mode='add'): for group_id in groups_id: auth_group = AuthGroup.objects.get(pk=group_id) setPermissionUserObject(auth_group, self, permissions='view_project', mode=mode) layerAction = 'add_permissions_to_viewer_user_groups' if mode == 'add' \ else 'remove_permissions_to_viewer_user_groups' layers = self.layer_set.all() for layer in layers: getattr(layer, layerAction)(groups_id) def tree(self): def readLeaf(layer, layers): if 'nodes' in layer: children = [] for node in layer['nodes']: children.append(readLeaf(node, layers)) return ['g_{}'.format(layer['name']), children] else: return [layers[layer['id']][0], layers[layer['id']][1]] layers = self.layer_set.values_list('id', 'name', 'qgs_layer_id') _layers = {l[2]: l for l in layers} layers_tree = [] for l in eval(self.layers_tree): layers_tree.append(readLeaf(l, _layers)) return layers_tree @property def url_alias(self): try: return ProjectMapUrlAlias.objects.get(app_name='qdjango', project_id=self.pk).alias except: return None @url_alias.setter def url_alias(self, url_alias): if url_alias: ProjectMapUrlAlias.objects.update_or_create( app_name='qdjango', project_id=self.pk, defaults={'alias': url_alias}) else: try: ProjectMapUrlAlias.objects.get(app_name='qdjango', project_id=self.pk).delete() except: pass def __getattr__(self, attr): if attr == 'viewers': return get_users_for_object(self, 'view_project', [G3W_VIEWER1, G3W_VIEWER2], with_anonymous=True) elif attr == 'editor': editors = get_users_for_object(self, 'change_project', [G3W_EDITOR1]) if len(editors) > 0: return editors[0] else: return None elif attr == 'editor2': editors = get_users_for_object(self, 'change_project', [G3W_EDITOR2]) if len(editors) > 0: return editors[0] else: return None # Get users groups # ================ elif attr == 'editor_user_groups': return get_groups_for_object(self, 'change_project', 'editor') elif attr == 'viewer_user_groups': return get_groups_for_object(self, 'view_project', 'viewer') return super(Project, self).__getattribute__(attr)
class Pedido(TimeStampedModel): codigo = models.CharField(unique=True, max_length=12) solicitante = models.ForeignKey(Trabajador) oficina = models.ForeignKey(Oficina) fecha = models.DateField() observaciones = models.TextField(blank=True) STATUS = Choices( ('PEND', _('PENDIENTE')), ('APROB', _('APROBADO')), ('DESAP', _('DESAPROBADO')), ('ATEN', _('ATENDIDO')), ('ATEN_PARC', _('ATENDIDO PARCIALMENTE')), ('CANC', _('CANCELADO')), ) estado = models.CharField(choices=STATUS, default=STATUS.PEND, max_length=20) history = HistoricalRecords() def anterior(self): try: ant = Pedido.objects.filter(pk__lt=self.pk).order_by('-pk')[0] except: ant = Pedido.objects.all().order_by('pk').last() return ant.pk def siguiente(self): try: sig = Pedido.objects.filter(pk__gt=self.pk).order_by('pk')[0] except: sig = Pedido.objects.all().order_by('pk').first() return sig.pk def establecer_estado_atendido(self): total = 0 total_atendida = 0 detalles = DetallePedido.objects.filter(pedido=self) for detalle in detalles: total = total + detalle.cantidad total_atendida = total_atendida + detalle.cantidad_atendida if total_atendida == 0: estado = Pedido.STATUS.PEND elif total_atendida < total: estado = Pedido.STATUS.ATEN_PARC elif total_atendida >= total: estado = Pedido.STATUS.ATEN self.estado = estado class Meta: permissions = ( ('aprobar_pedido', 'Puede aprobar Pedido'), ('ver_detalle_pedido', 'Puede ver detalle de Pedido'), ('ver_tabla_aprobacion_pedidos', 'Puede ver tabla de Aprobación de Pedidos'), ('ver_tabla_pedidos', 'Puede ver tabla de Pedidos'), ('ver_reporte_pedidos_excel', 'Puede ver Reporte de Pedidos en excel'), ) def __str__(self): return self.codigo def save(self, *args, **kwargs): if self.codigo == '': anio = self.fecha.year mov_ant = Pedido.objects.filter(fecha__year=anio).aggregate( Max('codigo')) id_ant = mov_ant['codigo__max'] if id_ant is None: aux = 1 else: aux = int(id_ant[-6:]) + 1 correlativo = str(aux).zfill(6) codigo = 'PE' + str(anio) + correlativo self.codigo = codigo super(Pedido, self).save() else: super(Pedido, self).save()
class Layer(G3WACLModelMixins, models.Model): """A QGIS layer.""" TYPES = Choices(('postgres', _('Postgres')), ('spatialite', _('SpatiaLite')), ('raster', _('Raster')), ('wfs', _('WFS')), ('wms', _('WMS')), ('ogr', _('OGR')), ('gdal', _('GDAL')), ('delimitedtext', _('CSV')), ('arcgismapserver', _('ArcGisMapServer')), ('arcgisfeatureserver', _('ArcGisFeatureServer')), ('mssql', _('MSSQL')), ('virtual', _('VirtualLayer')), ('oracle', _('Oracle')), ('vector-tile', _('Vector Tile')), ('wcs', _('WCS'))) # General info name = models.CharField(_('Name'), max_length=255) title = models.CharField(_('Title'), max_length=255, blank=True) origname = models.CharField(_('Original Name'), max_length=256, null=True, blank=True) qgs_layer_id = models.CharField(_('Qgis Layer Project ID'), max_length=255, blank=True, null=True) description = models.TextField(_('Description'), blank=True) slug = AutoSlugField(_('Slug'), populate_from='name', unique=True, always_update=True) is_active = models.BooleanField(_('Is active'), default=1) # Project project = models.ForeignKey(Project, verbose_name=_('Project'), on_delete=models.CASCADE) parent_project = models.ForeignKey( Project, verbose_name=_('Parent Project for Embedded layers'), blank=True, null=True, on_delete=models.CASCADE, editable=False, related_name='parent_project') # Type and content layer_type = models.CharField(_('Type'), choices=TYPES, max_length=255) datasource = models.TextField(_('Datasource')) is_visible = models.BooleanField(_('Is visible'), default=1) order = models.IntegerField(_('Order'), default=1) # Optional data file (non-postgres layers need it) data_file = models.FileField(_('Associated data file'), upload_to=get_layer_data_file_path, blank=True, null=True) # TODO: make this a property of the Layer object # Database columns (DB layers need it) database_columns = models.TextField(_('Database columns'), blank=True, null=True) # minscale and maxscale and scalebasedvisibility min_scale = models.IntegerField(_('Layer Min Scale visibility'), blank=True, null=True) max_scale = models.IntegerField(_('Layer Max Scale visibility'), blank=True, null=True) scalebasedvisibility = models.BooleanField( _('Layer scale based visibility'), default=False) # srid srid = models.IntegerField(_('Layer SRID'), blank=True, null=True) # for capabilities and edit opsions capabilities = models.IntegerField(_('Bitwise capabilities'), blank=True, null=True) edit_options = models.IntegerField(_('Bitwise edit options'), blank=True, null=True) wfscapabilities = models.IntegerField(_('Bitwise wfs options'), blank=True, null=True) # geometryType geometrytype = models.CharField(_('Geometry type'), max_length=255, blank=True, null=True) exclude_attribute_wms = models.TextField(_('Attributes excluded from wms'), blank=True, null=True) exclude_attribute_wfs = models.TextField(_('Attributes excluded from wfs'), blank=True, null=True) # possible layer relations vectorjoins = models.TextField(_('Layer relations'), blank=True, null=True) # editing widgets edittypes = models.TextField(_('Columns layer widgets'), blank=True, null=True) # not show attributes table not_show_attributes_table = models.BooleanField( _('Not show attributes table'), default=False, blank=True) # exclude from legend exclude_from_legend = models.BooleanField(_('Exclude to legend'), default=False, blank=True) # form editor layout editor_layout = models.CharField(_('Form editor layout'), max_length=100, blank=True, null=True) editor_form_structure = models.TextField(_('Editor form structure'), blank=True, null=True) download = models.BooleanField(_('Download data'), default=False, blank=True) download_xls = models.BooleanField(_('Download data in xls format'), default=False, blank=True) download_gpx = models.BooleanField(_('Download data in gpx format'), default=False, blank=True) download_csv = models.BooleanField(_('Download data in csv format'), default=False, blank=True) download_gpkg = models.BooleanField(_('Download data in gpkg format'), default=False, blank=True) # layer extension extent = models.TextField(_('Layer extension'), null=True, blank=True) # for layer WMS/WMST: set if load direct from their servers or from local QGIS-server external = models.BooleanField(_('Get WMS/WMS externally'), default=False, blank=True) # For temporal properties temporal_properties = models.TextField(_('Temporal properties'), null=True, blank=True) has_column_acl = models.BooleanField(_('Has column ACL constraints'), default=False, editable=False, db_index=True) objects = models.Manager() # The default manager. vectors = VectorLayersManager() @property def qgis_layer(self): """Returns the QgsMapLayer instance corresponding to this Layer, or None in case of errors :return: the QgsMapLayer instance :rtype: QgsVectorLayer or QgsRasterLayer """ layer = None try: return self.project.qgis_project.mapLayers()[self.qgs_layer_id] except: logger.warning('Cannot retrieve QgsMapLayer for QDjango layer %s' % self.qgs_layer_id) return layer @property def styles(self): """Returns the layer styles :return: list of dictionaries { name: '<style_name:str>', default: <bool> } :rtype: list """ styles = [] layer = self.qgis_layer if not layer is None: sm = layer.styleManager() for style in sm.styles(): styles.append({ 'name': style, 'current': style == sm.currentStyle() }) return styles def visible_fields_for_user(self, user): """Returns a list of field names visible by the user according to ColumnAcl""" if isinstance(self.qgis_layer, QgsVectorLayer): attributes = self.qgis_layer.fields().names() if self.has_column_acl: if user.is_anonymous: user = get_anonymous_user() for acl in self.columnacl_set.filter( models.Q(user=user) | models.Q(group__in=user.groups.all())): attributes = list( set(attributes) - set(acl.restricted_fields)) return attributes else: return [] def is_embedded(self): """Returns true if the layer is embedded from another project""" return self.parent_project is not None def style(self, name): """Returns the style from name :param style: name of the style to return :type style: str :return: The requested style :rtype: QgsMapLayerStyle """ layer = self.qgis_layer if layer is None: return QgsMapLayerStyle() sm = layer.styleManager() return sm.style(name) def styles_count(self): """Return number of styles""" return len(self.styles) def set_current_style(self, style): """Changes the current style :param style: name of the style to make current :type style: str :return: True on success :rtype: bool """ with QgisProjectFileLocker(self.project) as project: layer = self.qgis_layer if layer is None: return False sm = layer.styleManager() result = sm.setCurrentStyle(style) if result: result = result and project.update_qgis_project() return result def rename_style(self, style, new_name): """Renames a style :param style: name of the style to rename :type style: str :param new_name: new name of the style :type new_name: str :return: True on success :rtype: bool """ result = False with QgisProjectFileLocker(self.project) as project: layer = self.qgis_layer if layer is None: return False sm = layer.styleManager() if new_name in sm.styles(): return False result = sm.renameStyle(style, new_name) if result: result = result and project.update_qgis_project() return result def replace_style(self, style, qml): """Replaces the style QML :param style: name of the style to replace :type style: str :param qml: :type qml: str :return: True on success :rtype: bool """ result = False with QgisProjectFileLocker(self.project) as project: layer = self.qgis_layer if layer is None: return False sm = layer.styleManager() # Validate! doc = QDomDocument('qgis') if not doc.setContent(qml)[0]: return False tmp_layer = layer.clone() if not tmp_layer.importNamedStyle(doc)[0]: return False del (tmp_layer) # If the style is current, just replace it in the layer if sm.currentStyle() == style: return layer.importNamedStyle(doc)[0] else: new_style = QgsMapLayerStyle(qml) result = sm.addStyle(style, new_style) result = sm.removeStyle(style) and sm.addStyle( style, new_style) if result: assert self.style(style).xmlData() == new_style.xmlData() result = result and project.update_qgis_project() return result def delete_style(self, style): """Deletes a style :param style: name of the style to delete :type style: str :return: True on success :rtype: bool """ result = False with QgisProjectFileLocker(self.project) as project: layer = self.qgis_layer if layer is None: return False sm = layer.styleManager() result = sm.removeStyle(style) if result: result = result and project.update_qgis_project() return result def add_style(self, style, qml): """Deletes a style :param style: name of the new style :type style: str :param qml: :type qml: str :return: True on success :rtype: bool """ layer = self.qgis_layer if layer is None: return False result = False with QgisProjectFileLocker(self.project) as project: sm = layer.styleManager() if sm.currentStyle() == style: return False # Validate! doc = QDomDocument('qgis') if not doc.setContent(qml)[0]: return False tmp_layer = layer.clone() if not tmp_layer.importNamedStyle(doc)[0]: return False del (tmp_layer) new_style = QgsMapLayerStyle(qml) result = sm.addStyle(style, new_style) if result: result = result and project.update_qgis_project() return result @property def extent_rect(self): """Return dict of coordinates extension string :rtype: str """ rect = QgsRectangle().fromWkt(self.extent) return { 'minx': rect.xMinimum(), 'miny': rect.yMinimum(), 'maxx': rect.xMaximum(), 'maxy': rect.yMaximum() } def __str__(self): return self.name class Meta: verbose_name = _('Layer') verbose_name_plural = _('Layers') unique_together = (('name', 'project', 'qgs_layer_id'), ) ordering = ['order'] permissions = ( ('add_feature', 'Can add features to layer'), ('change_feature', 'Can update features geometry of layer'), ('delete_feature', 'Can delete features from layer'), ('change_attr_feature', 'Can update features attributes into layer'), ) def database_columns_by_name(self): return { db_col['name']: db_col for db_col in eval(self.database_columns) } def getWidgetsNumber(self): """ Count widgets for self layer :return: integer """ return len(get_widgets4layer(self)) def getConstraintsNumber(self): """ Count constraints for self layer :return: integer """ return len(get_constraints4layer(self)) def getColumnAclNumber(self): """ Count ColumnAcl for self layer :return: integer """ return self.columnacl_set.count() if self.has_column_acl else 0 def _permissionsToEditor(self, user, mode='add'): setPermissionUserObject(user, self, permissions=[ 'change_layer', 'delete_layer', 'view_layer', 'add_feature', 'change_feature', 'change_attr_feature', 'delete_feature' ], mode=mode) def _permissionsToViewers(self, users_id, mode='add'): # If user_id is in LayerAcl not add view_layer permission l_acl_users = [ la.user.pk for la in self.layeracl_set.filter(user__isnull=False) ] for user_id in users_id: execute = True if l_acl_users and user_id in l_acl_users and mode == 'add': execute = False if user_id in l_acl_users and mode != 'add': # Remove layer from LayerAcl self.layeracl_set.filter(user_id=user_id).delete() if execute: setPermissionUserObject(User.objects.get(pk=user_id), self, permissions='view_layer', mode=mode) def _permissions_to_user_groups_editor(self, groups_id, mode='add'): for group_id in groups_id: setPermissionUserObject(AuthGroup.objects.get(pk=group_id), self, permissions=[ 'change_layer', 'delete_layer', 'view_layer', 'add_feature', 'change_feature', 'change_attr_feature', 'delete_feature' ], mode=mode) def _permissions_to_user_groups_viewer(self, groups_id, mode='add'): # If group_id is in LayerAcl not add view_layer permission l_acl_groups = [ la.group.pk for la in self.layeracl_set.filter(group__isnull=False) ] for group_id in groups_id: execute = True if l_acl_groups and group_id in l_acl_groups and mode == 'add': execute = False if group_id in l_acl_groups and mode != 'add': # Remove layer from LayerAcl self.layeracl_set.filter(group_id=group_id).delete() if execute: setPermissionUserObject(AuthGroup.objects.get(pk=group_id), self, permissions=['view_layer'], mode=mode)
class Member(TimeStampedModel): id = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False, ) STATUS = Choices( ( -10, 'inactive', 'Inactive', ), ( 0, 'new', 'New', ), ( 10, 'active', 'Active', ), ) status = FSMIntegerField( help_text= """DO NOT CHANGE MANUALLY unless correcting a mistake. Use the buttons to change state.""", choices=STATUS, default=STATUS.new, ) # MEM_STATUS = Choices( # (10, 'active', 'Active',), # (20, 'active_internal', 'Active Internal',), # (30, 'active_licensed', 'Active Licensed',), # (40, 'cancelled', 'Cancelled',), # (50, 'closed', 'Closed',), # (60, 'closed_merged', 'Closed Merged',), # (70, 'closed_revoked', 'Closed Revoked',), # (80, 'closed_voluntary', 'Closed Voluntary',), # (90, 'expelled', 'Expelled',), # (100, 'expired', 'Expired',), # (105, 'expired_licensed', 'Expired Licensed',), # (110, 'lapsed', 'Lapsed',), # (120, 'not_approved', 'Not Approved',), # (130, 'pending', 'Pending',), # (140, 'pending_voluntary', 'Pending Voluntary',), # (150, 'suspended', 'Suspended',), # (160, 'suspended_membership', 'Suspended Membership',), # (170, 'awaiting_payment', 'Awaiting Payment',), # ) # mem_status = models.IntegerField( # choices=MEM_STATUS, # null=True, # blank=True, # ) # SUB_STATUS = Choices( # (10, 'active', 'Active',), # (20, 'expired', 'Expired',), # (30, 'pending', 'Pending',), # (40, 'lapsedRenew', 'Lapsed',), # (50, 'cancelled', 'Cancelled',), # (60, 'swapped', 'Swapped',), # ) # sub_status = models.IntegerField( # choices=SUB_STATUS, # null=True, # blank=True, # ) # MEM_CODE = Choices( # (10, 'RG', 'RG Regular'), # (20, 'R5', 'R5 Regular 50 Year'), # (30, 'SN', 'SN Senior'), # (40, 'S5', 'S5 Senior 50 Year'), # (50, 'SL', 'SL Senior Legacy'), # (60, 'Y1', 'Y1 Youth Initial'), # (70, 'Y2', 'Y2 Youth Subsequent'), # (80, 'LF', 'LF Lifetime Regular'), # (90, 'L5', 'L5 Lifetime 50 Year'), # (100, 'LY', 'LY Lifetime Youth'), # (110, 'LS', 'LS Lifetime Senior'), # (120, 'AS', 'AS Associate'), # ) # mem_code = models.IntegerField( # choices=MEM_CODE, # null=True, # blank=True, # ) # inactive_date = models.DateField( # null=True, # blank=True, # ) # INACTIVE_REASON = Choices( # (1, 'Non_renewal', 'Non-Renewal'), # (2, 'Renewed', 'Renewed'), # (3, 'NotCancelled', 'Not Cancelled'), # (4, 'Non_Payment', 'Non-Payment'), # (5, 'Expired', 'Expired'), # (6, 'Deceased', 'Deceased'), # (7, 'changedOption', 'changedOption'), # (8, 'Other', 'Other'), # (9, 'cancelled', 'cancelled'), # (10, 'Transferred', 'Transferred'), # (11, 'swappedChapter', 'swappedChapter'), # (12, 'swapped', 'swapped'), # ) # inactive_reason = models.IntegerField( # choices=INACTIVE_REASON, # null=True, # blank=True, # ) PART = Choices( # (-1, 'director', 'Director'), (1, 'tenor', 'Tenor'), (2, 'lead', 'Lead'), (3, 'baritone', 'Baritone'), (4, 'bass', 'Bass'), ) part = models.IntegerField( choices=PART, null=True, blank=True, ) start_date = models.DateField( null=True, blank=True, ) end_date = models.DateField( null=True, blank=True, ) mc_pk = models.CharField( null=True, blank=True, max_length=36, unique=True, db_index=True, ) # Properties @cached_property def is_mc(self): return bool(self.mc_pk) # FKs group = models.ForeignKey( 'Group', related_name='members', on_delete=models.CASCADE, ) person = models.ForeignKey( 'Person', related_name='members', on_delete=models.CASCADE, ) # Relations statelogs = GenericRelation( StateLog, related_query_name='members', ) # Internals objects = MemberManager() class Meta: unique_together = (( 'group', 'person', ), ) class JSONAPIMeta: resource_name = "member" def __str__(self): return str(self.id) def clean(self): if all([ self.status == self.STATUS.active, self.person.status == self.person.STATUS.inactive, ]): raise ValidationError({ 'status': 'Can not be active when person is inactive', }) if self.end_date: if all([ self.status == self.STATUS.active, self.end_date < now().date(), ]): raise ValidationError({ 'status': 'Can not be active with a passed end date', }) # Permissions @staticmethod @allow_staff_or_superuser @authenticated_users def has_read_permission(request): return True @allow_staff_or_superuser @authenticated_users def has_object_read_permission(self, request): return True @staticmethod @allow_staff_or_superuser @authenticated_users def has_write_permission(request): return any([ request.user.is_group_manager, ]) @allow_staff_or_superuser @authenticated_users def has_object_write_permission(self, request): return any([ all([ self.group.officers.filter( person__user=request.user, status__gt=0, ), self.mc_pk == None, ]), ]) # Transitions @fsm_log_by @fsm_log_description @transition(field=status, source='*', target=STATUS.active) def activate(self, description=None, *args, **kwargs): """Activate the Member.""" return @fsm_log_by @fsm_log_description @transition(field=status, source='*', target=STATUS.inactive) def deactivate(self, description=None, *args, **kwargs): """Deactivate the Member.""" return
class NormaJuridica(models.Model): ESFERA_FEDERACAO_CHOICES = Choices( ('M', 'municipal', _('Municipal')), ('E', 'estadual', _('Estadual')), ('F', 'federal', _('Federal')), ) texto_integral = models.FileField( blank=True, null=True, upload_to=norma_upload_path, verbose_name=_('Texto Integral'), storage=OverwriteStorage(), validators=[restringe_tipos_de_arquivo_txt]) tipo = models.ForeignKey(TipoNormaJuridica, on_delete=models.PROTECT, verbose_name=_('Tipo da Norma Jurídica')) materia = models.ForeignKey(MateriaLegislativa, blank=True, null=True, on_delete=models.PROTECT, verbose_name=_('Matéria')) numero = models.CharField(max_length=8, verbose_name=_('Número')) ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'), choices=RANGE_ANOS) esfera_federacao = models.CharField(max_length=1, verbose_name=_('Esfera Federação'), choices=ESFERA_FEDERACAO_CHOICES) data = models.DateField(blank=False, null=True, verbose_name=_('Data')) data_publicacao = models.DateField(blank=True, null=True, verbose_name=_('Data de Publicação')) veiculo_publicacao = models.CharField( max_length=30, blank=True, verbose_name=_('Veículo de Publicação')) pagina_inicio_publicacao = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Pg. Início')) pagina_fim_publicacao = models.PositiveIntegerField( blank=True, null=True, verbose_name=_('Pg. Fim')) ementa = models.TextField(verbose_name=_('Ementa')) indexacao = models.TextField(blank=True, verbose_name=_('Indexação')) observacao = models.TextField(blank=True, verbose_name=_('Observação')) complemento = models.NullBooleanField(blank=True, verbose_name=_('Complementar ?'), choices=YES_NO_CHOICES) # XXX was a CharField (attention on migrate) assuntos = models.ManyToManyField(AssuntoNorma, blank=True, verbose_name=_('Assuntos')) data_vigencia = models.DateField(blank=True, null=True, verbose_name=_('Data Fim Vigência')) timestamp = models.DateTimeField(null=True) texto_articulado = GenericRelation(TextoArticulado, related_query_name='texto_articulado') data_ultima_atualizacao = models.DateTimeField(blank=True, null=True, auto_now=True, verbose_name=_('Data')) autores = models.ManyToManyField(Autor, through='AutoriaNorma', through_fields=('norma', 'autor'), symmetrical=False) norma_de_destaque = models.BooleanField( verbose_name=_('Norma de Destaque ?'), choices=YES_NO_CHOICES, default=False) apelido = models.TextField(blank=True, verbose_name=_('Apelido')) user = models.ForeignKey(get_settings_auth_user_model(), verbose_name=_('Usuário'), on_delete=models.PROTECT, null=True, blank=True) ip = models.CharField(verbose_name=_('IP'), max_length=30, blank=True, default='') _certidao = GenericRelation(CertidaoPublicacao, related_query_name='normajuridica_cert') def diariooficial(self): if self.veiculo_publicacao: if not self.diariooficial_set.filter( edicao=self.veiculo_publicacao).exists(): from cmj.diarios.models import DiarioOficial d = DiarioOficial.objects.filter( edicao=self.veiculo_publicacao).last() if d: d.normas.add(self) return self.diariooficial_set.all() class Meta: verbose_name = _('Norma Jurídica') verbose_name_plural = _('Normas Jurídicas') ordering = ['-data', '-numero'] def get_normas_relacionadas(self): principais = NormaRelacionada.objects.filter( norma_principal=self.id).order_by('norma_principal__data', 'norma_relacionada__data') relacionadas = NormaRelacionada.objects.filter( norma_relacionada=self.id).order_by('norma_principal__data', 'norma_relacionada__data') return (principais, relacionadas) def get_anexos_norma_juridica(self): anexos = AnexoNormaJuridica.objects.filter(norma=self.id) return anexos @property def certidao(self): return self._certidao.all().first() @property def __descr__(self): return self.ementa def __str__(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo, 'numero': self.numero, 'data': defaultfilters.date(self.data, "d \d\e F \d\e Y") } @property def epigrafe(self): return _('%(tipo)s nº %(numero)s de %(data)s') % { 'tipo': self.tipo, 'numero': self.numero, 'data': defaultfilters.date(self.data, "d \d\e F \d\e Y") } def delete(self, using=None, keep_parents=False): if self.texto_integral: self.texto_integral.delete() return models.Model.delete(self, using=using, keep_parents=keep_parents) def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if not self.pk and self.texto_integral: texto_integral = self.texto_integral self.texto_integral = None models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) self.texto_integral = texto_integral return models.Model.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)