first commit
This commit is contained in:
122
.gitignore
vendored
Normal file
122
.gitignore
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Python template
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.idea
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
*.iml
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
venvwindows/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
app/package.json
|
||||||
|
app/package-lock.json
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
|
||||||
|
instance/config.py
|
||||||
|
.idea/
|
||||||
|
/passwords.py
|
||||||
|
|
||||||
|
getnewitems.py
|
||||||
|
helperfunctions/
|
||||||
|
test.py
|
||||||
|
tools/
|
||||||
|
nginx.txt
|
||||||
|
app/node_modules/
|
||||||
19
Dockerfile.dev
Normal file
19
Dockerfile.dev
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM python:3.12-bullseye
|
||||||
|
|
||||||
|
ENV PYTHONFAULTHANDLER=1
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
ENV MODE="DEVELOPMENT"
|
||||||
|
|
||||||
|
RUN mkdir -p /app
|
||||||
|
|
||||||
|
COPY requirements.txt /app
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
COPY . /app
|
||||||
19
Dockerfile.local
Normal file
19
Dockerfile.local
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM python:3.12-bullseye
|
||||||
|
|
||||||
|
ENV PYTHONFAULTHANDLER=1
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
ENV MODE="LOCAL"
|
||||||
|
|
||||||
|
RUN mkdir -p /app
|
||||||
|
|
||||||
|
COPY requirements.txt /app
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
COPY . /app
|
||||||
19
Dockerfile.prod
Normal file
19
Dockerfile.prod
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM python:3.12-bullseye
|
||||||
|
|
||||||
|
ENV PYTHONFAULTHANDLER=1
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
ENV MODE="PRODUCTION"
|
||||||
|
|
||||||
|
RUN mkdir -p /app
|
||||||
|
|
||||||
|
COPY requirements.txt /app
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
COPY . /app
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Eamco Playground
|
||||||
|
|
||||||
|
This is a FastAPI project for Eamco playground application.
|
||||||
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
0
app/models/__init__.py
Normal file
0
app/models/__init__.py
Normal file
86
app/models/auto.py
Normal file
86
app/models/auto.py
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
from sqlalchemy import (Column, Integer,
|
||||||
|
DECIMAL, TEXT,
|
||||||
|
VARCHAR, DATE, INTEGER)
|
||||||
|
from datetime import datetime
|
||||||
|
from database import Base
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Auto_Update(Base):
|
||||||
|
__tablename__ = 'auto_update'
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
|
||||||
|
last_updated = Column(DATE())
|
||||||
|
|
||||||
|
|
||||||
|
class Auto_Temp(Base):
|
||||||
|
__tablename__ = 'auto_temp'
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
|
||||||
|
todays_date = Column(DATE)
|
||||||
|
temp = Column(DECIMAL(5, 2))
|
||||||
|
temp_max = Column(DECIMAL(5, 2))
|
||||||
|
temp_min = Column(DECIMAL(5, 2))
|
||||||
|
temp_avg = Column(DECIMAL(5, 2))
|
||||||
|
degree_day = Column(INTEGER())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Auto_Delivery(Base):
|
||||||
|
__tablename__ = 'auto_delivery'
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
|
||||||
|
customer_id = Column(INTEGER())
|
||||||
|
account_number = Column(VARCHAR(25))
|
||||||
|
customer_town = Column(VARCHAR(140))
|
||||||
|
customer_state = Column(INTEGER)
|
||||||
|
customer_address = Column(VARCHAR(1000))
|
||||||
|
customer_zip = Column(VARCHAR(25))
|
||||||
|
customer_full_name = Column(VARCHAR(250))
|
||||||
|
last_fill = Column(DATE())
|
||||||
|
days_since_last_fill = Column(INTEGER())
|
||||||
|
last_updated = Column(DATE())
|
||||||
|
estimated_gallons_left = Column(DECIMAL(6, 2))
|
||||||
|
estimated_gallons_left_prev_day = Column(DECIMAL(6, 2))
|
||||||
|
tank_height = Column(VARCHAR(25))
|
||||||
|
tank_size = Column(VARCHAR(25))
|
||||||
|
house_factor = Column(DECIMAL(5, 2))
|
||||||
|
auto_status = Column(INTEGER())
|
||||||
|
|
||||||
|
|
||||||
|
class Tickets_Auto_Delivery(Base):
|
||||||
|
__tablename__ = 'auto_tickets'
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
customer_id = Column(INTEGER())
|
||||||
|
account_number = Column(VARCHAR(25))
|
||||||
|
|
||||||
|
customer_town = Column(VARCHAR(140))
|
||||||
|
customer_state = Column(Integer)
|
||||||
|
customer_address = Column(VARCHAR(1000))
|
||||||
|
customer_zip = Column(VARCHAR(25))
|
||||||
|
customer_full_name = Column(VARCHAR(250))
|
||||||
|
customer_zip = Column(VARCHAR(25))
|
||||||
|
|
||||||
|
oil_prices_id = Column(INTEGER())
|
||||||
|
fill_date = Column(DATE())
|
||||||
|
gallons_delivered = Column(DECIMAL(6, 2))
|
||||||
|
price_per_gallon = Column(DECIMAL(6, 2))
|
||||||
|
|
||||||
|
total_amount_customer = Column(DECIMAL(6, 2))
|
||||||
29
app/models/cards.py
Normal file
29
app/models/cards.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
from sqlalchemy import (Column, Integer,
|
||||||
|
BOOLEAN, DATE, String,
|
||||||
|
VARCHAR,
|
||||||
|
INTEGER)
|
||||||
|
|
||||||
|
from database import Base
|
||||||
|
|
||||||
|
|
||||||
|
class Card_Card(Base):
|
||||||
|
__tablename__ = 'card_card'
|
||||||
|
__table_args__ = {"schema": "public"}
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
date_added = Column(DATE())
|
||||||
|
user_id = Column(INTEGER())
|
||||||
|
card_number = Column(VARCHAR(50))
|
||||||
|
last_four_digits = Column(INTEGER())
|
||||||
|
name_on_card = Column(VARCHAR(500))
|
||||||
|
expiration_month = Column(INTEGER())
|
||||||
|
expiration_year = Column(INTEGER())
|
||||||
|
type_of_card = Column(VARCHAR(500))
|
||||||
|
security_number = Column(INTEGER())
|
||||||
|
accepted_or_declined = Column(INTEGER())
|
||||||
|
main_card = Column(BOOLEAN())
|
||||||
|
auth_net_payment_profile_id = Column(String, unique=True, index=True, nullable=False)
|
||||||
31
app/models/customer.py
Normal file
31
app/models/customer.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
from sqlalchemy import (Column, Integer,
|
||||||
|
String,
|
||||||
|
VARCHAR,
|
||||||
|
DATE, INTEGER)
|
||||||
|
from database import Base
|
||||||
|
|
||||||
|
|
||||||
|
class Customer_Customer(Base):
|
||||||
|
__tablename__ = 'customer_customer'
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
auth_net_profile_id = Column(String, unique=True, index=True, nullable=True)
|
||||||
|
account_number = Column(VARCHAR(25))
|
||||||
|
customer_last_name = Column(VARCHAR(250))
|
||||||
|
customer_first_name = Column(VARCHAR(250))
|
||||||
|
customer_town = Column(VARCHAR(140))
|
||||||
|
customer_state = Column(INTEGER)
|
||||||
|
customer_zip = Column(VARCHAR(25))
|
||||||
|
customer_first_call = Column(DATE())
|
||||||
|
customer_email = Column(VARCHAR(500))
|
||||||
|
customer_automatic = Column(INTEGER)
|
||||||
|
customer_phone_number = Column(VARCHAR(25))
|
||||||
|
customer_home_type = Column(INTEGER)
|
||||||
|
customer_apt = Column(VARCHAR(140))
|
||||||
|
customer_address = Column(VARCHAR(1000))
|
||||||
|
company_id = Column(INTEGER)
|
||||||
|
|
||||||
|
|
||||||
51
app/models/delivery.py
Normal file
51
app/models/delivery.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
from sqlalchemy import (Column, INTEGER,
|
||||||
|
DECIMAL, TEXT,
|
||||||
|
VARCHAR, TIMESTAMP, DATE)
|
||||||
|
import datetime
|
||||||
|
from database import Base
|
||||||
|
|
||||||
|
|
||||||
|
class Delivery(Base):
|
||||||
|
__tablename__ = "delivery_delivery"
|
||||||
|
|
||||||
|
id = Column(INTEGER,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
|
||||||
|
customer_id = Column(INTEGER)
|
||||||
|
customer_name = Column(VARCHAR(1000))
|
||||||
|
customer_address = Column(VARCHAR(1000))
|
||||||
|
customer_town = Column(VARCHAR(140))
|
||||||
|
customer_state = Column(VARCHAR(140))
|
||||||
|
customer_zip = Column(VARCHAR(10))
|
||||||
|
|
||||||
|
gallons_ordered = Column(INTEGER)
|
||||||
|
customer_asked_for_fill = Column(INTEGER)
|
||||||
|
gallons_delivered = Column(DECIMAL(6, 2))
|
||||||
|
customer_filled = Column(INTEGER)
|
||||||
|
|
||||||
|
delivery_status = Column(INTEGER)
|
||||||
|
when_ordered = Column(DATE(), )
|
||||||
|
when_delivered = Column(DATE())
|
||||||
|
expected_delivery_date = Column(DATE(), default=None)
|
||||||
|
automatic = Column(INTEGER)
|
||||||
|
automatic_id = Column(INTEGER)
|
||||||
|
oil_id = Column(INTEGER)
|
||||||
|
supplier_price = Column(DECIMAL(6, 2))
|
||||||
|
customer_price = Column(DECIMAL(6, 2))
|
||||||
|
customer_temperature = Column(DECIMAL(6, 2))
|
||||||
|
dispatcher_notes = Column(TEXT())
|
||||||
|
prime = Column(INTEGER)
|
||||||
|
same_day = Column(INTEGER)
|
||||||
|
payment_type = Column(INTEGER)
|
||||||
|
payment_card_id = Column(INTEGER)
|
||||||
|
cash_recieved = Column(DECIMAL(6, 2))
|
||||||
|
|
||||||
|
driver_employee_id = Column(INTEGER)
|
||||||
|
driver_first_name = Column(VARCHAR(140))
|
||||||
|
driver_last_name = Column(VARCHAR(140))
|
||||||
|
|
||||||
|
pre_charge_amount = Column(DECIMAL(6, 2))
|
||||||
|
total_price = Column(DECIMAL(6, 2))
|
||||||
|
final_price = Column(DECIMAL(6, 2))
|
||||||
29
app/models/employee.py
Normal file
29
app/models/employee.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from sqlalchemy import (Column, INTEGER,
|
||||||
|
DECIMAL, TEXT,
|
||||||
|
VARCHAR, TIMESTAMP, DATE)
|
||||||
|
import datetime
|
||||||
|
from database import Base
|
||||||
|
|
||||||
|
|
||||||
|
class Employee_Employee(Base):
|
||||||
|
__tablename__ = 'employee_employee'
|
||||||
|
__table_args__ = {"schema": "public"}
|
||||||
|
|
||||||
|
id = Column(INTEGER,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
|
||||||
|
user_id = Column(INTEGER)
|
||||||
|
employee_first_name = Column(VARCHAR(250))
|
||||||
|
employee_last_name = Column(VARCHAR(250))
|
||||||
|
employee_apt = Column(VARCHAR(250))
|
||||||
|
employee_address = Column(VARCHAR(1000))
|
||||||
|
employee_town = Column(VARCHAR(140))
|
||||||
|
employee_state = Column(VARCHAR(140))
|
||||||
|
employee_zip = Column(VARCHAR(25))
|
||||||
|
employee_birthday = Column(DATE())
|
||||||
|
employee_type = Column(INTEGER)
|
||||||
|
employee_phone_number = Column(VARCHAR(25))
|
||||||
|
employee_start_date = Column(DATE())
|
||||||
|
employee_end_date = Column(DATE(), default=None)
|
||||||
28
app/models/money.py
Normal file
28
app/models/money.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from sqlalchemy import (Column, Integer,
|
||||||
|
DECIMAL, Text,
|
||||||
|
VARCHAR, TIMESTAMP, Date)
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from database import Base
|
||||||
|
|
||||||
|
|
||||||
|
class MoneyDelivery(Base):
|
||||||
|
__tablename__ = 'money_delivery'
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
|
||||||
|
delivery_id = Column(Integer)
|
||||||
|
time_added = Column(TIMESTAMP(), default=datetime.utcnow())
|
||||||
|
gallons_delivered = Column(DECIMAL(6, 2))
|
||||||
|
supplier_price = Column(DECIMAL(6, 2))
|
||||||
|
customer_price = Column(DECIMAL(6, 2))
|
||||||
|
total_amount_oil = Column(DECIMAL(6, 2))
|
||||||
|
total_amount_prime = Column(DECIMAL(6, 2))
|
||||||
|
total_amount_same_day = Column(DECIMAL(6, 2))
|
||||||
|
total_amount_fee = Column(DECIMAL(6, 2))
|
||||||
|
total_amount = Column(DECIMAL(6, 2))
|
||||||
|
taxes_paid = Column(DECIMAL(6, 2))
|
||||||
|
total_profit = Column(DECIMAL(6, 2))
|
||||||
|
total_profit_oil = Column(DECIMAL(6, 2))
|
||||||
34
app/models/pricing.py
Normal file
34
app/models/pricing.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from sqlalchemy import (Column, Integer, DECIMAL, TIMESTAMP)
|
||||||
|
from datetime import datetime
|
||||||
|
from database import Base
|
||||||
|
|
||||||
|
|
||||||
|
class Pricing_Oil_Oil(Base):
|
||||||
|
__tablename__ = 'pricing_oil_oil'
|
||||||
|
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
|
||||||
|
price_from_supplier = Column(DECIMAL(6, 2))
|
||||||
|
price_for_customer = Column(DECIMAL(6, 2))
|
||||||
|
price_for_employee = Column(DECIMAL(6, 2))
|
||||||
|
price_same_day = Column(DECIMAL(6, 2))
|
||||||
|
price_prime = Column(DECIMAL(6, 2))
|
||||||
|
date = Column(TIMESTAMP(), default=datetime.utcnow())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Pricing_Taxes(Base):
|
||||||
|
__tablename__ = 'taxes_pricing'
|
||||||
|
|
||||||
|
|
||||||
|
id = Column(Integer,
|
||||||
|
primary_key=True,
|
||||||
|
autoincrement=True,
|
||||||
|
unique=False)
|
||||||
|
state_id = Column(Integer)
|
||||||
|
taxes_oil = Column(DECIMAL(6, 2))
|
||||||
|
taxes_other = Column(DECIMAL(6, 2))
|
||||||
0
app/routers/__init__.py
Normal file
0
app/routers/__init__.py
Normal file
106
app/routers/confirm.py
Normal file
106
app/routers/confirm.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
|
||||||
|
from fastapi import APIRouter, Request
|
||||||
|
from datetime import date
|
||||||
|
from database import session
|
||||||
|
from pyowm import OWM
|
||||||
|
from decimal import Decimal
|
||||||
|
from app.models.auto import Auto_Delivery, Tickets_Auto_Delivery
|
||||||
|
from app.models.pricing import Pricing_Oil_Oil
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
from app.script.update_auto import calc_home_factor
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/confirm",
|
||||||
|
tags=["confirm"],
|
||||||
|
responses={404: {"description": "Not found"}},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/auto/update/{autoid}")
|
||||||
|
async def update_auto(autoid: int, request: Request):
|
||||||
|
|
||||||
|
request_body = await request.json()
|
||||||
|
gallons_delivered = request_body['gallons_delivered']
|
||||||
|
gallons_delivered = Decimal(gallons_delivered)
|
||||||
|
|
||||||
|
|
||||||
|
get_auto_delivery = (session
|
||||||
|
.query(Auto_Delivery)
|
||||||
|
.filter(Auto_Delivery.id == autoid)
|
||||||
|
.first())
|
||||||
|
|
||||||
|
gallons_put_in_home = Decimal(gallons_delivered)
|
||||||
|
|
||||||
|
customer_home_factor = get_auto_delivery.house_factor
|
||||||
|
|
||||||
|
|
||||||
|
new_home_factor = calc_home_factor(gallons_put_in_home = gallons_put_in_home,
|
||||||
|
current_house_factor=customer_home_factor)
|
||||||
|
|
||||||
|
gallons_left_buffer = int(get_auto_delivery.tank_size) - 30
|
||||||
|
|
||||||
|
|
||||||
|
get_auto_delivery.house_factor = new_home_factor
|
||||||
|
get_auto_delivery.tank_height = 'Full'
|
||||||
|
get_auto_delivery.last_fill = date.today()
|
||||||
|
get_auto_delivery.estimated_gallons_left = gallons_left_buffer
|
||||||
|
get_auto_delivery.estimated_gallons_left_prev_day = gallons_left_buffer
|
||||||
|
get_auto_delivery.auto_status = 1
|
||||||
|
get_auto_delivery.days_since_last_fill = 0
|
||||||
|
|
||||||
|
session.add(get_auto_delivery)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
return ({"ok": True}), 200
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/auto/create/{autoid}")
|
||||||
|
async def create_auto_ticket(autoid: int, request: Request):
|
||||||
|
|
||||||
|
|
||||||
|
request_body = await request.json()
|
||||||
|
gallons_delivered = request_body['gallons_delivered']
|
||||||
|
gallons_delivered = Decimal(gallons_delivered)
|
||||||
|
|
||||||
|
|
||||||
|
get_auto_delivery = (session
|
||||||
|
.query(Auto_Delivery)
|
||||||
|
.filter(Auto_Delivery.id == autoid)
|
||||||
|
.first())
|
||||||
|
get_todays_price = (session.query(Pricing_Oil_Oil)
|
||||||
|
.order_by(Pricing_Oil_Oil.id.desc())
|
||||||
|
.first())
|
||||||
|
gallons_put_in_home = Decimal(gallons_delivered)
|
||||||
|
todays_price = Decimal(get_todays_price.price_for_customer)
|
||||||
|
total_amount = gallons_put_in_home * todays_price
|
||||||
|
|
||||||
|
create_new_ticket = Tickets_Auto_Delivery(
|
||||||
|
customer_id = get_auto_delivery.customer_id,
|
||||||
|
account_number = get_auto_delivery.account_number,
|
||||||
|
customer_town = get_auto_delivery.customer_town,
|
||||||
|
customer_state = get_auto_delivery.customer_state,
|
||||||
|
customer_address = get_auto_delivery.customer_address,
|
||||||
|
customer_zip =get_auto_delivery.customer_zip,
|
||||||
|
customer_full_name = get_auto_delivery.customer_full_name,
|
||||||
|
oil_prices_id = get_todays_price.id,
|
||||||
|
gallons_delivered = gallons_delivered,
|
||||||
|
price_per_gallon = get_todays_price.price_for_customer,
|
||||||
|
total_amount_customer = total_amount,
|
||||||
|
fill_date = date.today(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
session.add(create_new_ticket)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
return ({
|
||||||
|
"ok": True,
|
||||||
|
"auto_ticket_id":create_new_ticket.id
|
||||||
|
}), 200
|
||||||
|
|
||||||
95
app/routers/delivery.py
Normal file
95
app/routers/delivery.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
from fastapi import APIRouter, Request, Depends
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
from fastapi.encoders import jsonable_encoder
|
||||||
|
from database import session
|
||||||
|
|
||||||
|
from app.models.auto import Auto_Delivery, Tickets_Auto_Delivery
|
||||||
|
from app.models.delivery import Delivery
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/delivery",
|
||||||
|
tags=["delivery"],
|
||||||
|
responses={404: {"description": "Not found"}},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/past/{customer_id}", status_code=200)
|
||||||
|
def past(customer_id: int):
|
||||||
|
|
||||||
|
get_customer_past_delivery = (session
|
||||||
|
.query(Delivery)
|
||||||
|
.filter(Delivery.customer_id == customer_id)
|
||||||
|
.order_by(Delivery.id.desc())
|
||||||
|
.all())
|
||||||
|
print(get_customer_past_delivery)
|
||||||
|
return JSONResponse(content=jsonable_encoder(get_customer_past_delivery), status_code=200)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/all/customers", status_code=200)
|
||||||
|
def get_delivery_customers():
|
||||||
|
|
||||||
|
|
||||||
|
automatics = (
|
||||||
|
session.query(Auto_Delivery)
|
||||||
|
.filter(Auto_Delivery.auto_status == 1)
|
||||||
|
.order_by(Auto_Delivery.estimated_gallons_left.asc())
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(content=jsonable_encoder(automatics), status_code=200)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/driver/{driver_employee_id}", status_code=200)
|
||||||
|
def get_delivery_for_specific_driver(driver_employee_id: int):
|
||||||
|
automatics = (
|
||||||
|
session.query(Delivery)
|
||||||
|
.filter(Delivery.driver_employee_id == driver_employee_id)
|
||||||
|
.filter(Delivery.automatic == 1)
|
||||||
|
.filter(Delivery.delivery_status == 0)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(content=jsonable_encoder(automatics), status_code=200)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{auto_id}", status_code=200)
|
||||||
|
def get_auto(auto_id):
|
||||||
|
|
||||||
|
get_delivery = (
|
||||||
|
session.query(Auto_Delivery)
|
||||||
|
.filter(Auto_Delivery.id == auto_id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(content=jsonable_encoder(get_delivery), status_code=200)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/delivery/{delivery_id_order}", status_code=200)
|
||||||
|
def get_delivery(delivery_id_order):
|
||||||
|
|
||||||
|
get_delivery = (
|
||||||
|
session.query(Tickets_Auto_Delivery)
|
||||||
|
.filter(Tickets_Auto_Delivery.id == delivery_id_order)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(content=jsonable_encoder(get_delivery), status_code=200)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/all/profile/{customer_id}", status_code=200)
|
||||||
|
def get_autos_customers(customer_id):
|
||||||
|
|
||||||
|
get_delivery = (
|
||||||
|
session.query(Tickets_Auto_Delivery)
|
||||||
|
.filter(Tickets_Auto_Delivery.customer_id == customer_id)
|
||||||
|
.order_by(Tickets_Auto_Delivery.id.asc())
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
|
return JSONResponse(content=jsonable_encoder(get_delivery), status_code=200)
|
||||||
305
app/routers/main.py
Normal file
305
app/routers/main.py
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
## File: app/routers/main.py (or your equivalent path)
|
||||||
|
|
||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from sqlalchemy import func
|
||||||
|
|
||||||
|
|
||||||
|
# Your existing imports
|
||||||
|
from database import session
|
||||||
|
from pyowm import OWM
|
||||||
|
|
||||||
|
from app.models.customer import Customer_Customer
|
||||||
|
from app.models.cards import Card_Card
|
||||||
|
# Imports needed for the migration task.
|
||||||
|
# YOU MUST ADJUST THESE IMPORTS TO MATCH YOUR PROJECT'S ACTUAL STRUCTURE.
|
||||||
|
from database import session # Assuming your SessionLocal is here for a clean session
|
||||||
|
from authorizenet import apicontractsv1
|
||||||
|
from authorizenet.constants import constants
|
||||||
|
from authorizenet.apicontrollers import (
|
||||||
|
createCustomerProfileController,
|
||||||
|
createCustomerPaymentProfileController,
|
||||||
|
getCustomerProfileIdsController,
|
||||||
|
getCustomerProfileController
|
||||||
|
)
|
||||||
|
# --- ROUTER DEFINITION ---
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/main",
|
||||||
|
tags=["main"],
|
||||||
|
responses={404: {"description": "Not found"}},
|
||||||
|
)
|
||||||
|
|
||||||
|
API_LOGIN_ID = '9U6w96gZmX'
|
||||||
|
TRANSACTION_KEY = '94s6Qy458mMNJr7G'
|
||||||
|
|
||||||
|
constants.show_url_on_request = True
|
||||||
|
constants.environment = constants.SANDBOX
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/maintenance/migrate-cards-now")
|
||||||
|
def run_card_migration_synchronously():
|
||||||
|
"""
|
||||||
|
Triggers a one-time, SYNCHRONOUS task to migrate all existing, insecurely
|
||||||
|
stored credit cards from the `card_card` table to secure Authorize.Net CIM profiles.
|
||||||
|
This function is self-contained and does not use `crud` or `schemas`.
|
||||||
|
|
||||||
|
WARNING: This is a long-running process and the request may time out.
|
||||||
|
Monitor server logs for completion. This endpoint should be removed after use.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _create_authnet_profile(customer_obj: Customer_Customer, card_obj: Card_Card):
|
||||||
|
"""Helper to create a new Authorize.Net Customer Profile."""
|
||||||
|
merchantAuth = apicontractsv1.merchantAuthenticationType(name=API_LOGIN_ID, transactionKey=TRANSACTION_KEY)
|
||||||
|
expiration_date_str = f"{card_obj.expiration_year}-{str(card_obj.expiration_month).zfill(2)}"
|
||||||
|
|
||||||
|
# Validate expiration
|
||||||
|
month = None
|
||||||
|
year = None
|
||||||
|
if card_obj.expiration_month:
|
||||||
|
try:
|
||||||
|
month = int(card_obj.expiration_month)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if card_obj.expiration_year:
|
||||||
|
try:
|
||||||
|
year = int(card_obj.expiration_year)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if not year or not month or month < 1 or month > 12 or year < 2000 or year > 2050:
|
||||||
|
raise ValueError(f"Invalid expiration year={card_obj.expiration_year}, month={card_obj.expiration_month} for card ID {card_obj.id}")
|
||||||
|
expiration_date_str = f"{year:04d}-{month:02d}"
|
||||||
|
# // FIX 1: Sanitize card number by removing all non-digit characters
|
||||||
|
sanitized_card_number = ''.join(filter(str.isdigit, str(card_obj.card_number)))
|
||||||
|
if len(sanitized_card_number) < 13 or len(sanitized_card_number) > 19 or not sanitized_card_number.isdigit():
|
||||||
|
raise ValueError(f"Invalid card number length {len(sanitized_card_number)} or non-numeric for card ID {card_obj.id}")
|
||||||
|
# Sanitize CVV
|
||||||
|
cardCode = str(card_obj.security_number).strip()
|
||||||
|
if len(cardCode) < 3 or len(cardCode) > 4 or not cardCode.isdigit():
|
||||||
|
raise ValueError(f"Invalid CVV length {len(cardCode)} or non-numeric for card ID {card_obj.id}")
|
||||||
|
# Debug print
|
||||||
|
print(f"DEBUG SEND CREATE: cardNumber='{sanitized_card_number}', expirationDate='{expiration_date_str}', cardCode='{cardCode}', customerID={customer_obj.id}, name='{customer_obj.customer_first_name} {customer_obj.customer_last_name}', address='{customer_obj.customer_address}', city='{customer_obj.customer_town}', zip='{customer_obj.customer_zip}', email='{customer_obj.customer_email}'")
|
||||||
|
creditCard = apicontractsv1.creditCardType(
|
||||||
|
cardNumber=sanitized_card_number,
|
||||||
|
expirationDate=expiration_date_str,
|
||||||
|
cardCode=cardCode
|
||||||
|
)
|
||||||
|
billTo = apicontractsv1.customerAddressType(
|
||||||
|
firstName=customer_obj.customer_first_name,
|
||||||
|
lastName=customer_obj.customer_last_name,
|
||||||
|
address=customer_obj.customer_address,
|
||||||
|
city=customer_obj.customer_town,
|
||||||
|
zip=customer_obj.customer_zip
|
||||||
|
)
|
||||||
|
paymentProfile = apicontractsv1.customerPaymentProfileType(
|
||||||
|
billTo=billTo,
|
||||||
|
payment=apicontractsv1.paymentType(creditCard=creditCard)
|
||||||
|
)
|
||||||
|
customerProfile = apicontractsv1.customerProfileType(
|
||||||
|
merchantCustomerId=str(customer_obj.id),
|
||||||
|
email=customer_obj.customer_email,
|
||||||
|
paymentProfiles=[paymentProfile]
|
||||||
|
)
|
||||||
|
request = apicontractsv1.createCustomerProfileRequest(
|
||||||
|
merchantAuthentication=merchantAuth,
|
||||||
|
profile=customerProfile,
|
||||||
|
validationMode="testMode"
|
||||||
|
)
|
||||||
|
controller = createCustomerProfileController(request)
|
||||||
|
controller.execute()
|
||||||
|
response = controller.getresponse()
|
||||||
|
|
||||||
|
if response is not None and hasattr(response, 'messages') and response.messages.resultCode == "Ok":
|
||||||
|
profile_id = response.customerProfileId if hasattr(response, 'customerProfileId') else None
|
||||||
|
payment_ids = response.customerPaymentProfileIdList.numericString if hasattr(response, 'customerPaymentProfileIdList') and hasattr(response.customerPaymentProfileIdList, 'numericString') else []
|
||||||
|
payment_id = payment_ids[0] if payment_ids else None
|
||||||
|
return str(profile_id), str(payment_id) if payment_id else None
|
||||||
|
else:
|
||||||
|
# Handle errors
|
||||||
|
error_msg = "Unknown Authorize.Net Error"
|
||||||
|
if response is not None and hasattr(response, 'messages') and response.messages is not None and hasattr(response.messages, 'message') and response.messages.message:
|
||||||
|
msg = response.messages.message[0] if isinstance(response.messages.message, list) else response.messages.message
|
||||||
|
if msg and hasattr(msg, 'text') and msg.text is not None:
|
||||||
|
if isinstance(msg.text, str):
|
||||||
|
error_msg = msg.text
|
||||||
|
else:
|
||||||
|
# Handle case where text might be an object with 'text' attribute
|
||||||
|
error_msg = msg.text.text if hasattr(msg.text, 'text') else str(msg.text)
|
||||||
|
print(f" AUTH.NET ERROR: {error_msg}")
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
def _add_authnet_payment_profile(profile_id: str, customer_obj: Customer_Customer, card_obj: Card_Card):
|
||||||
|
"""Helper to add a new Payment Profile to an existing Customer Profile."""
|
||||||
|
merchantAuth = apicontractsv1.merchantAuthenticationType(name=API_LOGIN_ID, transactionKey=TRANSACTION_KEY)
|
||||||
|
expiration_date_str = f"{card_obj.expiration_year}-{str(card_obj.expiration_month).zfill(2)}"
|
||||||
|
|
||||||
|
# // FIX 1 (Applied here as well): Sanitize card number
|
||||||
|
sanitized_card_number = ''.join(filter(str.isdigit, str(card_obj.card_number)))
|
||||||
|
|
||||||
|
creditCard = apicontractsv1.creditCardType(
|
||||||
|
cardNumber=sanitized_card_number,
|
||||||
|
expirationDate=expiration_date_str,
|
||||||
|
cardCode=str(card_obj.security_number).strip()
|
||||||
|
)
|
||||||
|
paymentProfile = apicontractsv1.customerPaymentProfileType(
|
||||||
|
billTo=apicontractsv1.customerAddressType(firstName=customer_obj.customer_first_name, lastName=customer_obj.customer_last_name),
|
||||||
|
payment=apicontractsv1.paymentType(creditCard=creditCard)
|
||||||
|
)
|
||||||
|
request = apicontractsv1.createCustomerPaymentProfileRequest(
|
||||||
|
merchantAuthentication=merchantAuth,
|
||||||
|
customerProfileId=profile_id,
|
||||||
|
paymentProfile=paymentProfile,
|
||||||
|
validationMode="testMode"
|
||||||
|
)
|
||||||
|
controller = createCustomerPaymentProfileController(request)
|
||||||
|
controller.execute()
|
||||||
|
response = controller.getresponse()
|
||||||
|
if response is not None and response.messages.resultCode == "Ok":
|
||||||
|
return str(response.customerPaymentProfileId)
|
||||||
|
else:
|
||||||
|
# // FIX 2 (Applied here as well): Robust error message parsing
|
||||||
|
error_msg = "Unknown Authorize.Net Error"
|
||||||
|
if response is not None and hasattr(response, 'messages') and response.messages is not None and hasattr(response.messages, 'message') and response.messages.message:
|
||||||
|
msg = response.messages.message[0]
|
||||||
|
if hasattr(msg, 'text') and msg.text is not None:
|
||||||
|
error_msg = msg.text.text
|
||||||
|
print(f" AUTH.NET ERROR: {error_msg}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# --- MIGRATION SCRIPT LOGIC ---
|
||||||
|
print("="*60)
|
||||||
|
print("MIGRATION STARTED: Migrating all customer cards to Authorize.Net CIM.")
|
||||||
|
print(f"Start Time: {datetime.now()}")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
customers_processed = 0
|
||||||
|
cards_migrated = 0
|
||||||
|
error_count = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
customers_to_migrate = (session
|
||||||
|
.query(Customer_Customer)
|
||||||
|
.filter(Customer_Customer.auth_net_profile_id == None)
|
||||||
|
.order_by(func.random())
|
||||||
|
.limit(1)
|
||||||
|
.all())
|
||||||
|
|
||||||
|
total_customers = len(customers_to_migrate)
|
||||||
|
print(f"Found {total_customers} customers to migrate.")
|
||||||
|
|
||||||
|
for index, customer in enumerate(customers_to_migrate):
|
||||||
|
customers_processed += 1
|
||||||
|
print(f"\n--- Processing Customer {index + 1}/{total_customers} (ID: {customer.id}, Name: {customer.customer_first_name}) ---")
|
||||||
|
|
||||||
|
insecure_cards = (session
|
||||||
|
.query(Card_Card)
|
||||||
|
.filter(Card_Card.user_id == customer.id)
|
||||||
|
.all())
|
||||||
|
|
||||||
|
print(f"DEBUG: Customer {customer.id} has {len(insecure_cards)} cards")
|
||||||
|
customer_profile_id_for_session = None
|
||||||
|
|
||||||
|
# # Check for existing profile
|
||||||
|
# existing_profile, existing_payment_ids = _get_existing_profile(str(customer.id))
|
||||||
|
# if existing_profile and existing_payment_ids:
|
||||||
|
# print(f" -> Found existing Authorize.Net profile ID {existing_profile}")
|
||||||
|
# customer.auth_net_profile_id = existing_profile
|
||||||
|
# session.add(customer)
|
||||||
|
# session.commit()
|
||||||
|
# for i, card_data in enumerate(insecure_cards):
|
||||||
|
# if i < len(existing_payment_ids):
|
||||||
|
# display_card_number = ''.join(filter(str.isdigit, str(card_data.card_number)))
|
||||||
|
# if not display_card_number:
|
||||||
|
# print(f" SKIPPING CARD: Card number is empty after sanitization for card ID {card_data.id}")
|
||||||
|
# error_count += 1
|
||||||
|
# continue
|
||||||
|
# card_data.auth_net_payment_profile_id = existing_payment_ids[i]
|
||||||
|
# session.add(card_data)
|
||||||
|
# session.commit()
|
||||||
|
# print(f" SUCCESS: Mapped existing Payment ID {existing_payment_ids[i]} to card ending ...{display_card_number[-4:]}")
|
||||||
|
# cards_migrated += 1
|
||||||
|
# else:
|
||||||
|
# print(f" WARNING: No existing payment profile Kawasaki for card {card_data.id}")
|
||||||
|
# error_count += 1
|
||||||
|
# continue # skip creation loop
|
||||||
|
|
||||||
|
for i, card_data in enumerate(insecure_cards):
|
||||||
|
try:
|
||||||
|
# Basic data validation before sending
|
||||||
|
if not card_data.card_number or not card_data.expiration_year or not card_data.expiration_month:
|
||||||
|
print(f" SKIPPING CARD: Incomplete card data for card ID {card_data.id}.")
|
||||||
|
error_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"DEBUG RAW: Card ID {card_data.id}: number='{card_data.card_number}', year='{card_data.expiration_year}', month='{card_data.expiration_month}', cvv='{card_data.security_number}', name='{customer.customer_first_name} {customer.customer_last_name}'")
|
||||||
|
|
||||||
|
# Sanitize card number for display
|
||||||
|
display_card_number = ''.join(filter(str.isdigit, str(card_data.card_number)))
|
||||||
|
|
||||||
|
if not display_card_number:
|
||||||
|
print(f" SKIPPING CARD: Card number is empty after sanitization for card ID {card_data.id}.")
|
||||||
|
error_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if i == 0:
|
||||||
|
print(f" -> Creating new CIM profile with card ending in ...{display_card_number[-4:]}")
|
||||||
|
profile_id, payment_id = _create_authnet_profile(customer, card_data)
|
||||||
|
|
||||||
|
if profile_id and payment_id:
|
||||||
|
customer.auth_net_profile_id = profile_id
|
||||||
|
session.add(customer)
|
||||||
|
|
||||||
|
customer_profile_id_for_session = profile_id
|
||||||
|
|
||||||
|
card_data.auth_net_payment_profile_id = payment_id
|
||||||
|
session.add(card_data)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
print(f" SUCCESS: Created Profile ID {profile_id} and Payment ID {payment_id}")
|
||||||
|
cards_migrated += 1
|
||||||
|
else:
|
||||||
|
print(f" ERROR: Failed to create profile for customer {customer.id}.")
|
||||||
|
error_count += 1
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if not display_card_number:
|
||||||
|
print(f" SKIPPING CARD: Card number is empty after sanitization for card ID {card_data.id}.")
|
||||||
|
error_count += 1
|
||||||
|
continue
|
||||||
|
print(f" -> Adding additional card ending in ...{display_card_number[-4:]}")
|
||||||
|
payment_id = _add_authnet_payment_profile(customer_profile_id_for_session, customer, card_data)
|
||||||
|
if payment_id:
|
||||||
|
card_data.auth_net_payment_profile_id = payment_id
|
||||||
|
session.add(card_data)
|
||||||
|
session.commit()
|
||||||
|
print(f" SUCCESS: Added Payment ID {payment_id}")
|
||||||
|
cards_migrated += 1
|
||||||
|
else:
|
||||||
|
print(f" ERROR: Failed to add additional card for customer {customer.id}.")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" CRITICAL ERROR processing a card for customer {customer.id}: {str(e)}")
|
||||||
|
error_count += 1
|
||||||
|
session.rollback()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"A critical error occurred during the migration process: {e}")
|
||||||
|
session.rollback()
|
||||||
|
return {"ok": False, "error": f"Migration failed with a critical error: {e}"}, 500
|
||||||
|
|
||||||
|
finally:
|
||||||
|
print("="*60)
|
||||||
|
print("MIGRATION FINISHED!")
|
||||||
|
print(f"End Time: {datetime.now()}")
|
||||||
|
print(f"Summary: Processed {customers_processed} customers, migrated {cards_migrated} cards, encountered {error_count} errors.")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"message": "Migration process completed successfully.",
|
||||||
|
"customers_processed": customers_processed,
|
||||||
|
"cards_migrated": cards_migrated,
|
||||||
|
"errors": error_count,
|
||||||
|
}, 200
|
||||||
0
app/schema/customer.py
Normal file
0
app/schema/customer.py
Normal file
46
app/schema/delivery.py
Normal file
46
app/schema/delivery.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
|
||||||
|
def datetime_now() -> datetime:
|
||||||
|
return datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
class DeliverPricing(BaseModel):
|
||||||
|
prime: bool
|
||||||
|
same_day: bool
|
||||||
|
gallons_delivered: float
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SchemaDelivery(BaseModel):
|
||||||
|
customer_id: int
|
||||||
|
customer_name: str
|
||||||
|
customer_address: str
|
||||||
|
customer_town: str
|
||||||
|
customer_state: int
|
||||||
|
customer_zip: int
|
||||||
|
gallons_ordered: float
|
||||||
|
customer_asked_for_fill: int
|
||||||
|
gallons_delivered: float
|
||||||
|
customer_filled: int
|
||||||
|
delivery_status: int
|
||||||
|
when_ordered: datetime = Field(default_factory=datetime_now)
|
||||||
|
when_delivered: datetime = Field(default_factory=datetime_now)
|
||||||
|
expected_delivery_date: datetime = Field(default_factory=datetime_now)
|
||||||
|
automatic: int
|
||||||
|
oil_id: int
|
||||||
|
supplier_price: float
|
||||||
|
customer_price: float
|
||||||
|
customer_temperature: float
|
||||||
|
dispatcher_notes: str
|
||||||
|
prime: int
|
||||||
|
same_day: int
|
||||||
|
payment_type: int
|
||||||
|
payment_card_id: int
|
||||||
|
cash_recieved: float
|
||||||
|
driver_employee_id: int
|
||||||
|
driver_first_name: str
|
||||||
|
driver_last_name: str
|
||||||
|
pre_charge_amount: float
|
||||||
|
total_price: float
|
||||||
|
final_price: float
|
||||||
21
app/schema/money.py
Normal file
21
app/schema/money.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
|
||||||
|
def datetime_now() -> datetime:
|
||||||
|
return datetime.now(timezone.utc)
|
||||||
|
|
||||||
|
class SchemaMoney(BaseModel):
|
||||||
|
delivery_id: int
|
||||||
|
time_added: datetime
|
||||||
|
gallons_delivered: float
|
||||||
|
supplier_price: float
|
||||||
|
customer_price: float
|
||||||
|
total_amount_oil: float
|
||||||
|
total_amount_prime: float
|
||||||
|
total_amount_same_day: float
|
||||||
|
total_amount_fee: float
|
||||||
|
total_amount: float
|
||||||
|
taxes_paid: float
|
||||||
|
total_profit: float
|
||||||
|
|
||||||
26
app/script/update_auto.py
Normal file
26
app/script/update_auto.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from decimal import Decimal
|
||||||
|
from database import session
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def calc_home_factor(gallons_put_in_home, current_house_factor):
|
||||||
|
|
||||||
|
|
||||||
|
if 200.01 <= gallons_put_in_home <= 500:
|
||||||
|
customer_home_factor = Decimal(current_house_factor) + Decimal(1)
|
||||||
|
elif 170.01 <= gallons_put_in_home <= 200:
|
||||||
|
customer_home_factor = Decimal(current_house_factor) + Decimal(1.5)
|
||||||
|
elif 150.01 <= gallons_put_in_home <= 170:
|
||||||
|
customer_home_factor = Decimal(current_house_factor) + Decimal(1.25)
|
||||||
|
elif 120.01 <= gallons_put_in_home <= 150:
|
||||||
|
customer_home_factor = Decimal(current_house_factor) - Decimal(.25)
|
||||||
|
elif 90.01 <= gallons_put_in_home <= 120:
|
||||||
|
customer_home_factor = Decimal(current_house_factor) - Decimal(.50)
|
||||||
|
elif 0.01 <= gallons_put_in_home <= 90:
|
||||||
|
customer_home_factor = Decimal(current_house_factor) - Decimal(.75)
|
||||||
|
else:
|
||||||
|
customer_home_factor = Decimal(current_house_factor)
|
||||||
|
if customer_home_factor <= 0:
|
||||||
|
customer_home_factor = Decimal(.25)
|
||||||
|
return customer_home_factor
|
||||||
22
config.py
Normal file
22
config.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import os
|
||||||
|
def load_config(mode=os.environ.get('MODE')):
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"mode is {mode}")
|
||||||
|
if mode == 'PRODUCTION':
|
||||||
|
from settings_prod import ApplicationConfig
|
||||||
|
return ApplicationConfig
|
||||||
|
|
||||||
|
elif mode == 'LOCAL':
|
||||||
|
from settings_local import ApplicationConfig
|
||||||
|
return ApplicationConfig
|
||||||
|
|
||||||
|
elif mode == 'DEVELOPMENT':
|
||||||
|
from settings_dev import ApplicationConfig
|
||||||
|
return ApplicationConfig
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
from settings_local import ApplicationConfig
|
||||||
|
return ApplicationConfig
|
||||||
28
database.py
Normal file
28
database.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.engine import URL
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
from sqlalchemy.orm import declarative_base
|
||||||
|
|
||||||
|
|
||||||
|
from config import load_config
|
||||||
|
|
||||||
|
|
||||||
|
ApplicationConfig = load_config()
|
||||||
|
|
||||||
|
|
||||||
|
url = URL.create(
|
||||||
|
drivername="postgresql",
|
||||||
|
username=ApplicationConfig.POSTGRES_USERNAME,
|
||||||
|
password=ApplicationConfig.POSTGRES_PW,
|
||||||
|
host=ApplicationConfig.POSTGRES_SERVER,
|
||||||
|
database=ApplicationConfig.POSTGRES_DBNAME00,
|
||||||
|
port=ApplicationConfig.POSTGRES_PORT
|
||||||
|
)
|
||||||
|
|
||||||
|
engine = create_engine(url)
|
||||||
|
|
||||||
|
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
41
main.py
Normal file
41
main.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
from app.routers import main, delivery, confirm
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
|
app.include_router(main.router)
|
||||||
|
app.include_router(delivery.router)
|
||||||
|
app.include_router(confirm.router)
|
||||||
|
|
||||||
|
origins = [
|
||||||
|
"http://localhost:9000",
|
||||||
|
"https://localhost:9513",
|
||||||
|
"http://localhost:9514",
|
||||||
|
"http://localhost:9512",
|
||||||
|
"http://localhost:9511",
|
||||||
|
"http://192.168.1.204:9000",
|
||||||
|
"http://192.168.1.204:9513",
|
||||||
|
"http://192.168.1.204:9514",
|
||||||
|
"http://192.168.1.204:9512",
|
||||||
|
"http://192.168.1.204:9511",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=origins,
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def read_root():
|
||||||
|
return {"Status": "Playground is online"}
|
||||||
|
|
||||||
7
requirements.txt
Normal file
7
requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
fastapi
|
||||||
|
uvicorn[standard]
|
||||||
|
psycopg2-binary
|
||||||
|
sqlalchemy
|
||||||
|
pyowm
|
||||||
|
setuptools
|
||||||
|
authorizenet
|
||||||
20
settings_dev.py
Normal file
20
settings_dev.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class ApplicationConfig:
|
||||||
|
"""
|
||||||
|
Basic Configuration for a generic User
|
||||||
|
"""
|
||||||
|
CURRENT_SETTINGS = 'LOCAL'
|
||||||
|
# databases info
|
||||||
|
POSTGRES_USERNAME = 'postgres'
|
||||||
|
POSTGRES_PW = 'password'
|
||||||
|
POSTGRES_SERVER = '192.168.1.204'
|
||||||
|
POSTGRES_PORT = '5432'
|
||||||
|
POSTGRES_DBNAME00 = 'eamco'
|
||||||
|
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
|
||||||
|
POSTGRES_PW,
|
||||||
|
POSTGRES_SERVER,
|
||||||
|
POSTGRES_DBNAME00
|
||||||
|
)
|
||||||
|
|
||||||
|
SQLALCHEMY_BINDS = {'eamco': SQLALCHEMY_DATABASE_URI}
|
||||||
20
settings_local.py
Normal file
20
settings_local.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class ApplicationConfig:
|
||||||
|
"""
|
||||||
|
Basic Configuration for a generic User
|
||||||
|
"""
|
||||||
|
CURRENT_SETTINGS = 'LOCAL'
|
||||||
|
# databases info
|
||||||
|
POSTGRES_USERNAME = 'postgres'
|
||||||
|
POSTGRES_PW = 'password'
|
||||||
|
POSTGRES_SERVER = '192.168.1.204'
|
||||||
|
POSTGRES_PORT = '5432'
|
||||||
|
POSTGRES_DBNAME00 = 'eamco'
|
||||||
|
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
|
||||||
|
POSTGRES_PW,
|
||||||
|
POSTGRES_SERVER,
|
||||||
|
POSTGRES_DBNAME00
|
||||||
|
)
|
||||||
|
|
||||||
|
SQLALCHEMY_BINDS = {'eamco': SQLALCHEMY_DATABASE_URI}
|
||||||
17
settings_prod.py
Normal file
17
settings_prod.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
class ApplicationConfig:
|
||||||
|
"""
|
||||||
|
Basic Configuration for a generic User
|
||||||
|
"""
|
||||||
|
CURRENT_SETTINGS = 'LOCAL'
|
||||||
|
# databases info
|
||||||
|
POSTGRES_USERNAME = 'postgres'
|
||||||
|
POSTGRES_PW = 'password'
|
||||||
|
POSTGRES_SERVER = '192.168.1.204'
|
||||||
|
POSTGRES_PORT = '5432'
|
||||||
|
POSTGRES_DBNAME00 = 'auburnoil'
|
||||||
|
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://{}:{}@{}/{}".format(POSTGRES_USERNAME,
|
||||||
|
POSTGRES_PW,
|
||||||
|
POSTGRES_SERVER,
|
||||||
|
POSTGRES_DBNAME00
|
||||||
|
)
|
||||||
|
SQLALCHEMY_BINDS = {'auburnoil': SQLALCHEMY_DATABASE_URI}
|
||||||
Reference in New Issue
Block a user