# Generated by Django 5.2.14 on 2026-06-16 17:36 import django.core.validators import django.db.models.deletion import django.utils.timezone from django.conf import settings from django.db import migrations from django.db import models class Migration(migrations.Migration): dependencies = [ ("documents", "0027_documentbarcode"), ] operations = [ migrations.CreateModel( name="OcrTemplate", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ("name", models.CharField(max_length=128, verbose_name="name")), ( "owner", models.ForeignKey( blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name="owner", ), ), ( "source_width", models.PositiveIntegerField( help_text="Width of the image the zones were drawn on (px)", validators=[django.core.validators.MinValueValidator(1)], verbose_name="source width", ), ), ( "source_height", models.PositiveIntegerField( help_text="Height of the image the zones were drawn on (px)", validators=[django.core.validators.MinValueValidator(1)], verbose_name="source height", ), ), ("enabled", models.BooleanField(default=True, verbose_name="enabled")), ( "combine_formats", models.JSONField( blank=True, default=dict, help_text="Per-target format strings for combining several zones into one field, keyed by target (custom field id, or 'title'/'asn'/'created'). Tokens like {Zone Name} are replaced with that zone's value.", verbose_name="combine formats", ), ), ( "created", models.DateTimeField( db_index=True, default=django.utils.timezone.now, editable=False, verbose_name="created", ), ), ( "updated", models.DateTimeField(auto_now=True, verbose_name="updated"), ), ( "document_type", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="ocr_templates", to="documents.documenttype", verbose_name="document type", ), ), ( "sample_document", models.ForeignKey( blank=True, help_text="Document used for previewing zones in the editor", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="+", to="documents.document", verbose_name="sample document", ), ), ], options={ "verbose_name": "OCR template", "verbose_name_plural": "OCR templates", "ordering": ("name",), }, ), migrations.CreateModel( name="OcrTemplateZone", fields=[ ( "id", models.AutoField( auto_created=True, primary_key=True, serialize=False, verbose_name="ID", ), ), ( "name", models.CharField( help_text="Descriptive name for this zone (e.g. 'Invoice Number')", max_length=128, verbose_name="zone name", ), ), ( "target", models.CharField( choices=[ ("custom_field", "Custom field"), ("title", "Title"), ("asn", "Archive serial number"), ("created", "Date created"), ], default="custom_field", help_text="Where the extracted value is written: a custom field, or a built-in document field (title, ASN, created date)", max_length=20, verbose_name="target", ), ), ( "page", models.IntegerField( blank=True, help_text="Page (1 = first, -1 = last; blank uses the template default)", null=True, verbose_name="page", ), ), ( "x", models.PositiveIntegerField( help_text="Left edge (px)", verbose_name="x", ), ), ( "y", models.PositiveIntegerField( help_text="Top edge (px)", verbose_name="y", ), ), ( "width", models.PositiveIntegerField( help_text="Zone width (px)", validators=[django.core.validators.MinValueValidator(1)], verbose_name="width", ), ), ( "height", models.PositiveIntegerField( help_text="Zone height (px)", validators=[django.core.validators.MinValueValidator(1)], verbose_name="height", ), ), ( "zone_source_width", models.PositiveIntegerField( blank=True, help_text="Width of the page image this zone was drawn on (px). Falls back to template source_width if unset.", null=True, verbose_name="zone source width", ), ), ( "zone_source_height", models.PositiveIntegerField( blank=True, help_text="Height of the page image this zone was drawn on (px). Falls back to template source_height if unset.", null=True, verbose_name="zone source height", ), ), ( "ocr_language", models.CharField( default="eng", help_text="Tesseract language code(s), e.g. 'deu+eng'", max_length=20, verbose_name="OCR language", ), ), ( "transform", models.CharField( choices=[ ("none", "None"), ("strip", "Strip whitespace"), ("uppercase", "Uppercase"), ("lowercase", "Lowercase"), ("numeric", "Numeric only"), ( "strip_punctuation", "Remove leading/trailing punctuation", ), ("date", "Parse date"), ("qr_code", "Read QR/barcode"), ], default="strip", max_length=20, verbose_name="transform", ), ), ( "date_format", models.CharField( blank=True, default="", help_text="Python strptime format for the 'Parse date' transform (e.g. %d.%m.%Y). Blank = auto-detect.", max_length=64, verbose_name="date format", ), ), ( "validation_regex", models.CharField( blank=True, default="", help_text="Optional regex pattern — extracted text is only accepted if it matches", max_length=256, verbose_name="validation regex", ), ), ("order", models.PositiveIntegerField(default=0, verbose_name="order")), ( "custom_field", models.ForeignKey( blank=True, help_text="Target custom field (only used when target is 'custom_field')", null=True, on_delete=django.db.models.deletion.CASCADE, related_name="ocr_zones", to="documents.customfield", verbose_name="custom field", ), ), ( "template", models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name="zones", to="documents.ocrtemplate", verbose_name="template", ), ), ], options={ "verbose_name": "OCR template zone", "verbose_name_plural": "OCR template zones", "ordering": ("template", "order"), }, ), ]