Major update spanning pricing, market data, and analytics: - Pricing: Replace single-price service fees with 5-tier pricing for same-day, prime, and emergency deliveries across create/edit/finalize - Market: Add Ticker_Price and CompanyPrice models with endpoints for live commodity prices (HO, CL, RB) and competitor price tracking - Stats: Add daily/weekly/monthly gallons endpoints with multi-year comparison and YoY totals for the stats dashboard - Delivery: Add map and history endpoints, fix finalize null-driver crash - Schema: Change fill_location from INTEGER to VARCHAR(250), add pre_load normalization for customer updates, fix admin auth check Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
132 lines
5.1 KiB
Python
Executable File
132 lines
5.1 KiB
Python
Executable File
import logging
|
|
from flask import request
|
|
from flask_login import current_user, logout_user, login_user, login_required
|
|
from app.admin import admin
|
|
from app import db
|
|
from app.common.responses import error_response, success_response
|
|
from datetime import datetime
|
|
from app.classes.pricing import (
|
|
Pricing_Oil_Oil,
|
|
Pricing_Oil_Oil_schema)
|
|
from app.classes.admin import Admin_Company, Admin_Company_schema, Call
|
|
from app.common.decorators import admin_required
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
@admin.route("/oil/create", methods=["POST"])
|
|
@admin_required
|
|
def create_oil_price():
|
|
"""
|
|
Changes the price for oil deliveries
|
|
"""
|
|
logger.info("POST /admin/oil/create - Creating new oil price")
|
|
now = datetime.utcnow()
|
|
price_from_supplier = request.json["price_from_supplier"]
|
|
price_for_customer = request.json["price_for_customer"]
|
|
price_for_employee = request.json["price_for_employee"]
|
|
|
|
# Legacy single-tier pricing (for backward compatibility, use tier1 values)
|
|
price_same_day_tier1 = request.json.get("price_same_day_tier1", 0)
|
|
price_prime_tier1 = request.json.get("price_prime_tier1", 0)
|
|
price_emergency_tier1 = request.json.get("price_emergency_tier1", 0)
|
|
|
|
# Get all tier pricing
|
|
price_same_day_tier2 = request.json.get("price_same_day_tier2", 0)
|
|
price_same_day_tier3 = request.json.get("price_same_day_tier3", 0)
|
|
price_same_day_tier4 = request.json.get("price_same_day_tier4", 0)
|
|
price_same_day_tier5 = request.json.get("price_same_day_tier5", 0)
|
|
|
|
price_prime_tier2 = request.json.get("price_prime_tier2", 0)
|
|
price_prime_tier3 = request.json.get("price_prime_tier3", 0)
|
|
price_prime_tier4 = request.json.get("price_prime_tier4", 0)
|
|
price_prime_tier5 = request.json.get("price_prime_tier5", 0)
|
|
|
|
price_emergency_tier2 = request.json.get("price_emergency_tier2", 0)
|
|
price_emergency_tier3 = request.json.get("price_emergency_tier3", 0)
|
|
price_emergency_tier4 = request.json.get("price_emergency_tier4", 0)
|
|
price_emergency_tier5 = request.json.get("price_emergency_tier5", 0)
|
|
|
|
new_admin_oil_price = Pricing_Oil_Oil(
|
|
price_from_supplier=price_from_supplier,
|
|
price_for_customer=price_for_customer,
|
|
price_for_employee=price_for_employee,
|
|
# Legacy columns (use tier1 for backward compatibility)
|
|
price_same_day=price_same_day_tier1,
|
|
price_prime=price_prime_tier1,
|
|
price_emergency=price_emergency_tier1,
|
|
# Tier pricing
|
|
price_same_day_tier1=price_same_day_tier1,
|
|
price_same_day_tier2=price_same_day_tier2,
|
|
price_same_day_tier3=price_same_day_tier3,
|
|
price_same_day_tier4=price_same_day_tier4,
|
|
price_same_day_tier5=price_same_day_tier5,
|
|
price_prime_tier1=price_prime_tier1,
|
|
price_prime_tier2=price_prime_tier2,
|
|
price_prime_tier3=price_prime_tier3,
|
|
price_prime_tier4=price_prime_tier4,
|
|
price_prime_tier5=price_prime_tier5,
|
|
price_emergency_tier1=price_emergency_tier1,
|
|
price_emergency_tier2=price_emergency_tier2,
|
|
price_emergency_tier3=price_emergency_tier3,
|
|
price_emergency_tier4=price_emergency_tier4,
|
|
price_emergency_tier5=price_emergency_tier5,
|
|
date=now,
|
|
)
|
|
# new_admin_oil_price = Pricing_Oil_Oil(
|
|
# price_from_supplier=price_from_supplier,
|
|
# price_for_customer=price_for_customer,
|
|
# price_for_employee=price_for_employee,
|
|
# price_same_day=price_same_day,
|
|
# price_prime=price_prime,
|
|
# date=now,
|
|
# )
|
|
|
|
db.session.add(new_admin_oil_price)
|
|
db.session.commit()
|
|
|
|
return success_response({'price': new_admin_oil_price.id})
|
|
|
|
|
|
|
|
@admin.route("/oil/get", methods=["GET"])
|
|
@admin_required
|
|
def get_oil_price():
|
|
"""
|
|
gets oil prices
|
|
"""
|
|
logger.info("GET /admin/oil/get - Fetching current oil prices")
|
|
get_oil_prices = (db.session
|
|
.query(Pricing_Oil_Oil)
|
|
.order_by(Pricing_Oil_Oil.date.desc())
|
|
.first())
|
|
price_schema = Pricing_Oil_Oil_schema(many=False)
|
|
return success_response({"price": price_schema.dump(get_oil_prices)})
|
|
|
|
|
|
@admin.route("/company/<int:company_id>", methods=["GET"])
|
|
@admin_required
|
|
def get_company(company_id):
|
|
logger.info(f"GET /admin/company/{company_id} - Fetching company data")
|
|
get_data_company = (db.session
|
|
.query(Admin_Company)
|
|
.first())
|
|
|
|
company_schema = Admin_Company_schema(many=False)
|
|
return success_response({"company": company_schema.dump(get_data_company)})
|
|
|
|
@admin.route("/voip_routing", methods=["GET"])
|
|
@admin_required
|
|
def get_voip_routing():
|
|
"""
|
|
Gets the current VOIP routing (latest Call record's current_phone)
|
|
"""
|
|
logger.info("GET /admin/voip_routing - Fetching current VoIP routing")
|
|
latest_call = (db.session
|
|
.query(Call)
|
|
.order_by(Call.created_at.desc())
|
|
.first())
|
|
if latest_call:
|
|
return success_response({"current_phone": latest_call.current_phone})
|
|
else:
|
|
return error_response("No VoIP routing found", 404)
|