class ProductsCategories(BaseModel): __tablename__ = 'products_categories' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(100)) query: sql.Select
class File(TimedBaseModel): __tablename__ = 'files' id = db.Column(db.Integer, primary_key=True, autoincrement=True) customer_id = db.Column(db.BigInteger, db.ForeignKey('customers.id'), nullable=False) file_key = db.Column(db.String, unique=True, nullable=False) mime_type = db.Column(db.String, nullable=False, default='') query: sql.Select @classmethod async def add(cls, customer_id: customer_id, file_name: str, file_unique_id, mime_type: str = None, file_prefix: str = ''): try: file_extension = mimetypes.guess_extension(mime_type) file_key = f"{file_prefix}{customer_id}/{file_unique_id}{file_extension}" obj = await cls.query.where(cls.file_key == file_key).gino.first() if not obj: s3_client.upload_file(file_name, S3_BUCKET, file_key) obj = cls(customer_id=customer_id, file_key=file_key, mime_type=mime_type) await obj.create() except UniqueViolationError: obj = await cls.query.where(cls.file_key == file_key).gino.first() return obj
class EntityType(BaseModel): __tablename__ = "entities_types" id = db.Column(db.Integer, primary_key=True, autoincrement=True) code = db.Column(db.String(50), unique=True) entity_id = db.Column(db.Integer, db.ForeignKey('entities.id'), nullable=False) name = db.Column(db.String(150), unique=False) @classmethod async def add(cls, code: str, name: str = '', entity_id: int = 0): try: obj = cls(code=code, name=name, entity_id=entity_id) await obj.create() except UniqueViolationError: pass @classmethod async def get(cls, code: str): item = await cls.query.where(cls.code == code.lower()).gino.first() return item @classmethod async def get_all(cls, entity_id: int = 0): if entity_id: items = await cls.query.where(cls.entity_id == entity_id ).gino.all() else: items = await cls.query.where().gino.all() return items
class Entity(BaseModel): __tablename__ = "entities" id = db.Column(db.Integer, primary_key=True, autoincrement=True) code = db.Column(db.String(50), unique=True) name = db.Column(db.String(50), unique=False, default='') query: sql.select @classmethod async def get(cls, code: str): item = await cls.query.where(cls.code == code.lower()).gino.first() return item @classmethod async def add(cls, code: str, name: str = ''): try: obj = cls(code=code, name=name) await obj.create() except UniqueViolationError: pass @classmethod async def get_all(cls): objs = await cls.query.gino.all() return objs
class Status(BaseModel): __tablename__ = 'statuses' id = db.Column(db.Integer, primary_key=True, autoincrement=True) status_name = db.Column(db.String(50), unique=True) comment = db.Column(db.String(255), default='') query: sql.Select
class Payment(TimedBaseModel): __tablename__ = 'payments' id = db.Column(db.Integer, primary_key=True, autoincrement=True) customer_id = db.Column(db.BigInteger, db.ForeignKey('customers.id'), nullable=False) order_id = db.Column(db.Integer, db.ForeignKey('orders.id'), nullable=True) entity_type_id = db.Column(db.Integer, db.ForeignKey('entities_types.id'), nullable=True) payments_sum = db.Column(db.Integer) query: sql.Select
class Promocode(TimedBaseModel): __tablename__ = "promocodes_to_customers" id = db.Column(db.Integer, primary_key=True, autoincrement=True) customer_id = db.Column(db.BigInteger, db.ForeignKey('customers.id'), nullable=False) pormocode_id = db.Column(db.Integer, db.ForeignKey('pormocodes.id'), nullable=False) product_id = db.Column(db.Integer, db.ForeignKey('products.id'), nullable=True) day_expire = db.Column(db.Integer, default=7) start = db.Column(db.Date, default='2020-01-01') finish = db.Column(db.Date, default='2099-12-31') discount_percent = db.Column(db.Integer, nullable=True) discount_amount = db.Column(db.Integer, nullable=True) query: sql.Select @classmethod async def get(cls, code: str): item = await cls.query.where(cls.code == code.upper()).gino.first() return item
class User(db.Model): __tablename__ = 'users' query: sql.Select id = db.Column(db.Integer, Sequence('user_id_seq'), primary_key=True) user_name = db.Column(db.String(50)) user_tg_id = db.Column(db.Integer, unique=True, index=True) date_of_create = db.Column(DateTime, default=datetime.utcnow) def __repr__(self): return f'''
class Weight(db.Model): __tablename__ = 'weight' query: sql.Select id = db.Column(db.Integer, primary_key=True) user_weight = db.Column(db.String(10)) date_of_update = db.Column(DateTime, default=datetime.utcnow) users_id = db.Column(db.Integer, db.ForeignKey('users.user_tg_id')) def __repr__(self): return f'''
class Promocode(BaseModel): __tablename__ = "promocodes" id = db.Column(db.Integer, primary_key=True, autoincrement=True) code = db.Column(db.String(50), unique=True) day_expire = db.Column(db.Integer, default=0) start = db.Column(db.Date, default='2020-01-01') finish = db.Column(db.Date, default='2099-12-31') @classmethod async def get(cls, code: str): item = await cls.query.where(cls.code == code.upper()).gino.first() return item
class Bill(TimedBaseModel): __tablename__ = "bills" id = db.Column(db.Integer, primary_key=True, autoincrement=True) uid = db.Column(db.String(36), unique=True) customer_id = db.Column(db.BigInteger, db.ForeignKey("customers.id")) order_id = db.Column(db.Integer, db.ForeignKey("orders.id")) amount = db.Column(db.Integer) status_id = db.Column(db.Integer, db.ForeignKey("statuses.id")) date_expire = db.Column(db.TIMESTAMP) comment = db.Column(db.String(255), default='') query: sql.Select @classmethod async def add(cls, order: Order, minutes=10, comment=''): try: if order.total >= 1: uid = str(uuid.uuid4()) date_expire = datetime.now() + timedelta(minutes=minutes) if not comment: comment = f"Заказ #{order.id}" obj = Bill(uid=uid, customer_id=order.customer_id, order_id=order.id, amount=order.total, status_id=1, date_expire=date_expire, comment=comment) await obj.create() return obj except UniqueViolationError: pass @classmethod async def get_or_add(cls, order: Order, minutes=10, comment=''): obj = await cls.get(order) if not obj: obj = await cls.add(order=order, minutes=minutes, comment=comment) return obj @classmethod async def get(cls, order: Order): obj = await cls.query.where( and_( cls.order_id == order.id, cls.date_expire < datetime.utcnow() ) ).gino.first() return obj
class Phone(TimedBaseModel): __tablename__ = "phones" id = db.Column(db.Integer, primary_key=True, autoincrement=True) customer_id = db.Column(db.BigInteger, db.ForeignKey('customers.id')) source_number = db.Column(db.String(150)) number = db.Column(db.String(50)) region = db.Column(db.String(100)) operator = db.Column(db.String(50)) old_operator = db.Column(db.String(50)) @classmethod async def add(cls, customer_id: int, source_number: str): import requests from phonenumbers import parse try: phone_obj = parse(number=source_number, region="RU") except NumberParseException.NOT_A_NUMBER: return { 'info': f"Неверный формат номера: <pre>{source_number}</pre>", 'example': ["+74959898533", "74959898533", "84959898533", "4959898533"] } url = "http://num.voxlink.ru/get/" querystring = { "num": f"+{phone_obj.country_code}{phone_obj.national_number}" } payload = "" response = requests.request("GET", url, data=payload, params=querystring) phone_obj = json.loads(response.text) if phone_obj.get('info'): return phone_obj.get('info', '') + " - разрешенный формат: " + ", ".join( phone_obj.get('example', '')) else: obj = cls(customer_id=customer_id, source_number=source_number, number=phone_obj.get('full_num'), region=phone_obj.get('region'), operator=phone_obj.get('operator'), old_operator=phone_obj.get('old_operator')) await obj.create()
class Custumer(TimedBaseModel): __tablename__ = 'customers' id = db.Column(BigInteger, primary_key=True) name = db.Column(String(200)) status_id = db.Column(db.Integer, db.ForeignKey('statuses.id'), nullable=False) referral_id = db.Column(db.BigInteger, default=0) is_admin = db.Column(db.Boolean, default=False) is_manager = db.Column(db.Boolean, default=False) is_supplier = db.Column(db.Boolean, default=False) query: sql.Select
class Order(TimedBaseModel): __tablename__ = 'orders' id = db.Column(db.Integer, primary_key=True, autoincrement=True) customer_id = db.Column(db.BigInteger, db.ForeignKey('customers.id'), nullable=False) status_id = db.Column(db.Integer, db.ForeignKey('statuses.id'), nullable=False) discount_percent = db.Column(db.Integer, default=0) subtotal = db.Column(db.Integer, default=0) customer_discount = db.Column(db.Integer, default=0) promocode_discount = db.Column(db.Integer, default=0) bonuses = db.Column(db.Integer, default=0) noncash = db.Column(db.Integer, default=0) total = db.Column(db.Integer, default=0) comment = db.Column(db.String(255), default='') query: sql.Select async def add_product(self, product: Product, price: int): try: from utils.db_api.models.orders_lines import OrderLine await OrderLine.add(order=self, product=product, price=price, quantity=1) await self.recalculate() return self except UniqueViolationError: pass async def recalculate(self): from utils.db_api.models.orders_lines import OrderLine items = await OrderLine.query.where(OrderLine.order_id == self.id ).gino.all() subtotal = 0 customer_discount = 0 promocode_discount = 0 bonuses = 0 noncash = 0 self_update = {} for item in items: item_update = dict() if item.deleted_at: if not item.customer_discount == 0: item_update.update({'customer_discount': 0}) if not item.promocode_discount == 0: item_update.update({'promocode_discount': 0}) if not item.bonuses == 0: item_update.update({'bonuses': 0}) if not item.noncash == 0: item_update.update({'noncash': 0}) else: subtotal += item.price * item.quantity customer_discount += int(item.price * item.quantity * self.discount_percent / 100) if item.customer_discount != int( item.price * self.discount_percent / 100): item_update.update({ 'customer_discount': int(item.price * item.quantity * self.discount_percent / 100) }) if item_update: await item.update(**item_update).apply() total = subtotal - customer_discount - promocode_discount - bonuses - noncash if self.subtotal != subtotal: self_update.update({'subtotal': subtotal}) if self.customer_discount != customer_discount: self_update.update({'customer_discount': customer_discount}) if self.promocode_discount != promocode_discount: self_update.update({'promocode_discount': promocode_discount}) if self.bonuses != bonuses: self_update.update({'bonuses': bonuses}) if self.noncash != noncash: self_update.update({'noncash': noncash}) if self.total != total: self_update.update({'total': total}) if self_update: await self.update(**self_update).apply() async def get_lines(self, include_deleted=False): from utils.db_api.models.orders_lines import OrderLine if include_deleted: items = await OrderLine.query.where(OrderLine.order_id == self.id ).gino.all() else: items = await OrderLine.query.where( and_(OrderLine.order_id == self.id, OrderLine.deleted_at == None)).gino.all() return items async def set_satus(self, new_status_id: int): if new_status_id == 2: await self.update(status_id=new_status_id).apply() async def get_description(self, need_recalculate: bool = False): if need_recalculate: await self.recalculate() result = f"Заказ №{self.id}\n" result += f"-" * 50 + "\n\n" order_lines = await self.get_lines() for line_number, order_line in enumerate(order_lines, 1): result += f"{line_number}. " + await order_line.get_description( ) + "\n" result += f"-" * 50 + "\n" result += "\n" if self.subtotal: result += f"Сумма товаров: {self.subtotal}{currency_symbol}\n" if self.customer_discount: result += f"Скидка {self.discount_percent}%: {self.customer_discount}{currency_symbol}\n" if self.noncash: result += f"Оплачено: {self.noncash}{currency_symbol}\n" if self.total: result += f"К оплате: {self.total} \n" return result @classmethod async def add(cls, tg_user: types.User): try: obj = Order(customer_id=tg_user.id, status_id=1) await obj.create() return obj except UniqueViolationError: pass @classmethod async def get_or_add(cls, tg_user: types.User): obj = await cls.get(tg_user=tg_user, status_id=1) if not obj: obj = await cls.add(tg_user=tg_user) return obj @classmethod async def get(cls, order_id: int = None, tg_user: types.User = None, status_id: int = 1): if order_id: obj = await cls.query.where(cls.id == order_id).gino.first() else: obj = await cls.query.where( and_(cls.customer_id == tg_user.id, cls.status_id == status_id)).gino.first() return obj
class OrderLine(TimedBaseModel): __tablename__ = 'orders_lines' id = db.Column(db.Integer, primary_key=True, autoincrement=True) order_id = db.Column(db.Integer, db.ForeignKey('orders.id'), nullable=False) product_id = db.Column(db.Integer, db.ForeignKey('products.id'), nullable=False) quantity = db.Column(db.Integer) price = db.Column(db.Integer) customer_discount = db.Column(db.Integer, default=0) promocode_id = db.Column(db.Integer, db.ForeignKey('promocodes.id'), nullable=True) promocode_discount = db.Column(db.Integer, default=0) bonuses = db.Column(db.Integer, default=0) noncash = db.Column(db.Integer, default=0) query: sql.Select @property async def product(self): item = await Product.get(self.product_id) return item async def get_description(self): product = await self.product result = f"" if self.deleted_at is not None: result = f"{emoji_delete} строка удалена\n" result += f"{product.product_name}\n" \ f"<code>{self.quantity} шт. X {self.price}{currency_symbol} " \ f"= {self.price * self.quantity}{currency_symbol}\n</code>" return result @classmethod async def get(cls, order_line_id: int): obj = await cls.query.where( and_( cls.id == order_line_id )).order_by(cls.id).gino.first() return obj @classmethod async def paginator(cls, order: Order, line_number=1): lines = await cls.query.where( and_( cls.order_id == order.id )).order_by(cls.id).gino.all() lines_count = len(lines) if line_number > lines_count: current_line = lines_count elif line_number < 1: current_line = 1 else: current_line = line_number order_line = lines[current_line - 1] result = { 'order_line': order_line, 'page': { 'first': 1, 'previous': 1 if current_line == 1 else current_line - 1, 'current': current_line, 'next': current_line + 1 if current_line < lines_count else lines_count, 'last': lines_count, } } return result async def set_quantity(self, quantity: int = 1): try: data_update = {} if quantity > 0: data_update = {'quantity': quantity, 'deleted_at': None} else: data_update = {'quantity': 0, 'deleted_at': func.now()} if data_update: await self.update(**data_update).apply() except UniqueViolationError: pass @classmethod async def add(cls, order: Order, product: Product, price: int, quantity: int = 1): try: current_lines = await cls.query.where( and_(cls.order_id == order.id, cls.product_id == product.id, cls.deleted_at is None) ).gino.all() # Если нет строк и количество больше 0, тогда добавить строку if quantity > 0 and len(current_lines) == 0: obj = OrderLine(order_id=order.id, product_id=product.id, quantity=quantity, price=price) await obj.create() elif quantity > 0 and len(current_lines) == 1: line = current_lines[0] line_update = {'quantity': quantity, 'price': price} if line_update: await line.update(**line_update).apply() elif quantity == 0 and len(current_lines) == 1: line = current_lines[0] line_update = {'quantity': quantity, 'price': price, 'deleted_at': func.now()} if line_update: await line.update(**line_update).apply() except UniqueViolationError: pass
class Document(TimedBaseModel): __tablename__ = "documents" id = db.Column(db.Integer, primary_key=True, autoincrement=True) customer_id = db.Column(db.BigInteger, db.ForeignKey('customers.id')) fio = db.Column(db.String) birthday = db.Column(db.Date) entity_type_id = db.Column(db.Integer, db.ForeignKey('entities_types.id')) number = db.Column(db.String) issued_code = db.Column(db.String) issued_by = db.Column(db.String) issued_date = db.Column(db.Date) registration_address = db.Column(db.String) foto_main = db.Column(db.String) foto_registration = db.Column(db.String)