Isbns, and minor fixes.
[redakcja.git] / src / isbn / models.py
1 from django.apps import apps
2 from django.db import models
3 from lxml import etree
4 import requests
5 from .product_forms import FORMS
6
7
8 class IsbnPool(models.Model):
9     PURPOSE_GENERAL = 'GENERAL'
10     PURPOSE_WL = 'WL'
11     PURPOSE_CHOICES = (
12         (PURPOSE_WL, 'Wolne Lektury'),
13         (PURPOSE_GENERAL, 'Ogólne'),
14     )
15
16     prefix = models.CharField(max_length=10)
17     suffix_from = models.IntegerField()
18     suffix_to = models.IntegerField()
19     ref_from = models.IntegerField()
20     purpose = models.CharField(max_length=8, choices=PURPOSE_CHOICES)
21
22     def __str__(self):
23         return '-'.join((
24             self.prefix[:3],
25             self.prefix[3:5],
26             self.prefix[5:],
27             'X' * (12 - len(self.prefix)),
28             'X'
29         ))
30
31     @staticmethod
32     def check_digit(prefix12):
33         digits = [int(d) for d in prefix12]
34         return str((-sum(digits[0::2]) + 7 * sum(digits[1::2])) % 10)
35     
36     def get_code(self, suffix, dashes=False):
37         suffix_length = 12 - len(self.prefix)
38         suffix_str = f'{suffix:0{suffix_length}d}'
39         prefix12 = self.prefix + suffix_str
40         check_digit = self.check_digit(prefix12)
41         if dashes:
42             isbn = '-'.join((
43                 self.prefix[:3],
44                 self.prefix[3:5],
45                 self.prefix[5:],
46                 suffix_str,
47                 check_digit
48             ))
49         else:
50             isbn = ''.join((
51                 prefix12, check_digit
52             ))
53         return isbn
54
55     
56     @property
57     def size(self):
58         return self.suffix_to - self.suffix_from + 1
59
60     @property
61     def entries(self):
62         return self.isbn_set.count()
63     
64     @property
65     def fill_percentage(self):
66         return 100 * self.entries / self.size
67
68     def bn_record_id_for(self, suffix):
69         return self.ref_from + suffix
70     
71     def import_all_bn_data(self):
72         for suffix in range(self.suffix_from, self.suffix_to + 1):
73             print(suffix)
74             self.import_bn_data_for(suffix)
75     
76     def import_bn_data_for(self, suffix):
77         record_id = self.bn_record_id_for(suffix)
78         content = requests.get(
79             f'https://e-isbn.pl/IsbnWeb/record/export_onix.xml?record_id={record_id}').content
80         elem = etree.fromstring(content)
81         product = elem.find('{http://ns.editeur.org/onix/3.0/reference}Product')
82         if product is not None:
83             isbn, created = self.isbn_set.get_or_create(
84                 suffix=suffix
85             )
86             isbn.bn_data = etree.tostring(product, pretty_print=True, encoding='unicode')
87             isbn.save(update_fields=['bn_data'])
88
89
90 class Isbn(models.Model):
91     pool = models.ForeignKey(IsbnPool, models.PROTECT)
92     suffix = models.IntegerField()
93     datestamp = models.DateField(blank=True, null=True)
94     book = models.ForeignKey(
95         'catalogue.Book', models.PROTECT, null=True, blank=True
96     )
97     form = models.CharField(
98         max_length=32, choices=[
99             (form, form)
100             for form, config in FORMS
101         ], null=True, blank=True
102     )
103     bn_data = models.TextField(blank=True)
104     wl_data = models.TextField(blank=True)
105     notes = models.TextField(blank=True)
106
107     class Meta:
108         ordering = ['pool', 'suffix']
109         unique_together = ['pool', 'suffix']
110
111     def __str__(self):
112         return self.get_code(True)
113         
114     def get_code(self, dashes=True):
115         return self.pool.get_code(self.suffix, dashes=dashes)
116
117     @classmethod
118     def import_from_documents(cls):
119         Book = apps.get_model('documents', 'Book')
120         for book in Book.objects.all():
121             try:
122                 catalogue_book = book.catalogue_book
123                 if catalogue_book is None:
124                     continue
125             except:
126                 continue
127             try:
128                 meta = book.wldocument(publishable=False, librarian2=True).meta
129             except:
130                 continue
131             for form in ('html', 'txt', 'pdf', 'epub', 'mobi'):
132                 isbn = getattr(meta, f'isbn_{form}')
133                 if isbn is not None:
134                     parts = isbn.split('-')
135                     assert parts[0] == 'ISBN'
136                     suffix = int(parts[-2])
137                     prefix = ''.join(parts[1:-2])
138                     pool = IsbnPool.objects.get(prefix=prefix)
139                     isbn, created = pool.isbn_set.get_or_create(
140                         suffix=suffix,
141                     )
142                     if isbn.book is None:
143                         isbn.book = catalogue_book
144                     else:
145                         assert isbn.book is catalogue_book
146                     if isbn.form is None:
147                         isbn.form = form
148                     else:
149                         assert isbn.form == form
150                     isbn.save(update_fields=['book', 'form'])