Completed
Push — main ( b7acb4...84e7fd )
by Jochen
03:57
created

byceps.services.shop.article.sequence_service   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Test Coverage

Coverage 73.52%

Importance

Changes 0
Metric Value
eloc 63
dl 0
loc 117
ccs 25
cts 34
cp 0.7352
rs 10
c 0
b 0
f 0
wmc 9

6 Functions

Rating   Name   Duplication   Size   Complexity  
A generate_article_number() 0 19 2
A find_article_number_sequence() 0 15 2
A find_article_number_sequences_for_shop() 0 12 1
A create_article_number_sequence() 0 10 1
A delete_article_number_sequence() 0 9 1
A _db_entity_to_article_number_sequence() 0 8 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A ArticleNumberGenerationFailed.__init__() 0 2 1
1
"""
2
byceps.services.shop.article.sequence_service
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2020 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9 1
from typing import List, Optional
10
11 1
from ....database import db
12
13 1
from ..sequence.models import NumberSequence as DbNumberSequence
14 1
from ..sequence.transfer.models import Purpose
15 1
from ..shop.transfer.models import ShopID
16
17 1
from .transfer.models import (
18
    ArticleNumber,
19
    ArticleNumberSequence,
20
    ArticleNumberSequenceID,
21
)
22
23
24 1
def create_article_number_sequence(
25
    shop_id: ShopID, prefix: str, *, value: Optional[int] = None
26
) -> ArticleNumberSequenceID:
27
    """Create an article number sequence."""
28 1
    sequence = DbNumberSequence(shop_id, Purpose.article, prefix, value=value)
29
30 1
    db.session.add(sequence)
31 1
    db.session.commit()
32
33 1
    return sequence.id
34
35
36 1
def delete_article_number_sequence(
37
    sequence_id: ArticleNumberSequenceID,
38
) -> None:
39
    """Delete the article number sequence."""
40 1
    db.session.query(DbNumberSequence) \
41
        .filter_by(id=sequence_id) \
42
        .delete()
43
44 1
    db.session.commit()
45
46
47 1
def find_article_number_sequence(
48
    sequence_id: ArticleNumberSequenceID,
49
) -> Optional[ArticleNumberSequence]:
50
    """Return the article number sequence, or `None` if the sequence ID
51
    is unknown or if the sequence's purpose is not article numbers.
52
    """
53
    sequence = DbNumberSequence.query \
54
        .filter_by(id=sequence_id) \
55
        .filter_by(_purpose=Purpose.article.name) \
56
        .one_or_none()
57
58
    if sequence is None:
59
        return None
60
61
    return _db_entity_to_article_number_sequence(sequence)
62
63
64 1
def find_article_number_sequences_for_shop(
65
    shop_id: ShopID,
66
) -> List[ArticleNumberSequence]:
67
    """Return the article number sequences defined for that shop."""
68
    sequences = DbNumberSequence.query \
69
        .filter_by(shop_id=shop_id) \
70
        .filter_by(_purpose=Purpose.article.name) \
71
        .all()
72
73
    return [
74
        _db_entity_to_article_number_sequence(sequence)
75
        for sequence in sequences
76
    ]
77
78
79 1
class ArticleNumberGenerationFailed(Exception):
80
    """Indicate that generating a prefixed, sequential article number
81
    has failed.
82
    """
83
84 1
    def __init__(self, message: str) -> None:
85
        self.message = message
86
87
88 1
def generate_article_number(
89
    sequence_id: ArticleNumberSequenceID,
90
) -> ArticleNumber:
91
    """Generate and reserve the next article number from this sequence."""
92 1
    sequence = DbNumberSequence.query \
93
        .filter_by(id=sequence_id) \
94
        .filter_by(_purpose=Purpose.article.name) \
95
        .with_for_update() \
96
        .one_or_none()
97
98 1
    if sequence is None:
99
        raise ArticleNumberGenerationFailed(
100
            f'No article number sequence found for ID "{sequence_id}".'
101
        )
102
103 1
    sequence.value = DbNumberSequence.value + 1
104 1
    db.session.commit()
105
106 1
    return ArticleNumber(f'{sequence.prefix}{sequence.value:05d}')
107
108
109 1
def _db_entity_to_article_number_sequence(
110
    sequence: DbNumberSequence,
111
) -> ArticleNumberSequence:
112
    return ArticleNumberSequence(
113
        sequence.id,
114
        sequence.shop_id,
115
        sequence.prefix,
116
        sequence.value,
117
    )
118