Fixes #3916: Erroneous ONIX file.
[wolnelektury.git] / src / isbn / models.py
1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 #
5 from django.db import models
6 from django.db.models import F
7 from jsonfield import JSONField
8
9
10 class ISBNPool(models.Model):
11     PURPOSE_WL = 'WL'
12     PURPOSE_FNP = 'FNP'
13     PURPOSE_CHOICES = (
14         (PURPOSE_WL, 'Wolne Lektury'),
15         (PURPOSE_FNP, 'Fundacja Nowoczesna Polska'),
16     )
17
18     prefix = models.CharField(max_length=10)
19     suffix_from = models.IntegerField()
20     suffix_to = models.IntegerField()
21     ref_from = models.IntegerField()
22     next_suffix = models.IntegerField()
23     purpose = models.CharField(max_length=4, choices=PURPOSE_CHOICES)
24
25     def __str__(self):
26         return self.prefix
27
28     @classmethod
29     def active_pool(cls, purpose):
30         pools = cls.objects.filter(purpose=purpose)
31         pools = pools.exclude(next_suffix__gt=F('suffix_to'))
32         if len(pools) == 1:
33             return pools.get()
34         else:
35             pools.exclude(next_suffix=F('suffix_from'))
36             return pools.get()
37
38     @staticmethod
39     def check_digit(prefix12):
40         digits = [int(d) for d in prefix12]
41         return str((-sum(digits[0::2]) + 7 * sum(digits[1::2])) % 10)
42
43     def isbn(self, suffix, dashes=False):
44         prefix_length = len(self.prefix)
45         suffix_length = 12 - prefix_length
46         suffix_str = ('%%0%dd' % suffix_length) % suffix
47         prefix12 = self.prefix + suffix_str
48         if dashes:
49             prefix12_final = '%s-%s-%s-%s-' % (self.prefix[:3], self.prefix[3:5], self.prefix[5:], suffix_str)
50         else:
51             prefix12_final = prefix12
52         return prefix12_final + self.check_digit(prefix12)
53
54
55 class ONIXRecord(models.Model):
56     isbn_pool = models.ForeignKey(ISBNPool)
57     datestamp = models.DateField(auto_now=True)
58     suffix = models.IntegerField()
59     product_form = models.CharField(max_length=4)
60     product_form_detail = models.CharField(max_length=8, blank=True)
61     title = models.CharField(max_length=256)
62     part_number = models.CharField(max_length=64, blank=True)
63     contributors = JSONField()  # roles, names, optional: ISNI, date of birth/death
64     edition_type = models.CharField(max_length=4)
65     edition_number = models.IntegerField(default=1)
66     language = models.CharField(max_length=4)
67     imprint = models.CharField(max_length=256)
68     publishing_date = models.DateField()
69     dc_slug = models.CharField(max_length=256, default='', db_index=True)
70
71     class Meta:
72         ordering = ['isbn_pool__id', 'suffix']
73         unique_together = ['isbn_pool', 'suffix']
74
75     @classmethod
76     def new_record(cls, purpose, data):
77         pool = ISBNPool.active_pool(purpose)
78         fields = {
79             'isbn_pool': pool,
80             'suffix': pool.next_suffix,
81         }
82         fields_to_copy = [
83             'product_form',
84             'product_form_detail',
85             'title',
86             'part_number',
87             'contributors',  # ???
88             'edition_type',
89             'edition_number',
90             'language',
91             'imprint',
92             'publishing_date',
93             'dc_slug',
94         ]
95         for field in fields_to_copy:
96             if field in data:
97                 fields[field] = data[field]
98         cls.objects.create(**fields)
99         pool.next_suffix += 1
100         pool.save()
101
102     def isbn(self, dashes=False):
103         return self.isbn_pool.isbn(self.suffix, dashes=dashes)
104
105     def reference(self):
106         return 'pl-eisbn-%s' % (self.isbn_pool.ref_from + self.suffix)