first commit
This commit is contained in:
12
app/api/v1/deal/__init__.py
Normal file
12
app/api/v1/deal/__init__.py
Normal file
@ -0,0 +1,12 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.v1.deal import deal, summaries, employee, services, product, products
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(deal.router)
|
||||
router.include_router(summaries.router, prefix='/summaries')
|
||||
router.include_router(employee.router, prefix='/employee')
|
||||
router.include_router(services.router, prefix='/services')
|
||||
router.include_router(product.router, prefix='/product')
|
||||
router.include_router(products.router, prefix='/products')
|
||||
BIN
app/api/v1/deal/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
app/api/v1/deal/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/api/v1/deal/__pycache__/deal.cpython-311.pyc
Normal file
BIN
app/api/v1/deal/__pycache__/deal.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/api/v1/deal/__pycache__/employee.cpython-311.pyc
Normal file
BIN
app/api/v1/deal/__pycache__/employee.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/api/v1/deal/__pycache__/product.cpython-311.pyc
Normal file
BIN
app/api/v1/deal/__pycache__/product.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/api/v1/deal/__pycache__/products.cpython-311.pyc
Normal file
BIN
app/api/v1/deal/__pycache__/products.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/api/v1/deal/__pycache__/services.cpython-311.pyc
Normal file
BIN
app/api/v1/deal/__pycache__/services.cpython-311.pyc
Normal file
Binary file not shown.
BIN
app/api/v1/deal/__pycache__/summaries.cpython-311.pyc
Normal file
BIN
app/api/v1/deal/__pycache__/summaries.cpython-311.pyc
Normal file
Binary file not shown.
422
app/api/v1/deal/deal.py
Normal file
422
app/api/v1/deal/deal.py
Normal file
@ -0,0 +1,422 @@
|
||||
import base64
|
||||
from datetime import datetime
|
||||
from io import BytesIO
|
||||
from time import time
|
||||
|
||||
import barcode
|
||||
from barcode.writer import ImageWriter
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import Response
|
||||
from num2words import num2words
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.pagesizes import A4
|
||||
from reportlab.lib.styles import ParagraphStyle
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.ttfonts import TTFont
|
||||
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, Image
|
||||
from starlette.requests import Request
|
||||
from starlette.templating import Jinja2Templates
|
||||
|
||||
from app import mongo
|
||||
from app.utils.response_util import response
|
||||
|
||||
router = APIRouter()
|
||||
templates = Jinja2Templates(directory="assets/templates")
|
||||
|
||||
MONTHS_RU = {
|
||||
1: "января",
|
||||
2: "февраля",
|
||||
3: "марта",
|
||||
4: "апреля",
|
||||
5: "мая",
|
||||
6: "июня",
|
||||
7: "июля",
|
||||
8: "августа",
|
||||
9: "сентября",
|
||||
10: "октября",
|
||||
11: "ноября",
|
||||
12: "декабря",
|
||||
}
|
||||
|
||||
|
||||
def format_date_russian(date: datetime) -> str:
|
||||
return f"{date.day} {MONTHS_RU[date.month]} {date.year} г."
|
||||
|
||||
|
||||
@router.post("/quickCreate", tags=[""])
|
||||
async def quick_create_deal(data: dict):
|
||||
start_time = time()
|
||||
|
||||
data["id"] = await mongo.get_next_id(mongo.deals_collection)
|
||||
data["createdAt"] = mongo.created_at()
|
||||
|
||||
status = await mongo.statuses_collection.find_one({"id": data["statusId"]}, {"_id": False})
|
||||
if not status:
|
||||
return response({"message": "Статус не найден", "ok": False}, start_time=start_time)
|
||||
|
||||
board = await mongo.boards_collection.find_one({"id": status["boardId"]}, {"_id": False})
|
||||
if not board:
|
||||
return response({"message": "Доска не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
data["boardId"] = status["boardId"]
|
||||
data["projectId"] = board["projectId"]
|
||||
|
||||
await mongo.deals_collection.insert_one(data)
|
||||
return response({
|
||||
"message": "Сделка создана",
|
||||
"ok": True,
|
||||
"dealId": data["id"]
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.get("/get/{deal_id}", tags=[""])
|
||||
async def get_deal(deal_id: int):
|
||||
start_time = time()
|
||||
|
||||
deal = await mongo.deals_collection.find_one({
|
||||
"id": deal_id
|
||||
}, {
|
||||
"_id": False
|
||||
})
|
||||
|
||||
deals = await mongo.additional_deals_data(deal, full=True)
|
||||
return response(deals[0], start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/update-general-info", tags=[""])
|
||||
async def update_deal_general_info(params: dict, request: Request):
|
||||
start_time = time()
|
||||
data = params["data"]
|
||||
deal_id = params["dealId"]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id}, {"_id": False})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
new_status = await mongo.statuses_collection.find_one({"id": data["statusId"]}, {"_id": False})
|
||||
if new_status and new_status["name"] == "Завершено":
|
||||
data["completedAt"] = mongo.created_at()
|
||||
|
||||
old_status_id = deal.get("statusId")
|
||||
await mongo.deals_collection.update_one({
|
||||
"id": deal_id
|
||||
}, {
|
||||
"$set": data
|
||||
})
|
||||
|
||||
if old_status_id != data["statusId"]:
|
||||
new_entry = {
|
||||
"changedAt": mongo.created_at(),
|
||||
"fromStatusId": old_status_id,
|
||||
"toStatusId": data["statusId"],
|
||||
"userId": request.state.user["id"],
|
||||
"comment": ""
|
||||
}
|
||||
|
||||
await mongo.deals_collection.update_one(
|
||||
{"id": deal_id},
|
||||
{"$push": {"statusHistory": new_entry}}
|
||||
)
|
||||
|
||||
return response({
|
||||
"message": "Данные сделки обновлены",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/delete", tags=[""])
|
||||
async def delete_deal(params: dict):
|
||||
start_time = time()
|
||||
deal_id = params["dealId"]
|
||||
|
||||
await mongo.deals_collection.delete_one({"id": deal_id})
|
||||
return response({
|
||||
"message": "Сделка удалена",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/complete", tags=[""])
|
||||
async def complete_deal(params: dict):
|
||||
start_time = time()
|
||||
deal_id = params["dealId"]
|
||||
|
||||
await mongo.deals_collection.update_one(
|
||||
{"id": deal_id},
|
||||
{"$set": {"isCompleted": True}}
|
||||
)
|
||||
|
||||
return response({
|
||||
"message": "Сделка завершена",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/prefill", tags=[""])
|
||||
async def prefill_deal(params: dict):
|
||||
start_time = time()
|
||||
old_deal_id = params["oldDealId"]
|
||||
new_deal_id = params["newDealId"]
|
||||
|
||||
old_deal = await mongo.deals_collection.find_one({"id": old_deal_id}, {"_id": False})
|
||||
if not old_deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
await mongo.deals_collection.update_one(
|
||||
{"id": new_deal_id},
|
||||
{"$set": {
|
||||
"name": old_deal["name"],
|
||||
"clientName": old_deal["clientName"],
|
||||
"services": old_deal.get("services", []),
|
||||
"products": old_deal.get("products", [])
|
||||
}}
|
||||
)
|
||||
|
||||
return response({
|
||||
"message": "Сделка предзаполнена",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.get("/billing-document/{deal_id}", tags=[""])
|
||||
async def deal_billing_document(deal_id: int):
|
||||
pdfmetrics.registerFont(TTFont("Arial", "assets/arial.ttf"))
|
||||
pdfmetrics.registerFont(TTFont("Arial Bold", "assets/arial_bold.ttf"))
|
||||
|
||||
center = ParagraphStyle(name="center", fontName="Arial", fontSize=10, alignment=1)
|
||||
bold_center = ParagraphStyle(name="bold_center", fontName="Arial Bold", fontSize=10, alignment=1)
|
||||
title = ParagraphStyle(name="title", fontName="Arial Bold", fontSize=14, alignment=1)
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id}, {"_id": False})
|
||||
buffer = BytesIO()
|
||||
doc = SimpleDocTemplate(buffer, pagesize=A4, leftMargin=20, rightMargin=20, topMargin=30, bottomMargin=20)
|
||||
elements = []
|
||||
|
||||
logo = Image("assets/logo.jpg", width=152, height=56)
|
||||
logo.hAlign = "LEFT"
|
||||
elements.append(logo)
|
||||
elements.append(Spacer(1, 10))
|
||||
|
||||
elements.append(Paragraph("Расчет стоимости услуг", title))
|
||||
elements.append(Spacer(1, 6))
|
||||
elements.append(Paragraph(f"№ {deal['id']} от {format_date_russian(datetime.now())}", center))
|
||||
elements.append(Paragraph("Адрес: 115516, г.Москва, ул. Промышленная 11", center))
|
||||
elements.append(Paragraph(f"Клиент: {deal.get('clientName', 'Не указан')}", center))
|
||||
elements.append(Paragraph(f"Маркетплейс: {deal.get('baseMarketplace', {}).get('name', 'Не указан')}", center))
|
||||
elements.append(Paragraph(f"Склад отгрузки: {deal.get('shippingWarehouse', 'Не указан')}", center))
|
||||
elements.append(Spacer(1, 10))
|
||||
|
||||
total_sum = 0
|
||||
product_infos = []
|
||||
table_width = 450
|
||||
|
||||
data_1 = [[
|
||||
Paragraph("Артикул ВБ", bold_center),
|
||||
Paragraph("Артикул продавца", bold_center),
|
||||
Paragraph("Размер", bold_center),
|
||||
Paragraph("Кол-во", bold_center),
|
||||
Paragraph("Цена", bold_center),
|
||||
Paragraph("Сумма", bold_center),
|
||||
]]
|
||||
|
||||
for product in deal.get("products", []):
|
||||
product_data = await mongo.products_collection.find_one({"id": product["productId"]}, {"_id": False})
|
||||
if not product_data:
|
||||
continue
|
||||
|
||||
article = product_data.get("article", "-")
|
||||
vendor_code = product_data.get("vendorCode", "-")
|
||||
size = product_data.get("size", "-")
|
||||
quantity = product["quantity"]
|
||||
price = sum(service["price"] * service.get("quantity", 1) for service in product["services"])
|
||||
amount = quantity * price
|
||||
total_sum += amount
|
||||
|
||||
data_1.append([
|
||||
Paragraph(str(article), center),
|
||||
Paragraph(str(vendor_code), center),
|
||||
Paragraph(str(size or 0), center),
|
||||
Paragraph(str(quantity or 1), center),
|
||||
Paragraph(f"{price} ₽", center),
|
||||
Paragraph(f"{amount} ₽", center),
|
||||
])
|
||||
|
||||
product_infos.append({
|
||||
"name": product_data.get("name") or "Без названия",
|
||||
"quantity": product["quantity"],
|
||||
"services": await get_services(product.get("services", []))
|
||||
})
|
||||
|
||||
table_1 = Table(data_1, colWidths=[table_width / 6] * 5)
|
||||
table_1.setStyle(TableStyle([
|
||||
("BOX", (0, 0), (-1, -1), 0.8, colors.black),
|
||||
("INNERGRID", (0, 0), (-1, -1), 0.4, colors.grey),
|
||||
("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
|
||||
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
||||
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
||||
("ROUNDEDCORNERS", (16, 16, 16, 16)),
|
||||
]))
|
||||
|
||||
elements.append(Paragraph("Товары", bold_center))
|
||||
elements.append(Spacer(1, 4))
|
||||
elements.append(table_1)
|
||||
elements.append(Spacer(1, 12))
|
||||
|
||||
data_2 = [[
|
||||
Paragraph("Товар / Услуга", bold_center),
|
||||
Paragraph("Кол-во", bold_center),
|
||||
Paragraph("Цена", bold_center),
|
||||
Paragraph("Сумма", bold_center),
|
||||
]]
|
||||
|
||||
for product in product_infos:
|
||||
for service in product["services"]:
|
||||
quantity = product.get("quantity", 0)
|
||||
price = service.get("price", 0)
|
||||
amount = quantity * price
|
||||
data_2.append([
|
||||
Paragraph(f"{product['name']} {service['name']}", center),
|
||||
Paragraph(str(quantity), center),
|
||||
Paragraph(f"{price} ₽", center),
|
||||
Paragraph(f"{amount} ₽", center),
|
||||
])
|
||||
|
||||
for service in await get_services(deal.get("services", [])):
|
||||
quantity = service.get("quantity", 0)
|
||||
price = service.get("price", 0)
|
||||
amount = quantity * price
|
||||
total_sum += amount
|
||||
data_2.append([
|
||||
Paragraph(service['name'], center),
|
||||
Paragraph(str(quantity), center),
|
||||
Paragraph(f"{price} ₽", center),
|
||||
Paragraph(f"{amount} ₽", center)
|
||||
])
|
||||
|
||||
table_2 = Table(data_2, colWidths=[
|
||||
table_width * 0.4, table_width * 0.2, table_width * 0.2, table_width * 0.2
|
||||
])
|
||||
|
||||
table_2.setStyle(TableStyle([
|
||||
("BOX", (0, 0), (-1, -1), 0.8, colors.black),
|
||||
("INNERGRID", (0, 0), (-1, -1), 0.4, colors.grey),
|
||||
("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
|
||||
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
||||
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
||||
("ROUNDEDCORNERS", (16, 16, 16, 16)),
|
||||
]))
|
||||
|
||||
elements.append(Paragraph("Услуги", bold_center))
|
||||
elements.append(Spacer(1, 4))
|
||||
elements.append(table_2)
|
||||
elements.append(Spacer(1, 12))
|
||||
elements.append(Paragraph(f"+79013618377 Ангелина К. (Т-Банк) Итого к оплате: {total_sum:,.0f} ₽".replace(",", " "), bold_center))
|
||||
elements.append(Paragraph(num2words(total_sum, lang='ru').capitalize() + " рублей", center))
|
||||
|
||||
doc.build(elements)
|
||||
buffer.seek(0)
|
||||
return Response(buffer.getvalue(), media_type="application/pdf", headers={"Content-Disposition": "inline; filename=billing_document.pdf"})
|
||||
|
||||
|
||||
@router.get("/tech-spec/{deal_id}", tags=[""])
|
||||
async def deal_tech_spec(request: Request, deal_id: int):
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id}, {"_id": False})
|
||||
|
||||
status = await mongo.statuses_collection.find_one({"id": deal["statusId"]}, {"_id": False})
|
||||
deal_status = status.get("name", "Статус не определен") if status else "Статус не найден"
|
||||
|
||||
deal_services = await get_services(deal.get("services", []))
|
||||
deal_data = {
|
||||
"id": deal["id"],
|
||||
"name": deal.get("name") or "Без названия",
|
||||
"status": deal_status,
|
||||
"createdAt": datetime.strptime(deal["createdAt"], "%Y-%m-%dT%H:%M:%S").strftime("%d.%m.%Y, %H:%M"),
|
||||
"clientName": deal.get("clientName") or "Не указан",
|
||||
"deliveryDate": (
|
||||
datetime.strptime(deal["deliveryDate"], "%Y-%m-%dT%H:%M:%S.%f").strftime("%d.%m.%Y")
|
||||
if deal.get("deliveryDate") else "Не указана"
|
||||
),
|
||||
"baseMarketplace": deal.get("baseMarketplace", {}).get("name") or "Не указан",
|
||||
"shippingWarehouse": deal.get("shippingWarehouse") or "Не указан",
|
||||
"products": [],
|
||||
"services": deal_services
|
||||
}
|
||||
|
||||
for product in deal.get("products", []):
|
||||
product_data = await mongo.products_collection.find_one({"id": product["productId"]}, {"_id": False})
|
||||
if not product_data:
|
||||
continue
|
||||
|
||||
barcode_value = product_data.get("barcodes", [None])[0]
|
||||
barcode_image = generate_barcode_base64(barcode_value) if barcode_value else None
|
||||
|
||||
product_services = await get_services(product.get("services", []))
|
||||
deal_data["products"].append({
|
||||
"name": product_data.get("name") or "Без названия",
|
||||
"article": product_data.get("vendorCode") or "Нет артикула",
|
||||
"imageUrl": product_data.get("imageUrl"),
|
||||
"size": product_data.get("size") or 0,
|
||||
"quantity": product.get("quantity") or 0,
|
||||
"barcode": barcode_image,
|
||||
"services": product_services,
|
||||
"comment": product.get("comment")
|
||||
})
|
||||
|
||||
return templates.TemplateResponse("deal_tech_spec.html", {"request": request, "deal": deal_data})
|
||||
|
||||
|
||||
@router.post("/add-kit")
|
||||
async def add_kits(params: dict):
|
||||
start_time = time()
|
||||
deal_id = params["dealId"]
|
||||
kit_id = params["kitId"]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id}, {"_id": False})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
service_kit = await mongo.service_kits_collection.find_one({"id": kit_id})
|
||||
if not service_kit:
|
||||
return response({"message": "Комплект не найден", "ok": False}, start_time=start_time)
|
||||
|
||||
for service in service_kit.get("services", []):
|
||||
price = service.get("price", 0)
|
||||
if service.get("priceRanges"):
|
||||
price_range = service["priceRanges"][0]
|
||||
price = price_range.get("price", price)
|
||||
|
||||
deal["services"].append({
|
||||
"serviceId": service["id"],
|
||||
"price": price,
|
||||
"isFixedPrice": False,
|
||||
"quantity": 1
|
||||
})
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"services": deal["services"]}})
|
||||
return response({
|
||||
"message": "Сервисы из комплекта добавлены в сделку",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
async def get_services(services):
|
||||
service_list = []
|
||||
for service in services:
|
||||
service_data = await mongo.services_collection.find_one({"id": service["serviceId"]}, {"_id": False})
|
||||
if service_data:
|
||||
service_list.append({
|
||||
"name": service_data.get("name") or "Неизвестная услуга",
|
||||
"quantity": service.get("quantity") or 0,
|
||||
"price": service.get("price") or 0
|
||||
})
|
||||
|
||||
return service_list
|
||||
|
||||
|
||||
def generate_barcode_base64(barcode_text: str) -> str:
|
||||
buffer = BytesIO()
|
||||
code128 = barcode.get("code128", barcode_text, writer=ImageWriter())
|
||||
code128.write(buffer, {"module_height": 10.0, "font_size": 10, "quiet_zone": 2.0})
|
||||
buffer.seek(0)
|
||||
encoded = base64.b64encode(buffer.read()).decode("utf-8")
|
||||
return f"data:image/png;base64,{encoded}"
|
||||
51
app/api/v1/deal/employee.py
Normal file
51
app/api/v1/deal/employee.py
Normal file
@ -0,0 +1,51 @@
|
||||
from time import time
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app import mongo
|
||||
from app.utils.response_util import response
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/available/{user_id}", tags=[""])
|
||||
async def get(user_id: int):
|
||||
start_time = time()
|
||||
|
||||
employees = await mongo.users_collection.find({}, {
|
||||
"_id": False
|
||||
}).sort("id", mongo.asc).to_list()
|
||||
|
||||
return response({
|
||||
"employees": employees
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("", tags=[""])
|
||||
async def add(params: dict):
|
||||
start_time = time()
|
||||
params["createdAt"] = mongo.created_at()
|
||||
|
||||
deal = await mongo.deals_collection.find_one(
|
||||
{"id": params["dealId"]},
|
||||
{"_id": False}
|
||||
)
|
||||
|
||||
employees = deal.get("employees", [])
|
||||
user_entry = {"userId": params["userId"], "createdAt": params["createdAt"]}
|
||||
|
||||
if params["isAssign"]:
|
||||
if user_entry not in employees:
|
||||
employees.append(user_entry)
|
||||
else:
|
||||
employees = [employee for employee in employees if employee["userId"] != params["userId"]]
|
||||
|
||||
await mongo.deals_collection.update_one(
|
||||
{"id": params["dealId"]},
|
||||
{"$set": {"employees": employees}}
|
||||
)
|
||||
|
||||
return response({
|
||||
"message": "Данные обновлены",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
82
app/api/v1/deal/product.py
Normal file
82
app/api/v1/deal/product.py
Normal file
@ -0,0 +1,82 @@
|
||||
from time import time
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app import mongo
|
||||
from app.utils.response_util import response
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/update")
|
||||
async def update_product(params: dict):
|
||||
start_time = time()
|
||||
|
||||
deal_id = params["dealId"]
|
||||
product_id = params["product"]["productId"]
|
||||
quantity = params["product"]["quantity"]
|
||||
services = params["product"]["services"] = [
|
||||
{"serviceId": service["service"]["id"], "price": service["price"], "isFixedPrice": service.get("isFixedPrice", False), "quantity": 1}
|
||||
for service in params["product"]["services"]
|
||||
]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
products = deal.get("products", [])
|
||||
for product in products:
|
||||
if product["productId"] == product_id:
|
||||
if "comment" in params["product"]:
|
||||
product["comment"] = params["product"]["comment"]
|
||||
|
||||
product["quantity"] = quantity
|
||||
product["services"] = services
|
||||
break
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"products": products}})
|
||||
return response({
|
||||
"message": "Товар обновлён в сделке",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/add-kit")
|
||||
async def add_kits(params: dict):
|
||||
start_time = time()
|
||||
deal_id = params["dealId"]
|
||||
kit_id = params["kitId"]
|
||||
product_id = params["productId"]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
service_kit = await mongo.service_kits_collection.find_one({"id": kit_id})
|
||||
if not service_kit:
|
||||
return response({"message": "Комплект не найден", "ok": False}, start_time=start_time)
|
||||
|
||||
kit_services = []
|
||||
for service in service_kit.get("services", []):
|
||||
price = service.get("price", 0)
|
||||
if service.get("priceRanges"):
|
||||
price_range = service["priceRanges"][0]
|
||||
price = price_range.get("price", price)
|
||||
|
||||
kit_services.append({
|
||||
"serviceId": service["id"],
|
||||
"price": price,
|
||||
"isFixedPrice": False,
|
||||
"quantity": 1
|
||||
})
|
||||
|
||||
for product in deal.get("products", []):
|
||||
if product["productId"] == product_id:
|
||||
product["services"].extend(kit_services)
|
||||
break
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"products": deal["products"]}})
|
||||
return response({
|
||||
"message": "Сервисы из комплекта добавлены в продукт сделки",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
57
app/api/v1/deal/products.py
Normal file
57
app/api/v1/deal/products.py
Normal file
@ -0,0 +1,57 @@
|
||||
from time import time
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app import mongo
|
||||
from app.utils.response_util import response
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/add")
|
||||
async def add_product(params: dict):
|
||||
start_time = time()
|
||||
|
||||
deal_id = params["dealId"]
|
||||
product_data = {
|
||||
"productId": params["product"]["product"]["id"],
|
||||
"quantity": params["product"]["quantity"],
|
||||
"services": [
|
||||
{"serviceId": service["service"]["id"], "price": service["price"], "isFixedPrice": service.get("isFixedPrice", False), "quantity": 1}
|
||||
for service in params["product"]["services"]
|
||||
]
|
||||
}
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
products = deal.get("products", [])
|
||||
products.append(product_data)
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"products": products}})
|
||||
return response({
|
||||
"message": "Товар добавлен к сделке",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/delete")
|
||||
async def delete_product(params: dict):
|
||||
start_time = time()
|
||||
|
||||
deal_id = params["dealId"]
|
||||
product_id = params["productId"]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
products = deal.get("products", [])
|
||||
products = [product for product in products if product["productId"] != product_id]
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"products": products}})
|
||||
return response({
|
||||
"message": "Товар удалён из сделки",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
139
app/api/v1/deal/services.py
Normal file
139
app/api/v1/deal/services.py
Normal file
@ -0,0 +1,139 @@
|
||||
from time import time
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app import mongo
|
||||
from app.utils.response_util import response
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/add")
|
||||
async def add_service(params: dict):
|
||||
start_time = time()
|
||||
|
||||
deal_id = params["dealId"]
|
||||
service_data = {
|
||||
"serviceId": params["serviceId"],
|
||||
"quantity": params["quantity"],
|
||||
"price": params["price"]
|
||||
}
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
services = deal.get("services", [])
|
||||
services.append(service_data)
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"services": services}})
|
||||
return response({
|
||||
"message": "Услуга добавлена к сделке",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/update")
|
||||
async def update_service(params: dict):
|
||||
start_time = time()
|
||||
|
||||
deal_id = params["dealId"]
|
||||
service_id = params["service"]["serviceId"]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
services = deal.get("services", [])
|
||||
for service in services:
|
||||
if service["serviceId"] == service_id:
|
||||
for key, value in params["service"].items():
|
||||
service[key] = value
|
||||
break
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"services": services}})
|
||||
return response({
|
||||
"message": "Услуга обновлена в сделке",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/delete")
|
||||
async def delete_service(params: dict):
|
||||
start_time = time()
|
||||
|
||||
deal_id = params["dealId"]
|
||||
service_id = params["serviceId"]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
services = deal.get("services", [])
|
||||
updated_services = [service for service in services if service["serviceId"] != service_id]
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"services": updated_services}})
|
||||
return response({
|
||||
"message": "Услуга удалена из сделки",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/copy")
|
||||
async def copy_services(params: dict):
|
||||
start_time = time()
|
||||
|
||||
deal_id = params["dealId"]
|
||||
source_product_id = params["sourceProductId"]
|
||||
destination_product_ids = params["destinationProductIds"]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id})
|
||||
if not deal:
|
||||
return response({
|
||||
"message": "Сделка не найдена",
|
||||
"ok": False
|
||||
}, start_time=start_time)
|
||||
|
||||
products = deal.get("products", [])
|
||||
source_product_services = []
|
||||
|
||||
for product in products:
|
||||
if product["productId"] == source_product_id:
|
||||
source_product_services = product.get("services", [])
|
||||
break
|
||||
|
||||
source_services_map = {s["serviceId"]: s for s in source_product_services}
|
||||
service_quantities = {}
|
||||
|
||||
for product in products:
|
||||
if product["productId"] in destination_product_ids:
|
||||
new_services = []
|
||||
for service_id, service in source_services_map.items():
|
||||
new_service = service.copy()
|
||||
new_services.append(new_service)
|
||||
service_quantities[service_id] = service_quantities.get(service_id, 0) + product["quantity"]
|
||||
product["services"] = new_services
|
||||
|
||||
for service_id, total_quantity in service_quantities.items():
|
||||
service_data = await mongo.services_collection.find_one({"id": service_id})
|
||||
if not service_data or "priceRanges" not in service_data:
|
||||
continue
|
||||
|
||||
price_ranges = sorted(service_data["priceRanges"], key=lambda x: x["fromQuantity"])
|
||||
new_price = None
|
||||
|
||||
for price_range in price_ranges:
|
||||
if total_quantity >= price_range["fromQuantity"]:
|
||||
new_price = price_range["price"]
|
||||
|
||||
if new_price is not None:
|
||||
for product in products:
|
||||
for service in product.get("services", []):
|
||||
if service["serviceId"] == service_id and not service.get("isFixedPrice", False):
|
||||
service["price"] = new_price
|
||||
|
||||
await mongo.deals_collection.update_one({"id": deal_id}, {"$set": {"products": products}})
|
||||
return response({
|
||||
"message": "Услуги скопированы и обновлены",
|
||||
"ok": True
|
||||
}, start_time=start_time)
|
||||
66
app/api/v1/deal/summaries.py
Normal file
66
app/api/v1/deal/summaries.py
Normal file
@ -0,0 +1,66 @@
|
||||
from time import time
|
||||
|
||||
from fastapi import APIRouter
|
||||
from starlette.requests import Request
|
||||
|
||||
from app import mongo
|
||||
from app.utils.response_util import response
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", tags=[""])
|
||||
async def get(full: bool):
|
||||
start_time = time()
|
||||
|
||||
return response({
|
||||
"summaries": await mongo.get_all_summaries(full)
|
||||
}, start_time=start_time)
|
||||
|
||||
|
||||
@router.post("/reorder", tags=[""])
|
||||
async def reorder(params: dict, request: Request):
|
||||
start_time = time()
|
||||
|
||||
deal_id = params["dealId"]
|
||||
status_id = params["statusId"]
|
||||
index = params["index"]
|
||||
comment = params["comment"]
|
||||
|
||||
deal = await mongo.deals_collection.find_one({"id": deal_id}, {"_id": False})
|
||||
if not deal:
|
||||
return response({"message": "Сделка не найдена", "ok": False}, start_time=start_time)
|
||||
|
||||
update_fields = {
|
||||
"statusId": status_id,
|
||||
"index": index
|
||||
}
|
||||
|
||||
new_status = await mongo.statuses_collection.find_one({"id": status_id}, {"_id": False})
|
||||
if new_status and new_status.get("name") == "Завершено":
|
||||
update_fields["completedAt"] = mongo.created_at()
|
||||
|
||||
old_status_id = deal.get("statusId")
|
||||
await mongo.deals_collection.update_one(
|
||||
{"id": deal_id},
|
||||
{"$set": update_fields}
|
||||
)
|
||||
|
||||
if old_status_id != status_id:
|
||||
new_entry = {
|
||||
"changedAt": mongo.created_at(),
|
||||
"fromStatusId": old_status_id,
|
||||
"toStatusId": status_id,
|
||||
"userId": request.state.user["id"],
|
||||
"comment": comment
|
||||
}
|
||||
|
||||
await mongo.deals_collection.update_one(
|
||||
{"id": deal_id},
|
||||
{"$push": {"statusHistory": new_entry}}
|
||||
)
|
||||
|
||||
return response({
|
||||
"ok": True,
|
||||
"summaries": await mongo.get_all_summaries(False)
|
||||
}, start_time=start_time)
|
||||
Reference in New Issue
Block a user