This commit is contained in:
Андрей Дувакин 2024-10-05 20:15:47 +05:00
parent c8338ba142
commit bd5aa7fcc6
3 changed files with 70 additions and 8 deletions

View File

@ -1,6 +1,8 @@
from itertools import permutations from itertools import permutations
from math import ceil from math import ceil
from pprint import pprint
import requests
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.infrastructure.database.repository.accessory_repository import AccessoriesRepository from app.infrastructure.database.repository.accessory_repository import AccessoriesRepository
@ -8,6 +10,7 @@ from app.infrastructure.database.repository.city_repository import CityRepositor
from app.infrastructure.database.repository.delivery_accessory_repository import DeliveryAccessoriesRepository from app.infrastructure.database.repository.delivery_accessory_repository import DeliveryAccessoriesRepository
from app.infrastructure.database.repository.delivery_order_repository import DeliveryOrdersRepository from app.infrastructure.database.repository.delivery_order_repository import DeliveryOrdersRepository
from app.infrastructure.database.repository.total_order_repository import TotalOrdersRepository from app.infrastructure.database.repository.total_order_repository import TotalOrdersRepository
from app.infrastructure.database.repository.truck_repository import TrucksRepository
class NewTotalOrderService: class NewTotalOrderService:
@ -17,38 +20,57 @@ class NewTotalOrderService:
self.delivery_accessory_repository = DeliveryAccessoriesRepository(db) self.delivery_accessory_repository = DeliveryAccessoriesRepository(db)
self.city_repository = CityRepository(db) self.city_repository = CityRepository(db)
self.accessory_repository = AccessoriesRepository(db) self.accessory_repository = AccessoriesRepository(db)
self.truck_repository = TrucksRepository(db)
def total_calculate(self): def total_calculate(self):
print(111111111111111111111111111111111111111)
accessories = self.accessory_repository.get_with_cities_all()
cities = self.city_repository.get_all_with_federal_district()
tracks = self.truck_repository.get_all()
distances = self.create_distance_matrix(cities)
for i in distances:
for j in i:
print(j)
print()
grouped_by_period = self.group_accessories_by_period(accessories) grouped_by_period = self.group_accessories_by_period(accessories)
routes_by_period = self.find_routes_by_period(grouped_by_period, distances, cities) routes_by_period = self.find_routes_by_period(grouped_by_period, distances, cities)
response = ''
for period, routes in routes_by_period.items(): for period, routes in routes_by_period.items():
for route in routes: for route in routes:
vehicle_count, selected_track = self.calculate_vehicle_requirements( vehicle_count, selected_track = self.calculate_vehicle_requirements(
[a for a in accessories if a.period == period], tracks) [a for a in accessories if a.period == period], tracks)
cost = self.calculate_route_cost(route, accessories, distances) cost = self.calculate_route_cost(route, accessories, distances)
print(f"Период: {period}") response += f"Период: {period}\n"
print(f"Маршрут: {' -> '.join([city.name for city in route])}") response += f"Маршрут: {' -> '.join([city.name for city in route])}\n"
selected_vehicle_name = next((track.name for track in tracks if track.id == selected_track), selected_vehicle_name = next((track.name for track in tracks if track.id == selected_track),
"Нет доступного автомобиля") "Нет доступного автомобиля")
print(f"Тип автомобиля: {selected_vehicle_name}") response += f"Тип автомобиля: {selected_vehicle_name}"
print(f"Количество автомобилей: {vehicle_count}") response += f"Количество автомобилей: {vehicle_count}"
print(f"Стоимость перевозки: {cost}\n") response += f"Стоимость перевозки: {cost}\n"
def find_routes_by_period(self, grouped_by_period, distances, cities): def find_routes_by_period(self, grouped_by_period, distances, cities):
purpose_city_id = self.city_repository.get_by_name('Челябинск').id
routes_by_period = {} routes_by_period = {}
for period, accessories in grouped_by_period.items(): for period, accessories in grouped_by_period.items():
cities_in_period = [next(city for city in cities if city.id == accessory.cityId) for accessory in cities_in_period = [next(city for city in cities if city.id == accessory.city_id) for accessory in
accessories] accessories]
all_routes = self.generate_routes(cities_in_period, next(city for city in cities if city.id == 9)) all_routes = self.generate_routes(cities_in_period,
next(city for city in cities if city.id == purpose_city_id))
routes_with_details = [] routes_with_details = []
for route in all_routes: for route in all_routes:
distance = self.calculate_route_distance(route, distances) distance = self.calculate_route_distance(route, distances)
total_weight = sum( total_weight = sum(
sum(accessory.weight for accessory in accessories if accessory.cityId == city.id) for city in route) sum(accessory.weight for accessory in accessories if accessory.city_id == city.id) for city in
route)
cost = self.calculate_route_cost(route, accessories, distances) cost = self.calculate_route_cost(route, accessories, distances)
routes_with_details.append((route, (distance, total_weight, cost))) routes_with_details.append((route, (distance, total_weight, cost)))
@ -57,6 +79,21 @@ class NewTotalOrderService:
return routes_by_period return routes_by_period
def create_distance_matrix(self, cities):
num_cities = len(cities)
distances = [[0] * num_cities for _ in range(num_cities)]
for i in range(num_cities):
for j in range(num_cities):
if i != j:
start_coords = (cities[i].x_coordinate, cities[i].y_coordinate)
end_coords = (cities[j].x_coordinate, cities[j].y_coordinate)
distances[i][j] = self.get_distance(start_coords, end_coords)
else:
distances[i][j] = 0
return distances
@staticmethod @staticmethod
def group_accessories_by_period(accessories): def group_accessories_by_period(accessories):
grouped = {} grouped = {}
@ -80,6 +117,7 @@ class NewTotalOrderService:
@staticmethod @staticmethod
def calculate_route_distance(route, distances): def calculate_route_distance(route, distances):
total_distance = 0 total_distance = 0
pprint(distances)
for i in range(len(route) - 1): for i in range(len(route) - 1):
total_distance += distances[route[i].id - 1][route[i + 1].id - 1] total_distance += distances[route[i].id - 1][route[i + 1].id - 1]
return total_distance return total_distance
@ -110,3 +148,17 @@ class NewTotalOrderService:
selected_track = track.id selected_track = track.id
return total_vehicles, selected_track return total_vehicles, selected_track
@staticmethod
def get_distance(start_coords, end_coords):
base_url = "http://router.project-osrm.org/route/v1/driving"
url = f"{base_url}/{start_coords[1]},{start_coords[0]};{end_coords[1]},{end_coords[0]}?overview=full"
response = requests.get(url)
data = response.json()
if data['routes']:
distance = data['routes'][0]['distance'] / 1000
return distance
else:
return float('inf')

View File

@ -9,6 +9,9 @@ class CityRepository:
def get_all(self): def get_all(self):
return self.db.query(City).all() return self.db.query(City).all()
def get_by_name(self, city_name):
return self.db.query(City).filter(City.name == city_name).first()
def get_all_with_federal_district(self): def get_all_with_federal_district(self):
return self.db.query(City) \ return self.db.query(City) \
.options(joinedload(City.federal_district)) \ .options(joinedload(City.federal_district)) \

View File

@ -4,6 +4,7 @@ from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.core.usecases.auth_service import verify_token from app.core.usecases.auth_service import verify_token
from app.core.usecases.new_total_order_service import NewTotalOrderService
from app.infrastructure.database.dependencies import get_db from app.infrastructure.database.dependencies import get_db
from app.core.entities.total_order import TotalOrderEntity from app.core.entities.total_order import TotalOrderEntity
from app.core.usecases.total_order_service import TotalOrdersService from app.core.usecases.total_order_service import TotalOrdersService
@ -54,3 +55,9 @@ def delete_total_order(total_order_id: int, db: Session = Depends(get_db),
if not success: if not success:
raise HTTPException(status_code=404, detail="Total order not found") raise HTTPException(status_code=404, detail="Total order not found")
return success return success
@router.post("/total-orders/calculate", response_model=TotalOrderEntity)
def calculate_total_order(db: Session = Depends(get_db)):
service = NewTotalOrderService(db)
return service.total_calculate()