Ejemplo n.º 1
0
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',
        )
Ejemplo n.º 2
0
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,))
Ejemplo n.º 3
0
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()
Ejemplo n.º 4
0
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')
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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()
Ejemplo n.º 7
0
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
    },
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
# -*- 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)
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
0
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()
Ejemplo n.º 15
0
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.")
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
from model_utils import Choices

INGREDIENT_STATUS_CHOICES = Choices("empty", "low", "full")
Ejemplo n.º 18
0
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
Ejemplo n.º 19
0
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'),
)

Ejemplo n.º 20
0
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'],
        ]
Ejemplo n.º 21
0
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})

Ejemplo n.º 22
0
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}"

Ejemplo n.º 23
0
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):
Ejemplo n.º 24
0
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):
Ejemplo n.º 26
0
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)
Ejemplo n.º 27
0
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()
Ejemplo n.º 28
0
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)
Ejemplo n.º 29
0
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
Ejemplo n.º 30
0
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)