diff options
Diffstat (limited to 'ishtar_common')
| -rw-r--r-- | ishtar_common/migrations/0210_auto_20210106_1127.py | 30 | ||||
| -rw-r--r-- | ishtar_common/models.py | 95 | 
2 files changed, 123 insertions, 2 deletions
| diff --git a/ishtar_common/migrations/0210_auto_20210106_1127.py b/ishtar_common/migrations/0210_auto_20210106_1127.py new file mode 100644 index 000000000..3dcf7e7ce --- /dev/null +++ b/ishtar_common/migrations/0210_auto_20210106_1127.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.27 on 2021-01-06 11:27 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + +    dependencies = [ +        ('ishtar_common', '0209_auto_20210105_1712'), +    ] + +    operations = [ +        migrations.AddField( +            model_name='documenttemplate', +            name='label_targets', +            field=models.TextField(blank=True, help_text='Each target is separated by a semi-colon. The first target is the name of the object including the data in base template. Following targets will be filled with the content of the first target. For instance: "Cadre1;Cadre2;Cadre3;Cadre4;Cadre5;Cadre6" for a sheet with 6 labels.', null=True, verbose_name='Labels: targets for labels in the LibreOffice file'), +        ), +        migrations.AddField( +            model_name='documenttemplate', +            name='label_template', +            field=models.FileField(blank=True, help_text='La taille maximale supportée pour le fichier est de 100 Mo.', null=True, upload_to='templates/%Y/', verbose_name='Base template for labels'), +        ), +        migrations.AlterField( +            model_name='documenttemplate', +            name='template', +            field=models.FileField(blank=True, help_text='La taille maximale supportée pour le fichier est de 100 Mo.', null=True, upload_to='templates/%Y/', verbose_name='Template'), +        ), +    ] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 23416d406..6ac197af4 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -20,6 +20,7 @@  """  Models description  """ +from bs4 import BeautifulSoup  import copy  import datetime  import inspect @@ -55,6 +56,7 @@ from django.contrib.sites.models import Site  from django.core.cache import cache  from django.core.exceptions import ObjectDoesNotExist, ValidationError, \      MultipleObjectsReturned +from django.core.files.base import ContentFile  from django.core.files.uploadedfile import SimpleUploadedFile  from django.core.urlresolvers import reverse  from django.db.models import Q, Max, Count @@ -1436,7 +1438,21 @@ class DocumentTemplate(models.Model):      slug = models.SlugField(_("Slug"), max_length=100, unique=True)      associated_model = models.ForeignKey(ImporterModel)      template = models.FileField( -        _("Template"), upload_to="templates/%Y/", help_text=max_size_help()) +        _("Template"), upload_to="templates/%Y/", blank=True, null=True, +        help_text=max_size_help()) +    label_template = models.FileField( +        _("Base template for labels"), upload_to="templates/%Y/", +        blank=True, null=True, help_text=max_size_help()) +    label_targets = models.TextField( +        _("Labels: targets for labels in the LibreOffice file"), +        blank=True, null=True, +        help_text=_("Each target is separated by a semi-colon. The first " +                    "target is the name of the object including the data in " +                    "base template. Following targets will be filled with the " +                    "content of the first target. For instance: " +                    "\"Cadre1;Cadre2;Cadre3;Cadre4;Cadre5;Cadre6\" for a " +                    "sheet with 6 labels.") +    )      available = models.BooleanField(_("Available"), default=True)      for_labels = models.BooleanField(_("Used for labels"), default=False)      label_per_page = models.IntegerField( @@ -1462,10 +1478,85 @@ class DocumentTemplate(models.Model):              raise ValidationError(_("For label template, you must provide "                                      "number of label per page.")) +    def generate_label_template(self): +        if not self.label_template.name or not self.label_targets: +            return +        targets = self.label_targets.split(";") +        base_target = targets[0] +        try: +            with zipfile.ZipFile(self.label_template.path) as zip: +                with zip.open('content.xml') as content: +                    soup = BeautifulSoup(content.read(), 'xml') +                    base_content = soup.find( +                        "draw:frame", attrs={"draw:name": base_target}) +                    if not base_content: +                        return +                    base_content = base_content.contents +        except (FileNotFoundError, zipfile.BadZipFile, KeyError): +            base_content = None +        if not base_content: +            return +        for idx, target in enumerate(targets[1:]): +            replace_str = "items." + str(idx + 1) +            new_content = [] +            for content in base_content: +                content = copy.copy(content) +                for text in content.find_all(text=re.compile("items.0")): +                    fixed_text = text.replace("items.0", replace_str) +                    text.replace_with(fixed_text) +                for image in content.find_all( +                        attrs={"draw:name": re.compile("items.0")}): +                    image["draw:name"] = image["draw:name"].replace("items.0", +                                                                    replace_str) +                new_content.append(content) +            next_target = soup.find( +                    "draw:frame", attrs={"draw:name": target}) +            if next_target: +                next_target.contents = new_content + +        with tempfile.TemporaryDirectory() as tmp: +            sp = self.label_template.name.split(os.sep)[-1].split(".") +            if len(sp) == 1:  # no extension? +                sp.append("odt") +            sp[-2] += "-label" +            new_filename = ".".join(sp) +            new_file = os.path.join(tmp, new_filename) +            with zipfile.ZipFile(new_file, 'w') as zip_out: +                with zipfile.ZipFile(self.label_template.path, 'r') as zip_in: +                    zip_out.comment = zip_in.comment +                    for item in zip_in.infolist(): +                        if item.filename != "content.xml": +                            zip_out.writestr(item, +                                             zip_in.read(item.filename)) +            with zipfile.ZipFile(new_file, mode='a', +                                 compression=zipfile.ZIP_DEFLATED) as zf: +                zf.writestr("content.xml", str(soup)) + +            media_dir = "templates/{}/".format(datetime.date.today().year) +            full_media_dir = os.path.join(settings.MEDIA_ROOT, media_dir) +            if not os.path.exists(full_media_dir): +                os.mkdir(full_media_dir) +            media_file = new_filename +            idx = 0 +            while os.path.exists(os.path.join(settings.MEDIA_ROOT, media_file)): +                idx += 1 +                sp = media_file.split(".") +                sub_sp = sp[-2].split("-label") +                sub_sp[-1] += str(idx) +                sp[-2] = "-label".join(sub_sp) +                media_file = ".".join(sp) +            with open(new_file, "rb") as file: +                with ContentFile(file.read()) as file_content: +                    self.template.save(media_file, file_content) +                    self.save() +      def save(self, *args, **kwargs):          if not self.slug:              self.slug = create_slug(DocumentTemplate, self.name) -        return super(DocumentTemplate, self).save(*args, **kwargs) +        super(DocumentTemplate, self).save(*args, **kwargs) +        if self.label_template.name and self.label_targets and not \ +                self.template: +            self.generate_label_template()      @classmethod      def get_tuples(cls, dct=None, empty_first=True): | 
