class Project(Model, AuditableRepository, Service): name = Property(str, required=True, validators=[NotEmpty()]) tasks = Property(list, sub_type=Task) created = Property(datetime, required=True, generator=date_now_generator) def __init__(self, **kwargs): Model.init_model(self, **kwargs)
class Group(Model, MongoRepository): id = Property(str, required=True, generator=create_uuid_generator('U')) name = Property(str, required=True, validators=[NotEmpty, Regexp('[A-Za-z0-9-_]')], index=UniqueIndex) users = Property(list, sub_type=User)
class Order(Model, MongoRepository): id = Property(str, generator=create_uuid_generator('O')) payment_method = Property(Payment, required=True) products = Property(list, sub_type=Product, required=True) order_date = Property(datetime, required=True, generator=date_now_generator) delivery_address = Property(Address, required=True) inventory_client = get_client_proxy('inventory') payment_client = get_client_proxy('payments') shipping_client = get_client_proxy('shipping') @classmethod def before_post(cls, *args, **kwargs): order: Order = kwargs.get('model') order.finalise_and_validate() status_code, rsp_dict = Order.inventory_client.reservations.post(Reservation(order_id=order.id, products=order.products)) order.update(reservation_id=rsp_dict.get('result')) @classmethod def after_post(cls, *args, **kwargs): order: Order = kwargs.get('model') amount = sum([p.price.amount for p in order.products]) auth_req = AuthorisationRequest(payment_method=order.payment_method, amount=amount) auth_req.external_reference = order.id status_code, rsp_dict = Order.payment_client.wrap('/payments/authorize').post(auth_req) print(f'<authorisation response> {rsp_dict}') if status_code not in [200, 201]: code, canceled_reservation = Order.inventory_client.wrap(f'/reservations/{order.reservation_id}/cancel').patch() if code not in [200, 201]: config.app_engine.logger.warn('reservation was not successful.') raise Exception('It is not aurhorised') else: code, result = Order.shipping_client.shippings.post( Shipping(reservation_id=order.reservation_id, delivery_address=order.delivery_address)) print(f':: {result.tracking_id}')
class ExampleClass(Model): just_numbers = Property(str, required=True, validators=[Regexp('^[0-9]+$')]) future_field = Property(datetime, validators=[Future]) email = Property(str, validators=Email) distance = Property(int, validators=[Min(10), Max(15)]) numbers = Property(list, validators=Unique)
class Portfolio(Model, MongoRepository): id = Property(str, required=True, generator=create_uuid_generator('P')) name = Property(str, required=True, validators=[NotEmpty, Regexp('[A-Za-z0-9-_]')], index=UniqueIndex) stocks = Property(list, sub_type=Stock, validators=NotEmpty) owner = Property(User, required=False)
class Order(Model): id = Property(str, generator=create_uuid_generator('O')) payment_method = Property(Payment, required=True) products = Property(list, sub_type=Product, required=True) order_date = Property(datetime, required=True, generator=date_now_generator) delivery_address = Property(Address, required=True)
class User(Model, AuditableRepository, Service): id = Property(str, required=True, generator=uuid_generator('U')) name = Property(str, required=True, validators=[NotEmpty]) email = Property(str, required=True, validators=[Email, NotEmpty]) password = Property(str, required=True, validators=[NotEmpty], converter=content_hasher(rounds=10), omit=True) roles = Property(list, sub_type=str, default_value=['Login'])
class Reservation(Model, MongoRepository): id = Property(str, generator=create_uuid_generator('R')) order_id = Property(str, required=True) order_date = Property(datetime, required=True, generator=date_now_generator) products = Property(list, sub_type=Product, required=True, validators=NotEmpty()) state = Property(ReservationState, required=True, default_value=ReservationState.RESERVED)
class User(Model, MongoRepository, Service, IdentityMixin): id = Property(str, required=True, generator=create_uuid_generator('U')) name = Property(str, required=True, validators=[NotEmpty, Regexp('[A-Za-z0-9-_]')], index=UniqueIndex) password = Property(str, required=True, validators=[NotEmpty], converter=content_hasher(rounds=10), omit=True) description = Property(str, index=TextIndex) roles = Property(list, sub_type=str) created = Property(datetime, required=True, validators=[Past], generator=date_now_generator) last_login = Property(datetime, marshaller=TimestampMarshaller) sequence = Property(int, index=Index) @link(rel='change_password', http_method='POST', require=[CurrentSubject(), Role('admin')]) def change_p(self, current_password, new_password): if not pbkdf2_sha256.verify(current_password, self.password): raise ServiceException(403, _('Current password is not correct')) else: self.password = new_password self.save() return _('Password changed') @link(require=Anonymous()) def get_description(self): return self.description
class Stock(Model): code = Property(str, required=True, validators=[NotEmpty, Regexp('[A-Za-z0-9-_]'), Max(4)], index=UniqueIndex) open = Property(float, required=True, validators=[Min(0)]) updated = Property(datetime, required=True, validators=[Past], generator=date_now_generator) history = Property(list, sub_type=int) sequence = Property(int, validators=[Min(1), Max(100)])
class Reservation(Model, MongoRepository, Service): id = Property(str, generator=create_uuid_generator('R')) order_id = Property(str, required=True) order_date = Property(datetime, required=True, generator=date_now_generator) products = Property(list, sub_type=Product, required=True) state = Property(ReservationState, required=True, default_value=ReservationState.RESERVED) @classmethod def before_post(self, *args, **kwargs): print('aaaa')
class Payment(Model): method = Property(PaymentMethod, required=True) customer_id = Property(str, required=True, validators=[NotEmpty]) customer_secret = Property(str, required=True, validators=[NotEmpty]) def validate(self): if self.method in (PaymentMethod.MASTER, PaymentMethod.VISA): if len(self.customer_id) < 16 or len(self.customer_secret) < 3: raise ValidationException( 'The card number must be 16 character long and the CVC 3.', self, 'payment_method') elif self.method in (PaymentMethod.PAYPAL, PaymentMethod.DIRECT_DEBIT): if len(self.customer_id) < 22: raise ValidationException( 'The IBAN must be at least 22 character long.', self, 'payment_method')
class Order(Model, MongoRepository, Service): id = Property(str, generator=create_uuid_generator('O')) products = Property(list, sub_type=Product, required=True) order_date = Property(datetime, required=True, generator=date_now_generator) @classmethod def before_post(cls, *args, **kwargs): print(request.args) print(request.headers) client = HttpClientServiceProxy('http://127.0.0.1:5000/') order = kwargs['document'] status, rsp_dict = client.reservation.post( Reservation(order_id=order.get('_id'), products=order.get('products'))) print(f'status: {status} -> {rsp_dict}')
class Address(Model): first_name = Property(str, required=True, validators=[NotEmpty]) last_name = Property(str, required=True, validators=[NotEmpty]) city = Property(str, required=True, validators=[NotEmpty]) street = Property(str, required=True, validators=[NotEmpty]) country = Property(str, required=True, validators=[NotEmpty]) postal_code = Property(str, required=True, validators=[NotEmpty])
class User(Model, MongoRepository, Service): id = Property(str) name = Property(str, required=True, index=UniqueIndex) email = Property(str, validators=[Email], index=UniqueIndex) password = Property(str, validators=[Regexp('(?=.{8,})')], converter=content_hasher(), omit=True) roles = Property(list, sub_type=str, default_value=['Login']) @link(http_method='POST', require=[CurrentSubject(), Role('admin')]) def change_password(self, current_password, new_password): if not pbkdf2_sha256.verify(current_password, self.password): raise ServiceException(403, _('Current password is not correct')) else: self.password = new_password self.save() return _('Password changed') @link(require=Anonymous()) def get_description(self): return self.description
class Task(Model, AuditableRepository): id = Property(str, required=True, generator=create_uuid_generator('U')) name = Property(str, required=True, validators=[NotEmpty]) description = Property(str, required=True, validators=[NotEmpty]) completed = Property(bool, required=True, default_value=False) created = Property(datetime, required=True, generator=date_now_generator) closed_date = Property(datetime, validators=[Past]) priority = Property(Priority, required=True, default_value=Priority.MEDIUM) def __init__(self, **kwargs): Model.init_model(self, **kwargs) def complete(self): self.completed = True self.closed_date = datetime.now()
class User(Model, MongoRepository, Service): id = Property(str, required=True, generator=uuid_generator('U')) name = Property(str, required=True, validators=[NotEmpty, Regexp('[A-Za-z0-9-_]')]) password = Property(str, required=True, validators=[NotEmpty]) description = Property(str) roles = Property(list, sub_type=str) created = Property(datetime, required=True, validators=[Past], generator=date_now_generator)
class Task(Model, AuditableRepository, Service): id = Property(str, required=True, generator=uuid_generator('T')) name = Property(str, required=True, validators=[NotEmpty]) description = Property(str) tags = Property(list, sub_type=str) completed = Property(bool, required=True, default_value=False) closed_date = Property(datetime, validators=[Past]) def __init__(self, **kwargs): Model.init_model(self, **kwargs) def complete(self): """ Mark the task complete and set the completion date to now; """ self.completed = True self.closed_date = datetime.now()
class Shipping(Model): reservation_id = Property(str, required=True, validators=NotEmpty) order_date = Property(datetime, required=True, generator=date_now_generator) delivery_address = Property(Address, required=True)
class Stock(Model, MongoRepository): id = Property(str, generator=create_uuid_generator('S')) product = Property(Product, required=True) stock = Property(int, required=True, default_value=0)
class Product(Model, MongoRepository): id = Property(str, generator=create_uuid_generator('P')) name = Property(str, required=True) description = Property(str) size = Property(ProductSize, required=True) price = Property(Money, required=True)
class Reservation(Model, MongoRepository): id = Property(str, generator=create_uuid_generator('R')) order_id = Property(str, required=True) order_date = Property(datetime, required=True, generator=date_now_generator) products = Property(list, sub_type=Product, required=True, validators=NotEmpty()) state = Property(ReservationState, required=True, default_value=ReservationState.RESERVED) stocks = Property(dict, sub_type=dict) tracking_id = Property(str) def group_products_by_code(self): products_by_code = dict() for product in self.products: size_and_quantity = products_by_code.get(product.code, {product.size.name: 0}) size_and_quantity[product.size.name] = size_and_quantity.get(product.size.name, 0) + 1 products_by_code[product.code] = size_and_quantity return products_by_code @classmethod def before_post(cls, *args, **kwargs): # method called before the reservation id is sent for pcode, size_and_quantity in kwargs['model'].group_products_by_code().items(): for psize, quantity in size_and_quantity.items(): # todo: what if there are multiple stock items with the same product code query = Stock.where( (Stock.product.code == pcode) & (Stock.product.size == psize) & (Stock.available >= quantity)) reserved_stock = query.find_one_and_update(available=Stock.available - quantity, reserved=Stock.reserved + quantity) if not reserved_stock: raise ReservationException(f"There's no stock available for code: {pcode} and size: {psize}.") if hasattr(kwargs['model'], 'stocks') and kwargs['model'].stocks is not None: size_and_qty = kwargs['model'].stocks.get(pcode, {psize: {'qty': quantity}}) if psize not in size_and_qty: size_and_qty[psize] = {'qty': quantity} else: size_and_qty = {psize: {'qty': quantity}} kwargs['model'].stocks = {} size_and_qty[psize]['stock'] = reserved_stock.id kwargs['model'].stocks[pcode] = size_and_qty @classmethod def after_post(cls, *args, **kwargs): reservation: Reservation = kwargs.get('model') print(f'reservation id: {reservation.id}') @action(method='PATCH', require=[Role('user')]) def commit(self): self.state = ReservationState.COMMITTED self.save() return self @action(method='PATCH', require=[Role('user')]) def execute(self, tracking_id): self.state = ReservationState.EXECUTED self.tracking_id = tracking_id self.save() for pcode, sizes in self.stocks.items(): for size, quantity_and_stock in sizes.items(): stock_id = quantity_and_stock.get('stock') query = Stock.where(Stock.id == stock_id) modified_count = query.update_one(reserved=Stock.reserved - quantity_and_stock.get('qty')) if modified_count != 1: config.app_engine.logger.warn(f'quantities were not reduced for stock: {stock_id}') return self @action(method='PATCH', require=[Role('user')]) def cancel(self): error = False for pcode, sizes in self.stocks.items(): for size, quantity_and_stock in sizes.items(): stock_id = quantity_and_stock.get('stock') query = Stock.where(Stock.id == stock_id) qty = quantity_and_stock.get('qty') modified_count = query.update_one(reserved=Stock.reserved - qty, available=Stock.available + qty) if modified_count != 1: error = True config.app_engine.logger.warn(f'quantities were not reduced for stock: {stock_id}') if not error: self.state = ReservationState.CANCELLED self.save() return self
class ExampleClass(Model): just_numbers = Property(str, required=True, validators=[Regexp('^[0-9]+$')]) future_field = Property(datetime, validators=[Future])
class Application(Model, MongoRepository): id = Property(str, required=True, generator=create_uuid_generator()) application_date = Property(date, required=True, marshaller=MongoDateTimeMarshaller)
class AuthorisationRequest(Model): payment_method = Property(PaymentMethod, required=True) amount = Property(Money, required=True) external_reference = Property(str, required=True, validators=NotEmpty)
class StockInventory(Model, MongoRepository): id = Property(str, generator=create_uuid_generator('S')) product = Property(Product, required=True) available = Property(int, required=True, default_value=0) reserved = Property(int, required=True, default_value=0)
class Product(Model): code = Property(str, required=True, validators=[NotEmpty]) name = Property(str, required=True) description = Property(str) size = Property(ProductSize, required=True) price = Property(Money, required=True)