1
|
|
|
""" |
2
|
|
|
byceps.services.shop.order.dbmodels.order |
3
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4
|
|
|
|
5
|
|
|
:Copyright: 2006-2021 Jochen Kupperschmidt |
6
|
|
|
:License: Revised BSD (see `LICENSE` file for details) |
7
|
|
|
""" |
8
|
|
|
|
9
|
1 |
|
from datetime import datetime |
10
|
1 |
|
from typing import Optional |
11
|
|
|
|
12
|
1 |
|
from sqlalchemy.ext.hybrid import hybrid_property |
13
|
|
|
|
14
|
1 |
|
from .....database import BaseQuery, db, generate_uuid |
15
|
1 |
|
from .....typing import UserID |
16
|
1 |
|
from .....util.instances import ReprBuilder |
17
|
|
|
|
18
|
1 |
|
from ....user.dbmodels.user import User |
19
|
|
|
|
20
|
1 |
|
from ...shop.transfer.models import ShopID |
21
|
|
|
|
22
|
1 |
|
from ..transfer.models import OrderNumber, PaymentMethod, PaymentState |
23
|
|
|
|
24
|
|
|
|
25
|
1 |
|
class OrderQuery(BaseQuery): |
26
|
|
|
|
27
|
1 |
|
def for_shop(self, shop_id: ShopID) -> BaseQuery: |
28
|
1 |
|
return self.filter_by(shop_id=shop_id) |
29
|
|
|
|
30
|
1 |
|
def placed_by(self, user_id: UserID) -> BaseQuery: |
31
|
1 |
|
return self.filter_by(placed_by_id=user_id) |
32
|
|
|
|
33
|
|
|
|
34
|
1 |
|
class Order(db.Model): |
35
|
|
|
"""An order for articles, placed by a user.""" |
36
|
|
|
|
37
|
1 |
|
__tablename__ = 'shop_orders' |
38
|
1 |
|
query_class = OrderQuery |
39
|
|
|
|
40
|
1 |
|
id = db.Column(db.Uuid, default=generate_uuid, primary_key=True) |
41
|
1 |
|
created_at = db.Column(db.DateTime, nullable=False) |
42
|
1 |
|
shop_id = db.Column(db.UnicodeText, db.ForeignKey('shops.id'), index=True, nullable=False) |
43
|
1 |
|
order_number = db.Column(db.UnicodeText, unique=True, nullable=False) |
44
|
1 |
|
placed_by_id = db.Column(db.Uuid, db.ForeignKey('users.id'), index=True, nullable=False) |
45
|
1 |
|
placed_by = db.relationship(User, foreign_keys=[placed_by_id]) |
46
|
1 |
|
first_names = db.Column(db.UnicodeText, nullable=False) |
47
|
1 |
|
last_name = db.Column(db.UnicodeText, nullable=False) |
48
|
1 |
|
country = db.Column(db.UnicodeText, nullable=False) |
49
|
1 |
|
zip_code = db.Column(db.UnicodeText, nullable=False) |
50
|
1 |
|
city = db.Column(db.UnicodeText, nullable=False) |
51
|
1 |
|
street = db.Column(db.UnicodeText, nullable=False) |
52
|
1 |
|
total_amount = db.Column(db.Numeric(7, 2), nullable=False) |
53
|
1 |
|
invoice_created_at = db.Column(db.DateTime, nullable=True) |
54
|
1 |
|
_payment_method = db.Column('payment_method', db.UnicodeText, nullable=True) |
55
|
1 |
|
_payment_state = db.Column('payment_state', db.UnicodeText, index=True, nullable=False) |
56
|
1 |
|
payment_state_updated_at = db.Column(db.DateTime, nullable=True) |
57
|
1 |
|
payment_state_updated_by_id = db.Column(db.Uuid, db.ForeignKey('users.id'), nullable=True) |
58
|
1 |
|
payment_state_updated_by = db.relationship(User, foreign_keys=[payment_state_updated_by_id]) |
59
|
1 |
|
cancelation_reason = db.Column(db.UnicodeText, nullable=True) |
60
|
1 |
|
shipping_required = db.Column(db.Boolean, nullable=False) |
61
|
1 |
|
shipped_at = db.Column(db.DateTime, nullable=True) |
62
|
|
|
|
63
|
1 |
|
def __init__( |
64
|
|
|
self, |
65
|
|
|
shop_id: ShopID, |
66
|
|
|
order_number: OrderNumber, |
67
|
|
|
placed_by_id: UserID, |
68
|
|
|
first_names: str, |
69
|
|
|
last_name: str, |
70
|
|
|
country: str, |
71
|
|
|
zip_code: str, |
72
|
|
|
city: str, |
73
|
|
|
street, |
74
|
|
|
*, |
75
|
|
|
created_at: Optional[datetime] = None, |
76
|
|
|
) -> None: |
77
|
1 |
|
if created_at is None: |
78
|
1 |
|
created_at = datetime.utcnow() |
79
|
1 |
|
self.created_at = created_at |
80
|
1 |
|
self.shop_id = shop_id |
81
|
1 |
|
self.order_number = order_number |
82
|
1 |
|
self.placed_by_id = placed_by_id |
83
|
1 |
|
self.first_names = first_names |
84
|
1 |
|
self.last_name = last_name |
85
|
1 |
|
self.country = country |
86
|
1 |
|
self.zip_code = zip_code |
87
|
1 |
|
self.city = city |
88
|
1 |
|
self.street = street |
89
|
1 |
|
self.payment_state = PaymentState.open |
90
|
|
|
|
91
|
1 |
|
@hybrid_property |
92
|
1 |
|
def payment_method(self) -> Optional[PaymentMethod]: |
93
|
1 |
|
if self._payment_method is None: |
94
|
1 |
|
return None |
95
|
|
|
|
96
|
1 |
|
return PaymentMethod[self._payment_method] |
97
|
|
|
|
98
|
1 |
|
@payment_method.setter |
99
|
1 |
|
def payment_method(self, method: PaymentMethod) -> None: |
100
|
1 |
|
assert method is not None |
101
|
1 |
|
self._payment_method = method.name |
102
|
|
|
|
103
|
1 |
|
@hybrid_property |
104
|
1 |
|
def payment_state(self) -> PaymentState: |
105
|
1 |
|
return PaymentState[self._payment_state] |
106
|
|
|
|
107
|
1 |
|
@payment_state.setter |
108
|
1 |
|
def payment_state(self, state: PaymentState) -> None: |
109
|
1 |
|
assert state is not None |
110
|
1 |
|
self._payment_state = state.name |
111
|
|
|
|
112
|
1 |
|
def __repr__(self) -> str: |
113
|
|
|
item_count = len(self.items) |
114
|
|
|
|
115
|
|
|
return ReprBuilder(self) \ |
116
|
|
|
.add_with_lookup('id') \ |
117
|
|
|
.add('shop', self.shop_id) \ |
118
|
|
|
.add_with_lookup('order_number') \ |
119
|
|
|
.add('placed_by', self.placed_by.screen_name) \ |
120
|
|
|
.add_custom(f'{item_count:d} items') \ |
121
|
|
|
.add_custom(self.payment_state.name) \ |
122
|
|
|
.build() |
123
|
|
|
|