Restructure project #3
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
result
|
||||
result-*
|
||||
|
||||
dist
|
||||
dist
|
||||
|
||||
test.db
|
@ -1,24 +0,0 @@
|
||||
import argparse
|
||||
|
||||
from dibbler.conf import config
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--config",
|
||||
help="Path to the config file",
|
||||
type=str,
|
||||
required=False,
|
||||
)
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
config.read(args.config)
|
||||
|
||||
import dibbler.text_based as text_based
|
||||
|
||||
text_based.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
7
dibbler/db.py
Normal file
7
dibbler/db.py
Normal file
@ -0,0 +1,7 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
from dibbler.conf import config
|
||||
|
||||
engine = create_engine(config.get('database', 'url'))
|
||||
Session = sessionmaker(bind=engine)
|
@ -5,7 +5,7 @@ import signal
|
||||
|
||||
from sqlalchemy import or_, and_
|
||||
|
||||
from .models.db import *
|
||||
from .models import User, Product
|
||||
|
||||
def search_user(string, session, ignorethisflag=None):
|
||||
string = string.lower()
|
||||
|
51
dibbler/main.py
Normal file
51
dibbler/main.py
Normal file
@ -0,0 +1,51 @@
|
||||
import argparse
|
||||
|
||||
from dibbler.conf import config
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--config",
|
||||
help="Path to the config file",
|
||||
type=str,
|
||||
required=False,
|
||||
)
|
||||
|
||||
subparsers = parser.add_subparsers(
|
||||
title='subcommands',
|
||||
dest='subcommand',
|
||||
required=True,
|
||||
)
|
||||
subparsers.add_parser(
|
||||
'loop',
|
||||
help='Run the dibbler loop'
|
||||
)
|
||||
subparsers.add_parser(
|
||||
'create-db',
|
||||
help='Create the database'
|
||||
)
|
||||
subparsers.add_parser(
|
||||
'slabbedasker',
|
||||
help='Find out who is slabbedasker'
|
||||
)
|
||||
|
||||
def main():
|
||||
args = parser.parse_args()
|
||||
config.read(args.config)
|
||||
|
||||
if args.subcommand == 'loop':
|
||||
import dibbler.text_based as text_based
|
||||
text_based.main()
|
||||
|
||||
elif args.subcommand == 'create-db':
|
||||
import dibbler.scripts.makedb as makedb
|
||||
makedb.main()
|
||||
|
||||
elif args.subcommand == 'slabbedasker':
|
||||
import dibbler.scripts.slabbedasker as slabbedasker
|
||||
slabbedasker.main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,4 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
from .models.db import db
|
||||
|
||||
db.Base.metadata.create_all(db.engine)
|
@ -2,7 +2,7 @@ from math import ceil
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
from dibbler.models.db import (
|
||||
from dibbler.models import (
|
||||
Product,
|
||||
Purchase,
|
||||
PurchaseEntry,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import sqlalchemy
|
||||
|
||||
from dibbler.conf import config
|
||||
from dibbler.models.db import (
|
||||
from dibbler.models import (
|
||||
Product,
|
||||
Purchase,
|
||||
PurchaseEntry,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import sqlalchemy
|
||||
|
||||
from dibbler.models.db import User, Product
|
||||
from dibbler.models import User, Product
|
||||
from .helpermenus import Menu, Selector
|
||||
|
||||
__all__ = ["AddUserMenu", "AddProductMenu", "EditProductMenu", "AdjustStockMenu", "CleanupStockMenu", "EditUserMenu"]
|
||||
|
@ -5,7 +5,8 @@ import re
|
||||
import sys
|
||||
from select import select
|
||||
|
||||
from dibbler.models.db import User, Session
|
||||
from dibbler.db import Session
|
||||
from dibbler.models import User
|
||||
from dibbler.helpers import (
|
||||
search_user,
|
||||
search_product,
|
||||
|
@ -4,7 +4,7 @@ import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
from dibbler.models.db import Session
|
||||
from dibbler.db import Session
|
||||
|
||||
from . import faq_commands, restart_commands
|
||||
from .buymenu import BuyMenu
|
||||
|
@ -1,7 +1,7 @@
|
||||
import sqlalchemy
|
||||
|
||||
from dibbler.conf import config
|
||||
from dibbler.models.db import Transaction, Product, User
|
||||
from dibbler.models import Transaction, Product, User
|
||||
from dibbler.helpers import less
|
||||
|
||||
from .helpermenus import Menu, Selector
|
||||
|
@ -1,7 +1,7 @@
|
||||
import re
|
||||
|
||||
from dibbler.conf import config
|
||||
from dibbler.models.db import Product, User
|
||||
from dibbler.models import Product, User
|
||||
from dibbler.printer_helpers import print_bar_code, print_name_label
|
||||
|
||||
from .helpermenus import Menu
|
||||
|
@ -1,7 +1,7 @@
|
||||
from sqlalchemy import desc, func
|
||||
|
||||
from dibbler.helpers import less
|
||||
from dibbler.models.db import PurchaseEntry, Product, User
|
||||
from dibbler.models import PurchaseEntry, Product, User
|
||||
from dibbler.statistikkHelpers import statisticsTextOnly
|
||||
|
||||
from .helpermenus import Menu
|
||||
|
40
dibbler/models/Base.py
Normal file
40
dibbler/models/Base.py
Normal file
@ -0,0 +1,40 @@
|
||||
from sqlalchemy import MetaData
|
||||
from sqlalchemy.orm import (
|
||||
DeclarativeBase,
|
||||
declared_attr,
|
||||
)
|
||||
from sqlalchemy.orm.collections import (
|
||||
InstrumentedDict,
|
||||
InstrumentedList,
|
||||
InstrumentedSet,
|
||||
)
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
metadata = MetaData(
|
||||
naming_convention={
|
||||
"ix": "ix_%(column_0_label)s",
|
||||
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
||||
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
|
||||
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
||||
"pk": "pk_%(table_name)s"
|
||||
}
|
||||
)
|
||||
|
||||
@declared_attr.directive
|
||||
def __tablename__(cls) -> str:
|
||||
return cls.__name__
|
||||
|
||||
def __repr__(self) -> str:
|
||||
columns = ", ".join(
|
||||
f"{k}={repr(v)}" for k, v in self.__dict__.items() if not any([
|
||||
k.startswith("_"),
|
||||
|
||||
# Ensure that we don't try to print out the entire list of
|
||||
# relationships, which could create an infinite loop
|
||||
isinstance(v, Base),
|
||||
isinstance(v, InstrumentedList),
|
||||
isinstance(v, InstrumentedSet),
|
||||
isinstance(v, InstrumentedDict),
|
||||
])
|
||||
)
|
||||
return f"<{self.__class__.__name__}({columns})>"
|
45
dibbler/models/Product.py
Normal file
45
dibbler/models/Product.py
Normal file
@ -0,0 +1,45 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
Integer,
|
||||
String,
|
||||
)
|
||||
from sqlalchemy.orm import (
|
||||
Mapped,
|
||||
mapped_column,
|
||||
relationship,
|
||||
)
|
||||
|
||||
from .Base import Base
|
||||
if TYPE_CHECKING:
|
||||
from .PurchaseEntry import PurchaseEntry
|
||||
from .UserProducts import UserProducts
|
||||
|
||||
class Product(Base):
|
||||
__tablename__ = 'products'
|
||||
|
||||
product_id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
bar_code: Mapped[str] = mapped_column(String(13))
|
||||
name: Mapped[str] = mapped_column(String(45))
|
||||
price: Mapped[int] = mapped_column(Integer)
|
||||
stock: Mapped[int] = mapped_column(Integer)
|
||||
hidden: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||||
|
||||
purchases: Mapped[set[PurchaseEntry]] = relationship(back_populates="product")
|
||||
users: Mapped[set[UserProducts]] = relationship(back_populates="product")
|
||||
|
||||
bar_code_re = r"[0-9]+"
|
||||
name_re = r".+"
|
||||
name_length = 45
|
||||
|
||||
def __init__(self, bar_code, name, price, stock=0, hidden = False):
|
||||
self.name = name
|
||||
self.bar_code = bar_code
|
||||
self.price = price
|
||||
self.stock = stock
|
||||
self.hidden = hidden
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
69
dibbler/models/Purchase.py
Normal file
69
dibbler/models/Purchase.py
Normal file
@ -0,0 +1,69 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from datetime import datetime
|
||||
import math
|
||||
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
DateTime,
|
||||
Integer,
|
||||
String,
|
||||
)
|
||||
from sqlalchemy.orm import (
|
||||
Mapped,
|
||||
mapped_column,
|
||||
relationship,
|
||||
)
|
||||
|
||||
from .Base import Base
|
||||
from .Transaction import Transaction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .PurchaseEntry import PurchaseEntry
|
||||
|
||||
class Purchase(Base):
|
||||
__tablename__ = 'purchases'
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
time: Mapped[datetime] = mapped_column(DateTime)
|
||||
price: Mapped[int] = mapped_column(Integer)
|
||||
|
||||
transactions: Mapped[set[Transaction]] = relationship(back_populates="purchase", order_by='Transaction.user_name')
|
||||
entries: Mapped[set[PurchaseEntry]] = relationship(back_populates="purchase")
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def is_complete(self):
|
||||
return len(self.transactions) > 0 and len(self.entries) > 0
|
||||
|
||||
def price_per_transaction(self, round_up=True):
|
||||
if round_up:
|
||||
return int(math.ceil(float(self.price)/len(self.transactions)))
|
||||
else:
|
||||
return int(math.floor(float(self.price)/len(self.transactions)))
|
||||
|
||||
def set_price(self, round_up=True):
|
||||
self.price = 0
|
||||
for entry in self.entries:
|
||||
self.price += entry.amount*entry.product.price
|
||||
if len(self.transactions) > 0:
|
||||
for t in self.transactions:
|
||||
t.amount = self.price_per_transaction(round_up=round_up)
|
||||
|
||||
def perform_purchase(self, ignore_penalty=False, round_up=True):
|
||||
self.time = datetime.datetime.now()
|
||||
self.set_price(round_up=round_up)
|
||||
for t in self.transactions:
|
||||
t.perform_transaction(ignore_penalty=ignore_penalty)
|
||||
for entry in self.entries:
|
||||
entry.product.stock -= entry.amount
|
||||
|
||||
def perform_soft_purchase(self, price, round_up=True):
|
||||
self.time = datetime.datetime.now()
|
||||
self.price = price
|
||||
for t in self.transactions:
|
||||
t.amount = self.price_per_transaction(round_up=round_up)
|
||||
for t in self.transactions:
|
||||
t.perform_transaction()
|
36
dibbler/models/PurchaseEntry.py
Normal file
36
dibbler/models/PurchaseEntry.py
Normal file
@ -0,0 +1,36 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import (
|
||||
Integer,
|
||||
ForeignKey,
|
||||
)
|
||||
from sqlalchemy.orm import (
|
||||
Mapped,
|
||||
mapped_column,
|
||||
relationship,
|
||||
)
|
||||
|
||||
from .Base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .Product import Product
|
||||
from .Purchase import Purchase
|
||||
|
||||
class PurchaseEntry(Base):
|
||||
__tablename__ = 'purchase_entries'
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
amount: Mapped[int] = mapped_column(Integer)
|
||||
|
||||
product_id: Mapped[int] = mapped_column(ForeignKey("products.product_id"))
|
||||
purchase_id: Mapped[int] = mapped_column(ForeignKey("purchases.id"))
|
||||
|
||||
product: Mapped[Product] = relationship(lazy='joined')
|
||||
purchase: Mapped[Purchase] = relationship(lazy='joined')
|
||||
|
||||
def __init__(self, purchase, product, amount):
|
||||
self.product = product
|
||||
self.product_bar_code = product.bar_code
|
||||
self.purchase = purchase
|
||||
self.amount = amount
|
51
dibbler/models/Transaction.py
Normal file
51
dibbler/models/Transaction.py
Normal file
@ -0,0 +1,51 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import (
|
||||
DateTime,
|
||||
ForeignKey,
|
||||
Integer,
|
||||
String,
|
||||
)
|
||||
from sqlalchemy.orm import (
|
||||
Mapped,
|
||||
mapped_column,
|
||||
relationship,
|
||||
)
|
||||
|
||||
from .Base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .User import User
|
||||
from .Purchase import Purchase
|
||||
|
||||
class Transaction(Base):
|
||||
__tablename__ = 'transactions'
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
|
||||
time: Mapped[datetime] = mapped_column(DateTime)
|
||||
amount: Mapped[int] = mapped_column(Integer)
|
||||
penalty: Mapped[int] = mapped_column(Integer)
|
||||
description: Mapped[str | None] = mapped_column(String(50))
|
||||
|
||||
user_name: Mapped[str] = mapped_column(ForeignKey('users.name'))
|
||||
purchase_id: Mapped[int | None] = mapped_column(ForeignKey('purchases.id'))
|
||||
|
||||
user: Mapped[User] = relationship(lazy='joined')
|
||||
purchase: Mapped[Purchase] = relationship(lazy='joined')
|
||||
|
||||
def __init__(self, user, amount=0, description=None, purchase=None, penalty=1):
|
||||
self.user = user
|
||||
self.amount = amount
|
||||
self.description = description
|
||||
self.purchase = purchase
|
||||
self.penalty = penalty
|
||||
|
||||
def perform_transaction(self, ignore_penalty=False):
|
||||
self.time = datetime.datetime.now()
|
||||
if not ignore_penalty:
|
||||
self.amount *= self.penalty
|
||||
self.user.credit -= self.amount
|
47
dibbler/models/User.py
Normal file
47
dibbler/models/User.py
Normal file
@ -0,0 +1,47 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import (
|
||||
Integer,
|
||||
String,
|
||||
)
|
||||
from sqlalchemy.orm import (
|
||||
Mapped,
|
||||
mapped_column,
|
||||
relationship,
|
||||
)
|
||||
|
||||
from .Base import Base
|
||||
if TYPE_CHECKING:
|
||||
from .UserProducts import UserProducts
|
||||
from .Transaction import Transaction
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = 'users'
|
||||
name: Mapped[str] = mapped_column(String(10), primary_key=True)
|
||||
credit: Mapped[str] = mapped_column(Integer)
|
||||
card: Mapped[str | None] = mapped_column(String(20))
|
||||
rfid: Mapped[str | None] = mapped_column(String(20))
|
||||
|
||||
products: Mapped[set[UserProducts]] = relationship(back_populates="user")
|
||||
transactions: Mapped[set[Transaction]] = relationship(back_populates="user")
|
||||
|
||||
name_re = r"[a-z]+"
|
||||
card_re = r"(([Nn][Tt][Nn][Uu])?[0-9]+)?"
|
||||
rfid_re = r"[0-9a-fA-F]*"
|
||||
|
||||
def __init__(self, name, card, rfid=None, credit=0):
|
||||
self.name = name
|
||||
if card == '':
|
||||
card = None
|
||||
self.card = card
|
||||
if rfid == '':
|
||||
rfid = None
|
||||
self.rfid = rfid
|
||||
self.credit = credit
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def is_anonymous(self):
|
||||
return self.card == '11122233'
|
31
dibbler/models/UserProducts.py
Normal file
31
dibbler/models/UserProducts.py
Normal file
@ -0,0 +1,31 @@
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import (
|
||||
Integer,
|
||||
ForeignKey,
|
||||
)
|
||||
from sqlalchemy.orm import (
|
||||
Mapped,
|
||||
mapped_column,
|
||||
relationship,
|
||||
)
|
||||
|
||||
from .Base import Base
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .User import User
|
||||
from .Product import Product
|
||||
|
||||
class UserProducts(Base):
|
||||
__tablename__ = 'user_products'
|
||||
|
||||
user_name: Mapped[str] = mapped_column(ForeignKey('users.name'), primary_key=True)
|
||||
product_id: Mapped[int] = mapped_column(ForeignKey("products.product_id"), primary_key=True)
|
||||
|
||||
count: Mapped[int] = mapped_column(Integer)
|
||||
sign: Mapped[int] = mapped_column(Integer)
|
||||
|
||||
user: Mapped[User] = relationship()
|
||||
product: Mapped[Product] = relationship()
|
||||
|
@ -0,0 +1,7 @@
|
||||
from .Base import Base
|
||||
from .Product import Product
|
||||
from .Purchase import Purchase
|
||||
from .PurchaseEntry import PurchaseEntry
|
||||
from .Transaction import Transaction
|
||||
from .User import User
|
||||
from .UserProducts import UserProducts
|
@ -1,177 +0,0 @@
|
||||
from math import ceil, floor
|
||||
import datetime
|
||||
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine, DateTime, Boolean
|
||||
from sqlalchemy.orm import sessionmaker, relationship, backref
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
from dibbler.conf import config
|
||||
|
||||
engine = create_engine(config.get('database', 'url'))
|
||||
Base = declarative_base()
|
||||
Session = sessionmaker(bind=engine)
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = 'users'
|
||||
name = Column(String(10), primary_key=True)
|
||||
card = Column(String(20))
|
||||
rfid = Column(String(20))
|
||||
credit = Column(Integer)
|
||||
|
||||
name_re = r"[a-z]+"
|
||||
card_re = r"(([Nn][Tt][Nn][Uu])?[0-9]+)?"
|
||||
rfid_re = r"[0-9a-fA-F]*"
|
||||
|
||||
def __init__(self, name, card, rfid=None, credit=0):
|
||||
self.name = name
|
||||
if card == '':
|
||||
card = None
|
||||
self.card = card
|
||||
if rfid == '':
|
||||
rfid = None
|
||||
self.rfid = rfid
|
||||
self.credit = credit
|
||||
|
||||
def __repr__(self):
|
||||
return f"<User('{self.name}')>"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def is_anonymous(self):
|
||||
return self.card == '11122233'
|
||||
|
||||
|
||||
class Product(Base):
|
||||
__tablename__ = 'products'
|
||||
|
||||
product_id = Column(Integer, primary_key=True)
|
||||
bar_code = Column(String(13))
|
||||
name = Column(String(45))
|
||||
price = Column(Integer)
|
||||
stock = Column(Integer)
|
||||
hidden = Column(Boolean, nullable=False, default=False)
|
||||
|
||||
bar_code_re = r"[0-9]+"
|
||||
name_re = r".+"
|
||||
name_length = 45
|
||||
|
||||
def __init__(self, bar_code, name, price, stock=0, hidden = False):
|
||||
self.name = name
|
||||
self.bar_code = bar_code
|
||||
self.price = price
|
||||
self.stock = stock
|
||||
self.hidden = hidden
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Product('{self.name}', '{self.bar_code}', '{self.price}', '{self.stock}', '{self.hidden}')>"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class UserProducts(Base):
|
||||
__tablename__ = 'user_products'
|
||||
user_name = Column(String(10), ForeignKey('users.name'), primary_key=True)
|
||||
product_id = Column(Integer, ForeignKey("products.product_id"), primary_key=True)
|
||||
count = Column(Integer)
|
||||
sign = Column(Integer)
|
||||
|
||||
user = relationship(User, backref=backref('products', order_by=count.desc()), lazy='joined')
|
||||
product = relationship(Product, backref="users", lazy='joined')
|
||||
|
||||
|
||||
class PurchaseEntry(Base):
|
||||
__tablename__ = 'purchase_entries'
|
||||
id = Column(Integer, primary_key=True)
|
||||
purchase_id = Column(Integer, ForeignKey("purchases.id"))
|
||||
product_id = Column(Integer, ForeignKey("products.product_id"))
|
||||
amount = Column(Integer)
|
||||
|
||||
product = relationship(Product, backref="purchases")
|
||||
|
||||
def __init__(self, purchase, product, amount):
|
||||
self.product = product
|
||||
self.product_bar_code = product.bar_code
|
||||
self.purchase = purchase
|
||||
self.amount = amount
|
||||
|
||||
def __repr__(self):
|
||||
return f"<PurchaseEntry('{self.product.name}', '{self.amount}')>"
|
||||
|
||||
|
||||
class Transaction(Base):
|
||||
__tablename__ = 'transactions'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
time = Column(DateTime)
|
||||
user_name = Column(String(10), ForeignKey('users.name'))
|
||||
amount = Column(Integer)
|
||||
description = Column(String(50))
|
||||
purchase_id = Column(Integer, ForeignKey('purchases.id'))
|
||||
penalty = Column(Integer)
|
||||
|
||||
user = relationship(User, backref=backref('transactions', order_by=time))
|
||||
|
||||
def __init__(self, user, amount=0, description=None, purchase=None, penalty=1):
|
||||
self.user = user
|
||||
self.amount = amount
|
||||
self.description = description
|
||||
self.purchase = purchase
|
||||
self.penalty = penalty
|
||||
|
||||
def perform_transaction(self, ignore_penalty=False):
|
||||
self.time = datetime.datetime.now()
|
||||
if not ignore_penalty:
|
||||
self.amount *= self.penalty
|
||||
self.user.credit -= self.amount
|
||||
|
||||
|
||||
class Purchase(Base):
|
||||
__tablename__ = 'purchases'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
time = Column(DateTime)
|
||||
price = Column(Integer)
|
||||
|
||||
transactions = relationship(Transaction, order_by=Transaction.user_name, backref='purchase')
|
||||
entries = relationship(PurchaseEntry, backref=backref("purchase"))
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Purchase({int(self.id):d}, {self.price:d}, '{self.time.strftime('%c')}')>"
|
||||
|
||||
def is_complete(self):
|
||||
return len(self.transactions) > 0 and len(self.entries) > 0
|
||||
|
||||
def price_per_transaction(self, round_up=True):
|
||||
if round_up:
|
||||
return int(ceil(float(self.price)/len(self.transactions)))
|
||||
else:
|
||||
return int(floor(float(self.price)/len(self.transactions)))
|
||||
|
||||
def set_price(self, round_up=True):
|
||||
self.price = 0
|
||||
for entry in self.entries:
|
||||
self.price += entry.amount*entry.product.price
|
||||
if len(self.transactions) > 0:
|
||||
for t in self.transactions:
|
||||
t.amount = self.price_per_transaction(round_up=round_up)
|
||||
|
||||
def perform_purchase(self, ignore_penalty=False, round_up=True):
|
||||
self.time = datetime.datetime.now()
|
||||
self.set_price(round_up=round_up)
|
||||
for t in self.transactions:
|
||||
t.perform_transaction(ignore_penalty=ignore_penalty)
|
||||
for entry in self.entries:
|
||||
entry.product.stock -= entry.amount
|
||||
|
||||
def perform_soft_purchase(self, price, round_up=True):
|
||||
self.time = datetime.datetime.now()
|
||||
self.price = price
|
||||
for t in self.transactions:
|
||||
t.amount = self.price_per_transaction(round_up=round_up)
|
||||
for t in self.transactions:
|
||||
t.perform_transaction()
|
9
dibbler/scripts/makedb.py
Normal file
9
dibbler/scripts/makedb.py
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/python
|
||||
from dibbler.models import Base
|
||||
from dibbler.db import engine
|
||||
|
||||
def main():
|
||||
Base.metadata.create_all(engine)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,6 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from dibbler.models.db import *
|
||||
from dibbler.db import Session
|
||||
from dibbler.models import User
|
||||
|
||||
def main():
|
||||
# Start an SQL session
|
||||
|
@ -5,7 +5,8 @@ import datetime
|
||||
from collections import defaultdict
|
||||
|
||||
from .helpers import *
|
||||
from .models.db import *;
|
||||
from .models import Transaction
|
||||
from .db import Session
|
||||
|
||||
def getUser():
|
||||
while 1:
|
||||
|
@ -29,7 +29,6 @@ from .conf import config
|
||||
|
||||
random.seed()
|
||||
|
||||
|
||||
def main():
|
||||
if not config.getboolean('general', 'stop_allowed'):
|
||||
signal.signal(signal.SIGQUIT, signal.SIG_IGN)
|
||||
|
@ -5,7 +5,8 @@ show_tracebacks = true
|
||||
input_encoding = 'utf8'
|
||||
|
||||
[database]
|
||||
url = postgresql://robertem@127.0.0.1/pvvvv
|
||||
; url = postgresql://robertem@127.0.0.1/pvvvv
|
||||
url = sqlite:///test.db
|
||||
|
||||
[limits]
|
||||
low_credit_warning_limit = -100
|
||||
|
@ -32,7 +32,7 @@ in {
|
||||
wantedBy = [ "default.target" ];
|
||||
serviceConfig = {
|
||||
ExecStartPre = "-${screen} -X -S dibbler kill";
|
||||
ExecStart = "${screen} -dmS dibbler -O -l ${cfg.package}/bin/dibbler --config ${cfg.config}";
|
||||
ExecStart = "${screen} -dmS dibbler -O -l ${cfg.package}/bin/dibbler --config ${cfg.config} loop";
|
||||
ExecStartPost = "${screen} -X -S dibbler width 42 80";
|
||||
User = "dibbler";
|
||||
Group = "dibbler";
|
||||
@ -41,7 +41,7 @@ in {
|
||||
Restart = "always";
|
||||
RestartSec = "5s";
|
||||
SuccessExitStatus = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/issues/84105
|
||||
|
@ -25,6 +25,4 @@ dynamic = ["version"]
|
||||
include = ["dibbler*"]
|
||||
|
||||
[project.scripts]
|
||||
dibbler = "dibbler.cli:main"
|
||||
slabbedasker = "dibbler.scripts.slabbedasker:main"
|
||||
statistikk = "dibbler.scripts.statistikk:main"
|
||||
dibbler = "dibbler.main:main"
|
Loading…
Reference in New Issue
Block a user