Ejemplo n.º 1
0
 def get_virtualfield(cls, name):
     format_num = None
     field_title = None
     if name == "str":
         field_title = ''
     elif name[:7] == "custom_":
         cf_id = int(name[7:])
         cf_model = CustomField.objects.get(id=cf_id)
         field_title = cf_model.name
         if cf_model.kind == 0:
             format_num = None
         if cf_model.kind == 1:
             format_num = 'N0'
         if cf_model.kind == 2:
             format_num = 'N%d' % cf_model.get_args()['prec']
         if cf_model.kind == 3:
             format_num = 'B'
         if cf_model.kind == 4:
             format_num = {}
             args_list = cf_model.get_args()['list']
             for list_index in range(len(args_list)):
                 format_num[six.text_type(
                     list_index)] = args_list[list_index]
     if field_title is not None:
         return LucteriosVirtualField(verbose_name=field_title,
                                      name=name,
                                      compute_from=name,
                                      format_string=lambda: format_num)
     return None
Ejemplo n.º 2
0
class Example(LucteriosModel):

    name = models.CharField(max_length=75, unique=True)
    value = models.IntegerField(
        validators=[MinValueValidator(0),
                    MaxValueValidator(20)])
    price = LucteriosDecimalField(
        max_digits=6,
        decimal_places=2,
        default=100.0,
        validators=[MinValueValidator(-5000.0),
                    MaxValueValidator(5000.0)],
        format_string=
        "C2EUR;{[font color='green']}%s{[/font]};{[font color='red']}%s{[/font]}"
    )
    date = models.DateField(null=True)
    time = models.TimeField()
    valid = models.BooleanField(default=False)
    comment = models.TextField(blank=True)
    virtual = LucteriosVirtualField(verbose_name='reduction',
                                    compute_from='get_virtual',
                                    format_string="N4")

    def __str__(self):
        return self.name

    def get_virtual(self):
        if self.id is None:
            return None
        elif (self.price is None) or (self.value is None):
            return 0
        else:
            return float(self.price) * float(self.value) / 100.0

    @classmethod
    def get_show_fields(cls):
        return [
            'name', ('value', 'price'), ('date', 'time'), 'virtual', 'valid',
            'comment'
        ]

    @classmethod
    def get_edit_fields(cls):
        return [
            'name', ('value', 'price'), ('date', 'time'), 'valid', 'comment'
        ]

    @classmethod
    def get_search_fields(cls):
        return ['name', 'value', 'price', 'date', 'time', 'valid', 'comment']

    @classmethod
    def get_default_fields(cls):
        return ["name", 'value', 'price']

    @classmethod
    def get_print_fields(cls):
        return cls.get_search_fields()
Ejemplo n.º 3
0
class AbstractContainer(LucteriosModel):

    parent = models.ForeignKey('FolderContainer', verbose_name=_('parent'), null=True, on_delete=models.CASCADE)
    name = models.CharField(_('name'), max_length=250, blank=False)
    description = models.TextField(_('description'), blank=True)
    icon = LucteriosVirtualField(verbose_name='', compute_from='get_icon', format_string='icon')
    modif = LucteriosVirtualField(verbose_name=_('modifier'), compute_from='get_modif', )
    date_modif = LucteriosVirtualField(verbose_name=_('date modification'), compute_from='get_date_modif', format_string='H')

    @classmethod
    def get_default_fields(cls):
        return ['icon', "name", "description", "modif", "date_modif"]

    def get_icon(self):
        if isinstance(self.get_final_child(), FolderContainer):
            icon_name = "folder.png"
        else:
            icon_name = "file.png"
        img = readimage_to_base64(join(dirname(__file__), "static", 'lucterios.documents', "images", icon_name))
        return img.decode('ascii')

    def get_modif(self):
        final_container = self.get_final_child()
        if isinstance(final_container, DocumentContainer):
            return final_container.modifier
        return None

    def get_date_modif(self):
        final_container = self.get_final_child()
        if isinstance(final_container, DocumentContainer):
            return final_container.date_modification
        return None

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        self.name = self.name[:250]
        return LucteriosModel.save(self, force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)

    class Meta(object):
        verbose_name = _('container')
        verbose_name_plural = _('containers')
        default_permissions = []
        ordering = ['-foldercontainer__isnull', 'parent__name', 'name']
Ejemplo n.º 4
0
class ContactCustomField(LucteriosModel):
    contact = models.ForeignKey('AbstractContact',
                                verbose_name=_('contact'),
                                null=False,
                                on_delete=models.CASCADE)
    field = models.ForeignKey('CustomField',
                              verbose_name=_('field'),
                              null=False,
                              on_delete=models.CASCADE)
    value = models.TextField(_('value'), default="")

    data = LucteriosVirtualField(verbose_name=_('value'),
                                 compute_from='get_data')

    def get_data(self):
        data = None
        if self.field.kind == 0:
            data = six.text_type(self.value)
        else:
            data = self.value
        if data == '':
            data = '0'
        if self.field.kind == 1:
            data = int(data)
        if self.field.kind == 2:
            data = float(data)
        if self.field.kind == 3:
            data = (data != 'False') and (data != '0') and (data != '') and (
                data != 'n')
        if self.field.kind == 4:
            data = int(data)
        dep_field = CustomizeObject.get_virtualfield(
            self.field.get_fieldname())
        return get_format_value(dep_field, data)

    def get_auditlog_object(self):
        return self.contact.get_final_child()

    class Meta(object):
        verbose_name = _('custom field value')
        verbose_name_plural = _('custom field values')
        default_permissions = []
Ejemplo n.º 5
0
class Parameter(LucteriosModel):
    name = models.CharField(_('name'), max_length=100, unique=True)
    typeparam = models.IntegerField(choices=((0, _('String')),
                                             (1, _('Integer')), (2, _('Real')),
                                             (3, _('Boolean')), (4,
                                                                 _('Select'))))
    args = models.CharField(_('arguments'), max_length=200, default="{}")
    value = models.TextField(_('value'), blank=True)
    metaselect = models.TextField('meta', blank=True)

    value_txt = LucteriosVirtualField(verbose_name=_('value'),
                                      compute_from='get_value')

    def __str__(self):
        return six.text_type(ugettext_lazy(self.name))

    @classmethod
    def check_and_create(cls,
                         name,
                         typeparam,
                         title,
                         args,
                         value,
                         param_titles=None,
                         meta=None):
        param, created = Parameter.objects.get_or_create(name=name,
                                                         typeparam=typeparam)
        if created:
            param.title = title
            param.param_titles = param_titles
            param.args = args
            param.value = value
            if meta is not None:
                param.metaselect = meta
            param.save()
        elif meta is not None:
            param.metaselect = meta
            param.save()
        elif param.args != args:
            param.args = args
            param.save()
        return created

    @classmethod
    def change_value(cls, pname, pvalue):
        db_param = cls.objects.get(name=pname)
        if (db_param.typeparam == 3) and isinstance(pvalue, six.text_type):
            db_param.value = six.text_type((pvalue == '1') or (pvalue == 'o'))
        else:
            db_param.value = pvalue
        db_param.save()

    def get_meta_select(self):
        from django.db.models import Q
        import importlib
        meta_select = None
        if self.metaselect != "":
            meta_select = eval(self.metaselect)
            if (len(meta_select) == 5) and isinstance(
                    meta_select[0], six.text_type) and isinstance(
                        meta_select[1], six.text_type) and isinstance(
                            meta_select[3], six.text_type) and isinstance(
                                meta_select[4], bool):
                if isinstance(meta_select[2], six.text_type):
                    meta_select = list(meta_select)
                    sys_modules = dict(sys.modules)
                    last = None
                    for item_val in meta_select[2].split(';'):
                        if item_val.startswith('import '):
                            module_name = item_val[7:]
                            mod_imported = importlib.import_module(module_name)
                            sys_modules[module_name] = mod_imported
                        else:
                            last = eval(item_val, sys_modules)
                    meta_select[2] = last
                elif not isinstance(meta_select[2], Q) and not isinstance(
                        meta_select[2], list):
                    meta_select = None
            else:
                meta_select = None
        return meta_select

    def get_value(self):
        from lucterios.CORE.parameters import ParamCache
        param = ParamCache(self.name, self)
        return six.text_type(param.get_read_text())

    class Meta(object):
        verbose_name = _('parameter')
        verbose_name_plural = _('parameters')
        default_permissions = ['add', 'change']
Ejemplo n.º 6
0
class Parameter(LucteriosModel):
    TYPE_STRING = 0
    TYPE_INTEGER = 1
    TYPE_REAL = 2
    TYPE_BOOL = 3
    TYPE_SELECT = 4
    TYPE_PASSWORD = 5
    TYPE_META = 6
    TYPE_LIST = ((TYPE_STRING, _('String')), (TYPE_INTEGER, _('Integer')),
                 (TYPE_REAL, _('Real')), (TYPE_BOOL, _('Boolean')),
                 (TYPE_SELECT, _('Select')), (TYPE_PASSWORD, _('Password')),
                 (TYPE_META, _('Meta')))

    name = models.CharField(_('name'), max_length=100, unique=True)
    typeparam = models.IntegerField(choices=TYPE_LIST, default=0)
    args = models.CharField(_('arguments'), max_length=200, default="{}")
    value = models.TextField(_('value'), blank=True)
    metaselect = models.TextField('meta', blank=True)

    value_txt = LucteriosVirtualField(verbose_name=_('value'),
                                      compute_from='get_value')

    def __str__(self):
        return six.text_type(ugettext_lazy(self.name))

    @classmethod
    def check_and_create(cls,
                         name,
                         typeparam,
                         title,
                         args,
                         value,
                         param_titles=None,
                         meta=None):
        param, created = Parameter.objects.get_or_create(name=name)
        if created:
            param.title = title
            param.typeparam = typeparam
            param.param_titles = param_titles
            param.args = args
            param.value = value
            if meta is not None:
                param.metaselect = meta
            param.save()
        elif param.typeparam != typeparam:
            param.typeparam = typeparam
            param.param_titles = param_titles
            if meta is not None:
                param.metaselect = meta
            param.args = args
            param.save()
        elif meta is not None:
            param.metaselect = meta
            param.save()
        elif param.args != args:
            param.args = args
            param.save()
        return created

    @classmethod
    def change_value(cls, pname, pvalue):
        db_param = cls.objects.get(name=pname)
        if (db_param.typeparam == cls.TYPE_BOOL) and isinstance(
                pvalue, six.text_type):
            db_param.value = six.text_type((pvalue == '1') or (pvalue == 'o'))
        else:
            db_param.value = pvalue
        db_param.save()

    def _meta_from_script(self, meta_select):
        import importlib
        meta_select = list(meta_select)
        sys_modules = dict(sys.modules)
        last = None
        for item_val in meta_select[2].split(';'):
            if item_val.startswith('import '):
                module_name = item_val[7:]
                mod_imported = importlib.import_module(module_name)
                sys_modules[module_name] = mod_imported
            else:
                last = eval(item_val, sys_modules)
        meta_select[2] = last
        return meta_select

    def get_meta_select(self):
        from django.db.models import Q
        meta_select = None
        if self.metaselect != "":
            meta_select = eval(self.metaselect)
            if (len(meta_select) == 5) and isinstance(
                    meta_select[0], six.text_type) and isinstance(
                        meta_select[1], six.text_type) and isinstance(
                            meta_select[3], six.text_type) and isinstance(
                                meta_select[4], bool):
                if isinstance(meta_select[2], six.text_type):
                    meta_select = self._meta_from_script(meta_select)
                elif not isinstance(meta_select[2], Q) and not isinstance(
                        meta_select[2], list):
                    meta_select = None
            else:
                meta_select = None
        return meta_select

    def get_value(self):
        from lucterios.CORE.parameters import ParamCache
        param = ParamCache(self.name, self)
        return six.text_type(param.get_read_text())

    def convert_to_int(self):
        try:
            return int(self.value)
        except ValueError:
            if self.value == 'False':
                return 0
            if self.value == 'True':
                return 1
            return int('0' + self.value)

    def convert_to_float(self):
        try:
            return float(self.value)
        except ValueError:
            return float('0' + self.value)

    class Meta(object):
        verbose_name = _('parameter')
        verbose_name_plural = _('parameters')
        default_permissions = ['add', 'change']
Ejemplo n.º 7
0
class Participant(LucteriosModel):
    event = models.ForeignKey(Event,
                              verbose_name=_('event'),
                              null=False,
                              default=None,
                              db_index=True,
                              on_delete=models.CASCADE)
    contact = models.ForeignKey(Individual,
                                verbose_name=_('contact'),
                                null=False,
                                default=None,
                                db_index=True,
                                on_delete=models.CASCADE)
    degree_result = models.ForeignKey(DegreeType,
                                      verbose_name=_('degree result'),
                                      null=True,
                                      default=None,
                                      db_index=True,
                                      on_delete=models.CASCADE)
    subdegree_result = models.ForeignKey(SubDegreeType,
                                         verbose_name=_('sub-degree result'),
                                         null=True,
                                         default=None,
                                         db_index=True,
                                         on_delete=models.CASCADE)
    comment = models.TextField(_('comment'), blank=True)
    article = models.ForeignKey(Article,
                                verbose_name=_('article'),
                                null=True,
                                default=None,
                                on_delete=models.PROTECT)
    reduce = models.DecimalField(
        verbose_name=_('reduce'),
        max_digits=10,
        decimal_places=3,
        default=0.0,
        validators=[MinValueValidator(0.0),
                    MaxValueValidator(9999999.999)])
    bill = models.ForeignKey(Bill,
                             verbose_name=_('bill'),
                             null=True,
                             default=None,
                             on_delete=models.SET_NULL)

    is_subscripter = LucteriosVirtualField(verbose_name=_('subscript?'),
                                           compute_from='get_is_subscripter',
                                           format_string='B')
    current_degree = LucteriosVirtualField(verbose_name=_('current'),
                                           compute_from='get_current_degree')
    article_ref_price = LucteriosVirtualField(
        verbose_name=_('article'), compute_from='get_article_ref_price')

    def __str__(self):
        return six.text_type(self.contact)

    def get_auditlog_object(self):
        return self.event

    @classmethod
    def get_default_fields(cls):
        fields = [
            "contact", 'is_subscripter', 'current_degree',
            (_('%s result') % Params.getvalue("event-degree-text"),
             'degree_result_simple')
        ]
        if Params.getvalue("event-subdegree-enable") == 1:
            fields.append(
                (_('%s result') % Params.getvalue("event-subdegree-text"),
                 'subdegree_result'))
        fields.append('article_ref_price')
        fields.append('comment')
        return fields

    @classmethod
    def get_edit_fields(cls):
        return ["contact", 'comment', 'article', 'reduce']

    @classmethod
    def get_show_fields(cls):
        return [
            "contact", 'degree_result', 'subdegree_result', 'comment',
            'article', 'reduce'
        ]

    def get_article_ref_price(self):
        if self.article_id is None:
            return None
        elif abs(self.reduce) > 0.0001:
            return "%s (-%s)" % (self.article.ref_price,
                                 get_amount_from_format_devise(self.reduce, 7))
        else:
            return self.article.ref_price

    def get_current_degree_ex(self):
        degree_list = Degree.objects.filter(
            Q(adherent_id=self.contact_id)
            & Q(degree__activity=self.event.activity)).distinct().order_by(
                '-degree__level', '-subdegree__level')
        if len(degree_list) > 0:
            return degree_list[0]
        else:
            return None

    def get_current_degree(self):
        degree = self.get_current_degree_ex()
        if degree is not None:
            return degree.get_text()
        else:
            return ""

    @property
    def degree_result_simple(self):
        if self.degree_result is not None:
            return self.degree_result.name
        else:
            return None

    def get_is_subscripter(self):
        return len(
            Subscription.objects.filter(adherent_id=self.contact_id,
                                        season=Season.get_from_date(
                                            self.event.date))) > 0

    def allow_degree(self):
        degree = self.get_current_degree_ex()
        if degree is not None:
            return DegreeType.objects.filter(
                level__gte=degree.degree.level,
                activity=self.event.activity).distinct().order_by('level')
        else:
            return DegreeType.objects.filter(
                activity=self.event.activity).distinct().order_by('level')

    def allow_subdegree(self):
        return SubDegreeType.objects.all().order_by('level')

    def give_result(self, degree, subdegree, comment):
        self.degree_result_id = degree
        if self.degree_result_id == 0:
            self.degree_result_id = None
        self.subdegree_result_id = subdegree
        if self.subdegree_result_id == 0:
            self.subdegree_result_id = None
        if (self.degree_result_id is
                None) and not (self.subdegree_result_id is None):
            old_degree = self.get_current_degree()
            self.degree_result = old_degree.degree
        if comment is not None:
            self.comment = comment
        self.save()
        if not (self.degree_result is None):
            try:
                adh = Adherent.objects.get(id=self.contact_id)
                Degree.objects.create(adherent=adh,
                                      degree=self.degree_result,
                                      subdegree=self.subdegree_result,
                                      date=self.event.date,
                                      event=self.event)
            except Exception:
                pass

    def _search_or_create_bill(self):
        high_contact = self.contact.get_final_child()
        new_third = get_or_create_customer(high_contact.get_ref_contact().id)
        bill_list = Bill.objects.filter(
            third=new_third, bill_type=1,
            status=0).annotate(participant_count=Count('participant')).filter(
                participant_count__gte=1).order_by('-date')
        if len(bill_list) > 0:
            self.bill = bill_list[0]
        if self.bill is None:
            self.bill = Bill.objects.create(bill_type=1,
                                            date=date.today(),
                                            third=new_third)
        return high_contact

    def create_bill(self):
        if self.article is not None:
            high_contact = self._search_or_create_bill()
            bill_comment = [
                "{[b]}%s{[/b]}: %s" %
                (self.event.event_type_txt, self.event.date_txt)
            ]
            bill_comment.append("{[i]}%s{[/i]}" % self.event.comment)
            if (self.bill.third.contact.id
                    == high_contact.id) and (self.event.event_type == 1) and (
                        self.comment is not None) and (self.comment != ''):
                bill_comment.append(self.comment)
            self.bill.comment = "{[br/]}".join(bill_comment)
            self.bill.save()
            self.bill.detail_set.all().delete()
            participant_list = list(self.bill.participant_set.all())
            if self not in participant_list:
                participant_list.append(self)
            for participant in participant_list:
                detail_comment = [participant.article.designation]
                if participant.bill.third.contact.id != participant.contact.id:
                    detail_comment.append(
                        _("Participant: %s") %
                        six.text_type(participant.contact))
                    if (participant.event.event_type
                            == 1) and (participant.comment is not None) and (
                                participant.comment != ''):
                        detail_comment.append(participant.comment)
                Detail.create_for_bill(
                    participant.bill,
                    participant.article,
                    reduce=participant.reduce,
                    designation="{[br/]}".join(detail_comment))
            self.save()

    def can_delete(self):
        if self.event.status > 0:
            return _('%s validated!') % self.event.event_type_txt
        if self.bill is not None:
            return self.bill.can_delete()
        return ''

    def delete(self, using=None):
        if self.bill is not None:
            self.bill.delete()
        LucteriosModel.delete(self, using=using)

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        if (self.id is None) and (self.event.event_type == 0) and (
            (self.comment is None) or (self.comment == '')):
            self.comment = Params.getvalue("event-comment-text")
        if (self.id is None) and self.is_subscripter and (
                self.event.default_article is not None):
            self.article = self.event.default_article
        if (self.id is None) and not self.is_subscripter and (
                self.event.default_article_nomember is not None):
            self.article = self.event.default_article_nomember
        return LucteriosModel.save(self,
                                   force_insert=force_insert,
                                   force_update=force_update,
                                   using=using,
                                   update_fields=update_fields)

    class Meta(object):
        verbose_name = _('participant')
        verbose_name_plural = _('participants')
        default_permissions = []
Ejemplo n.º 8
0
class Event(LucteriosModel):
    activity = models.ForeignKey(Activity,
                                 verbose_name=_('activity'),
                                 null=False,
                                 default=None,
                                 db_index=True,
                                 on_delete=models.PROTECT)
    date = models.DateField(verbose_name=_('date'), null=False)
    comment = models.TextField(_('comment'), blank=False)
    status = FSMIntegerField(verbose_name=_('status'),
                             choices=((0, _('building')), (1, _('valid'))),
                             null=False,
                             default=0,
                             db_index=True)
    event_type = models.IntegerField(verbose_name=_('event type'),
                                     choices=((0, _('examination')),
                                              (1, _('trainning/outing'))),
                                     null=False,
                                     default=0,
                                     db_index=True)
    date_end = models.DateField(verbose_name=_('end date'), null=True)
    default_article = models.ForeignKey(
        Article,
        verbose_name=_('default article (member)'),
        related_name="event",
        null=True,
        default=None,
        on_delete=models.PROTECT)
    default_article_nomember = models.ForeignKey(
        Article,
        verbose_name=_('default article (no member)'),
        related_name="eventnomember",
        null=True,
        default=None,
        on_delete=models.PROTECT)
    cost_accounting = models.ForeignKey(CostAccounting,
                                        verbose_name=_('cost accounting'),
                                        null=True,
                                        default=None,
                                        db_index=True,
                                        on_delete=models.PROTECT)

    date_txt = LucteriosVirtualField(verbose_name=_('date'),
                                     compute_from='get_date_txt')

    def __str__(self):
        if Params.getvalue("member-activite-enable"):
            return "%s %s" % (self.activity, self.date)
        else:
            return six.text_type(self.date)

    @classmethod
    def get_default_fields(cls):
        if Params.getvalue("member-activite-enable"):
            return [(Params.getvalue("member-activite-text"), "activity"),
                    'status', 'event_type', 'date_txt', 'comment']
        else:
            return ['status', 'event_type', ('date', 'date_txt'), 'comment']

    @classmethod
    def get_edit_fields(cls):
        field = []
        if Params.getvalue("member-activite-enable"):
            field.append(
                ((Params.getvalue("member-activite-text"), "activity"), ))
        field.extend([
            'status', 'event_type', 'date', 'date_end', 'default_article',
            'default_article_nomember', 'comment'
        ])
        return field

    @classmethod
    def get_show_fields(cls):
        field = [('date', 'date_end')]
        if Params.getvalue("member-activite-enable"):
            field.append(('status', (Params.getvalue("member-activite-text"),
                                     "activity")))
        else:
            field.append(('status', ))
        field.extend([
            'organizer_set', 'participant_set', ('comment', ),
            ((_('default article (member)'), 'default_article.ref_price'),
             (_('default article (no member)'),
              'default_article_nomember.ref_price'))
        ])
        return field

    @classmethod
    def get_search_fields(cls):
        return ['status', 'event_type', 'date', 'date_end', 'comment']

    @property
    def event_type_txt(self):
        return get_value_if_choices(self.event_type,
                                    self._meta.get_field('event_type'))

    def get_date_txt(self):
        if self.event_type == 0:
            return get_date_formating(self.date)
        else:
            return "%s -> %s" % (get_date_formating(
                self.date), get_date_formating(self.date_end))

    def can_delete(self):
        if self.status > 0:
            return _('%s validated!') % self.event_type_txt
        return ''

    def save(self,
             force_insert=False,
             force_update=False,
             using=None,
             update_fields=None):
        if self.event_type == 0:
            self.date_end = None
        elif (self.date_end is None) or (self.date_end < self.date):
            self.date_end = self.date
        return LucteriosModel.save(self,
                                   force_insert=force_insert,
                                   force_update=force_update,
                                   using=using,
                                   update_fields=update_fields)

    def chech_validity(self):
        msg = ''
        if self.status > 0:
            msg = _('%s validated!') % get_value_if_choices(
                self.event_type, self._meta.get_field('event_type'))
        elif len(self.organizer_set.filter(isresponsible=True)) == 0:
            msg = _('no responsible!')
        elif len(self.participant_set.all()) == 0:
            msg = _('no participant!')
        return msg

    def can_be_valid(self):
        msg = self.chech_validity()
        if msg != '':
            raise LucteriosException(IMPORTANT, msg)

    transitionname__validate = _("Validation")

    @transition(field=status,
                source=0,
                target=1,
                conditions=[lambda item: item.chech_validity() == ''])
    def validate(self):
        for participant in self.participant_set.all():
            participant.give_result(
                self.xfer.getparam('degree_%d' % participant.id, 0),
                self.xfer.getparam('subdegree_%d' % participant.id, 0),
                self.xfer.getparam('comment_%d' % participant.id))
            participant.create_bill()

    class Meta(object):
        verbose_name = _('event')
        verbose_name_plural = _('events')
        ordering = ['-date']
Ejemplo n.º 9
0
class Message(LucteriosModel):
    subject = models.CharField(_('subject'), max_length=50, blank=False)
    body = models.TextField(_('body'), default="")
    status = FSMIntegerField(verbose_name=_('status'),
                             default=0,
                             choices=((0, _('open')), (1, _('valided')),
                                      (2, _('sending'))))
    recipients = models.TextField(_('recipients'), default="", null=False)
    date = models.DateField(verbose_name=_('date'), null=True)
    contact = models.ForeignKey('contacts.AbstractContact',
                                verbose_name=_('contact'),
                                null=True,
                                on_delete=models.SET_NULL)
    email_to_send = models.TextField(_('email to send'), default="")
    documents = models.ManyToManyField(Document,
                                       verbose_name=_('documents'),
                                       blank=True)
    attachments = models.ManyToManyField(DocumentContainer,
                                         verbose_name=_('documents'),
                                         blank=True)
    doc_in_link = models.BooleanField(_('documents in link'),
                                      null=False,
                                      default=False)
    contact_nb = LucteriosVirtualField(verbose_name=_('number of recipients'),
                                       compute_from='get_contact_nb',
                                       format_string='N')
    contact_noemail = LucteriosVirtualField(
        verbose_name=_('without email address'),
        compute_from='get_contact_noemail')

    def __init__(self, *args, **kwargs):
        LucteriosModel.__init__(self, *args, **kwargs)
        self._show_only_failed = False
        self._last_xfer = None

    def set_context(self, xfer):
        self._show_only_failed = xfer.getparam('show_only_failed', False)
        self._last_xfer = xfer

    @property
    def emailsent_query(self):
        if self._show_only_failed:
            return ~models.Q(error='')
        else:
            return models.Q()

    @classmethod
    def get_default_fields(cls):
        return ['status', 'date', 'subject', 'contact_nb']

    @classmethod
    def get_show_fields(cls):
        return {
            '': [('status', 'date')],
            _('001@Message'): ['subject', 'body'],
            _('002@Recipients'):
            ['recipients', ('contact_nb', 'contact_noemail')],
            _('003@Documents'):
            ['attachments', (('', 'empty'), ), 'doc_in_link']
        }

    @property
    def empty(self):
        return ""

    def get_contact_nb(self):
        return len(self.get_contacts())

    @property
    def line_set(self):
        return MessageLineSet(hints={'body': self.body})

    def get_contact_noemail(self):
        no_emails = self.get_contacts(False)
        return [six.text_type(no_email) for no_email in no_emails]

    @classmethod
    def get_edit_fields(cls):
        return ['subject', 'body', 'doc_in_link']

    @classmethod
    def get_print_fields(cls):
        return [
            'status', 'date', 'subject', 'body', 'line_set', 'line_set.line',
            'contact', 'OUR_DETAIL'
        ]

    def get_recipients(self):
        for item in self.recipients.split('\n'):
            if item != '':
                modelname, criteria = item.split(' ')
                yield modelname, get_search_query_from_criteria(
                    criteria, apps.get_model(modelname))

    def get_contacts(self, email=None):
        def append_contact(new_contact):
            if new_contact not in contact_list:
                contact_list.append(new_contact)

        contact_list = []
        for modelname, item in self.get_recipients():
            model = apps.get_model(modelname)
            contact_filter = item[0]
            if (email is not None) and (model.get_field_by_name('email') is
                                        None):
                for contact in model.objects.filter(contact_filter).distinct():
                    if (email is True) and hasattr(
                            contact,
                            'get_email') and (contact.get_email() != []):
                        append_contact(contact)
                    elif (email is
                          False) and (not hasattr(contact, 'get_email') or
                                      (contact.get_email() == [])):
                        append_contact(contact)
            else:
                if (email is not None) and (model.get_field_by_name('email')
                                            is not None):
                    contact_filter &= ~models.Q(
                        email='') if email else models.Q(email='')
                for contact in model.objects.filter(contact_filter).distinct():
                    append_contact(contact)
        return contact_list

    @property
    def recipients_description(self):
        for modelname, item in self.get_recipients():
            model = apps.get_model(modelname)
            yield (model._meta.verbose_name.title(),
                   " {[br/]}".join(item[1].values()))

    def add_recipient(self, modelname, criteria):
        if self.status == 0:
            self.recipients += modelname + ' ' + criteria + "\n"
            self.save()

    def del_recipient(self, recipients):
        if (self.status == 0) and (recipients >= 0):
            recipient_list = self.recipients.split('\n')
            if recipients < len(recipient_list):
                del recipient_list[recipients]
                self.recipients = "\n".join(recipient_list)
                self.save()

    transitionname__valid = _("Valid")

    @transition(field=status,
                source=0,
                target=1,
                conditions=[lambda item: item.recipients != ''])
    def valid(self):
        self.date = date.today()

    def get_printmodel_names(self):
        printmodel_name = {}
        for last_sending_item in self.email_to_send.split('\n'):
            if len(last_sending_item.split(':')) == 3:
                printmodel_name[last_sending_item.split(':')
                                [0]] = last_sending_item.split(':')[2]
        for old_emailsent in self.emailsent_set.all():
            last_sending_item = old_emailsent.email
            if len(last_sending_item.split(':')) == 3:
                printmodel_name[last_sending_item.split(':')
                                [0]] = last_sending_item.split(':')[2]
        return printmodel_name

    @property
    def is_dynamic(self):
        return len(self.get_printmodel_names()) > 0

    def _prep_sending(self):
        email_list = []
        printmodel_name = self.get_printmodel_names()
        for contact in self.get_contacts(True):
            if len(printmodel_name) == 0:
                for email1 in contact.email.split(';'):
                    for email2 in email1.split(','):
                        if (":%s|" % email2) not in ("|".join(email_list) +
                                                     '|'):
                            email_list.append("%d:%s" % (contact.id, email2))
            else:
                model_name = contact.__class__.get_long_name()
                email_list.append(
                    "%s:%d:%s" %
                    (model_name, contact.id, printmodel_name[model_name]
                     if model_name in printmodel_name.keys() else "0"))
        self.email_to_send = "\n".join(email_list)
        self.save()
        self.emailsent_set.all().delete()

    transitionname__sending = _("Emails")

    @transition(field=status,
                source=1,
                target=2,
                conditions=[lambda item: will_mail_send()])
    def sending(self):
        if will_mail_send():
            self._prep_sending()
            if self._last_xfer is not None:
                abs_url = self._last_xfer.request.META.get(
                    'HTTP_REFERER',
                    self._last_xfer.request.build_absolute_uri()).split('/')
                root_url = '/'.join(abs_url[:-2])
            else:
                root_url = ''
            getLogger('lucterios.mailing').debug(
                'Message.sending() -> add_mailing_in_scheduler(http_root_address=%s)',
                root_url)
            add_mailing_in_scheduler(check_nb=False,
                                     http_root_address=root_url)
        return

    def define_email_message(self):
        if not hasattr(self, 'http_root_address'):
            raise LucteriosException(GRAVE, "No http_root_address")
        link_html = ""
        self._attache_files = []
        for doc in self.attachments.all():
            if self.doc_in_link:
                if doc.sharekey is None:
                    doc.change_sharekey(False)
                    doc.save()
                doc.set_context(self.http_root_address)
                link_html += "<li><a href='%s'>%s</a></li>" % (doc.shared_link,
                                                               doc.name)
            else:
                self._attache_files.append((doc.name, doc.content))
        if self.doc_in_link and (link_html != ''):
            link_html = "<hr/><h3>%s</h3><ul>%s</ul>" % (_('Shared documents'),
                                                         link_html)
        self._email_content = "<html><body>%s%s</body></html>" % (toHtml(
            self.body), link_html)

    @property
    def email_content(self):
        if not hasattr(self, '_email_content'):
            self.define_email_message()
        return self._email_content

    @property
    def attach_files(self):
        if not hasattr(self, '_attache_files'):
            self.define_email_message()
        return self._attache_files

    def sendemail(self, nb_to_send, http_root_address):
        getLogger('lucterios.mailing').debug(
            'Message.sendemail(nb_to_send=%s, http_root_address=%s)',
            nb_to_send, http_root_address)
        self.http_root_address = http_root_address
        if will_mail_send() and (self.status == 2):
            email_list = self.email_to_send.split("\n")
            for contact_email in email_list[:nb_to_send]:
                contact_email_det = contact_email.split(':')
                if len(contact_email_det) == 2:
                    contact_id, email = contact_email_det
                    try:
                        contact = AbstractContact.objects.get(id=contact_id)
                    except AbstractContact.DoesNotExist:
                        contact = None
                elif len(contact_email_det) == 3:
                    modelname, object_id, _printmodel = contact_email_det
                    model = apps.get_model(modelname)
                    item = model.objects.get(id=object_id)
                    if hasattr(item, 'contact'):
                        contact = item.contact
                    elif isinstance(item, AbstractContact):
                        contact = item
                    else:
                        contact = None
                    email = contact_email
                else:
                    continue
                email_sent = EmailSent.objects.create(message=self,
                                                      contact=contact,
                                                      email=email,
                                                      date=timezone.now())
                email_sent.send_email(http_root_address)
            self.email_to_send = "\n".join(email_list[nb_to_send:])
            if self.email_to_send == '':
                self.status = 1
            self.save()
        return

    def get_email_status(self):
        if not hasattr(self, '_email_status'):
            self._email_status = json.loads(self.email_sent)
        return self._email_status

    @property
    def date_begin(self):
        emails_sent = self.emailsent_set.order_by('date')
        if len(emails_sent) > 0:
            return get_date_formating(emails_sent[0].date)
        return '---'

    @property
    def date_end(self):
        emails_sent = self.emailsent_set.order_by('-date')
        if len(emails_sent) > 0:
            return get_date_formating(emails_sent[0].date)
        return '---'

    @property
    def nb_total(self):
        return self.emailsent_set.all().count()

    @property
    def nb_errors(self):
        return self.emailsent_set.filter(success=False).count()

    @property
    def nb_open(self):
        return self.emailsent_set.filter(last_open_date__isnull=False).count()

    @property
    def statistic(self):
        return _(
            'Send = %(send)d at %(date)s - Error = %(error)d - Open = %(open)d => %(ratio).1f %%'
        ) % {
            'send': self.nb_total,
            'date': self.date_end,
            'error': self.nb_errors,
            'open': self.nb_open,
            'ratio': (100.0 * self.nb_open) / self.nb_total
        }

    class Meta(object):
        verbose_name = _('message')
        verbose_name_plural = _('messages')
        ordering = ['-date']
Ejemplo n.º 10
0
class EmailSent(LucteriosModel):
    message = models.ForeignKey(Message,
                                verbose_name=_('message'),
                                null=False,
                                on_delete=models.CASCADE)
    contact = models.ForeignKey('contacts.AbstractContact',
                                verbose_name=_('contact'),
                                null=True,
                                on_delete=models.SET_NULL)
    email = models.CharField(_('email'), max_length=50, blank=False)
    date = models.DateTimeField(verbose_name=_('date'), null=True)
    success = models.BooleanField(verbose_name=_('success'), default=False)
    error = models.TextField(_('error'), default="")
    last_open_date = models.DateTimeField(verbose_name=_('last open date'),
                                          null=True,
                                          default=None)
    nb_open = models.IntegerField(verbose_name=_('number open'),
                                  null=False,
                                  default=0)
    sended_item = LucteriosVirtualField(verbose_name=_('sended item'),
                                        compute_from='get_sended_item')

    @classmethod
    def get_default_fields(cls):
        return [
            'contact', 'sended_item', 'date', 'success', 'error',
            'last_open_date', 'nb_open'
        ]

    def get_send_email_objects(self):
        return [self.item]

    def get_sended_item(self):
        if len(self.email.split(':')) == 3:
            modelname, object_id, _printmodel = self.email.split(':')
            model = apps.get_model(modelname)
            return six.text_type(model.objects.get(id=object_id))
        else:
            return self.email

    def _extract_obj(self):
        if len(self.email.split(':')) == 3:
            modelname, object_id, printmodel = self.email.split(':')
            model = apps.get_model(modelname)
            self.item = model.objects.get(id=object_id)
            if hasattr(self.item, "get_pdfreport"):
                self.print_file = [self.item.get_pdfreport(int(printmodel))]
            else:
                printmodel_obj = PrintModel.objects.get(id=printmodel)
                if hasattr(self.item, "get_document_filename"):
                    pdf_name = "%s.pdf" % self.item.get_document_filename()
                else:
                    pdf_name = "%s.pdf" % remove_accent(printmodel_obj.name)
                gen = ReportingGenerator()
                gen.items = self.get_send_email_objects()
                gen.model_text = printmodel_obj.value
                pdf_file = BytesIO(gen.generate_report(None, False))
                self.print_file = [(pdf_name, pdf_file)]
        else:
            self.print_file = None
            self.item = None

    def get_emails(self):
        if not hasattr(self, 'item'):
            self._extract_obj()
        if self.item is not None:
            cclist = self.item.get_email(False)
            return self.item.get_email(
                True), cclist if len(cclist) > 0 else None
        else:
            return [self.email], None

    def get_attach_files(self):
        if not hasattr(self, 'print_file'):
            self._extract_obj()
        if self.print_file is not None:
            return self.print_file
        else:
            return self.message.attach_files

    def replace_tag(self, text):
        if not hasattr(self, 'item'):
            self._extract_obj()
        contact = None
        doc_reference = ''
        if self.item is not None:
            if hasattr(self.item, 'contact'):
                contact = self.item.contact
            elif isinstance(self.item, AbstractContact):
                contact = self.item
            if hasattr(self.item, 'reference'):
                doc_reference = self.item.reference
            else:
                doc_reference = six.text_type(self.item.id)
        first_doc_name = ''
        if (first_doc_name == '') and (len(self.get_attach_files()) > 0):
            first_doc_name = self.get_attach_files()[0][0]
        if contact is None:
            contact = self.contact
        text = text.replace(
            '#name',
            contact.get_final_child().get_presentation()
            if contact is not None else '???')
        text = text.replace('#doc', first_doc_name)
        text = text.replace('#reference', doc_reference)
        return text

    def send_email(self, http_root_address):
        getLogger('lucterios.mailing').debug(
            'EmailSent.send_email(http_root_address=%s)', http_root_address)
        try:
            body = self.replace_tag(self.message.email_content)
            h2txt = HTML2Text()
            h2txt.ignore_links = False
            body_txt = h2txt.handle(body)
            if http_root_address != '':
                self.message.http_root_address = http_root_address
                img_html = "<img src='%s/lucterios.mailing/emailSentAddForStatistic?emailsent=%d' alt=''/>" % (
                    http_root_address, self.id)
                body = body.replace('</body>', img_html + '</body>')
            email, ccemail = self.get_emails()
            getLogger('lucterios.mailing').debug('send email %s : %s' %
                                                 (self.message.subject, email))
            no_send_list = send_email(split_doubled_email(email),
                                      self.replace_tag(self.message.subject),
                                      body,
                                      files=self.get_attach_files(),
                                      cclist=split_doubled_email(ccemail),
                                      withcopy=self.item is not None,
                                      body_txt=body_txt)
            self.success = True
            if len(no_send_list) > 0:
                email_list = email
                if ccemail is not None:
                    email_list.extend(ccemail)
                for email_item in split_doubled_email(email_list):
                    if email_item not in no_send_list:
                        no_send_list[email_item] = 'OK'
                self.error = six.text_type(no_send_list)
        except Exception as error:
            if getLogger('lucterios.mailing').isEnabledFor(DEBUG):
                getLogger('lucterios.mailing').exception('send_email')
            self.success = False
            self.error = six.text_type(error)
        self.save()

    class Meta(object):
        verbose_name = _('email sent info')
        verbose_name_plural = _('email sent info')
        default_permissions = []
        ordering = ['-last_open_date', 'contact', '-date', 'email']
Ejemplo n.º 11
0
class CustomField(LucteriosModel):
    modelname = models.CharField(_('model'), max_length=100)
    name = models.CharField(_('name'), max_length=200, unique=False)
    kind = models.IntegerField(_('kind'),
                               choices=((0, _('String')), (1, _('Integer')),
                                        (2, _('Real')), (3, _('Boolean')),
                                        (4, _('Select'))))
    args = models.CharField(_('arguments'), max_length=200, default="{}")
    model_title = LucteriosVirtualField(verbose_name=_('model'),
                                        compute_from='get_model_title')
    kind_txt = LucteriosVirtualField(verbose_name=_('kind'),
                                     compute_from='get_kind_txt')

    def __str__(self):
        return self.name

    @classmethod
    def get_show_fields(cls):
        return ['modelname', 'name', 'kind']

    @classmethod
    def get_edit_fields(cls):
        return ['modelname', 'name', 'kind']

    @classmethod
    def get_default_fields(cls):
        return ['name', 'model_title', 'kind_txt']

    def model_associated(self):
        from django.apps import apps
        return apps.get_model(self.modelname)

    def get_fieldname(self):
        return "custom_%d" % self.id

    def get_model_title(self):
        return six.text_type(self.model_associated()._meta.verbose_name)

    def get_kind_txt(self):
        dep_field = self.get_field_by_name('kind')
        args = self.get_args()
        params_txt = ""
        if self.kind == 0:
            if args['multi']:
                params_txt = "(%s)" % _('multi-line')
        elif self.kind == 1:
            params_txt = "[%d;%d]" % (int(args['min']), int(args['max']))
        elif self.kind == 2:
            prec = ".%df" % int(args['prec'])
            floatformat = "[%" + prec + ";%" + prec + "]"
            params_txt = floatformat % (float(args['min']), float(args['max']))
        elif self.kind == 4:
            params_txt = "(%s)" % ",".join(args['list'])
        value = "%s %s" % (get_value_if_choices(self.kind,
                                                dep_field), params_txt)
        return value.strip()

    def get_args(self):
        default_args = {
            'min': 0,
            'max': 0,
            'prec': 0,
            'list': [],
            'multi': False
        }
        try:
            args = eval(self.args)
        except Exception:
            args = {}
        for name, val in default_args.items():
            if name not in args.keys():
                args[name] = val
        args['list'] = list(args['list'])
        return args

    def get_field(self):
        from django.db.models.fields import IntegerField, DecimalField, BooleanField, TextField
        from django.core.validators import MaxValueValidator, MinValueValidator
        args = self.get_args()
        if self.kind == 0:
            dbfield = TextField(self.name)
        if self.kind == 1:
            dbfield = IntegerField(self.name,
                                   validators=[
                                       MinValueValidator(float(args['min'])),
                                       MaxValueValidator(float(args['max']))
                                   ])
        if self.kind == 2:
            dbfield = DecimalField(self.name,
                                   decimal_places=int(args['prec']),
                                   validators=[
                                       MinValueValidator(float(args['min'])),
                                       MaxValueValidator(float(args['max']))
                                   ])
        if self.kind == 3:
            dbfield = BooleanField(self.name)
        if self.kind == 4:
            choices = []
            for item in args['list']:
                choices.append((len(choices), item))
            dbfield = IntegerField(self.name, choices=tuple(choices))
        return dbfield

    @classmethod
    def get_filter(cls, model):
        model_list = []
        for sub_class in model.get_select_contact_type():
            model_list.append(sub_class[0])
        return cls.objects.filter(modelname__in=model_list)

    @classmethod
    def get_fields(cls, model):
        fields = []
        import inspect
        model_list = []
        for sub_class in inspect.getmro(model):
            if hasattr(sub_class, "get_long_name"):
                model_list.append(sub_class.get_long_name())
        for cf_model in cls.objects.filter(modelname__in=model_list):
            fields.append((cf_model.get_fieldname(), cf_model))
        return fields

    @classmethod
    def edit_fields(cls, xfer, init_col):
        col = init_col
        col_offset = 0
        colspan = 1
        row = xfer.get_max_row() + 5
        for cf_name, cf_model in cls.get_fields(xfer.item.__class__):
            comp = cf_model.editor.get_comp(getattr(xfer.item, cf_name))
            comp.set_location(col + col_offset, row, colspan, 1)
            comp.description = cf_model.name
            xfer.add_component(comp)
            col_offset += 1
            if col_offset == 2:
                col_offset = 0
                colspan = 1
                row += 1
            else:
                colspan = 2

    class Meta(object):
        verbose_name = _('custom field')
        verbose_name_plural = _('custom fields')
        default_permissions = []