from typing import Annotated from fastapi import FastAPI, Depends from sqlalchemy import select, func, and_, cast, String from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import joinedload from backend.session import get_session from database.sipro import * app = FastAPI() def get_marketplace_suppliers_and_company_warehouses(marketplace: Marketplace): company = marketplace.company suppliers = set() company_warehouses = set() for warehouse in marketplace.warehouses: for supplier in warehouse.suppliers: if supplier.is_pseudo: continue suppliers.add(supplier) company_warehouses.update(warehouse.company_warehouses) if marketplace.sell_warehouse_products: company_warehouse = company.warehouse if company_warehouse and not company.is_denco: company_warehouses.add(company_warehouse) return suppliers, company_warehouses # def get_stocks_data(marketplace: Marketplace): # suppliers, company_warehouses = get_marketplace_suppliers_and_company_warehouses(marketplace) # supplier_ids = [supplier.id for supplier in suppliers] # company_warehouse_ids = [warehouse.id for warehouse in company_warehouses] # # sell_mixes: bool = marketplace.sell_mixes # sell_blocks: bool = marketplace.sell_blocks # sell_warehouse_products: bool = marketplace.sell_warehouse_products # sell_from_price: int = marketplace.sell_from_price # # stmt = ( # select( # MarketplaceProduct # ) # .join( # Product # ) # .options( # joinedload(MarketplaceProduct.product) # ) # .where( # MarketplaceProduct.marketplace_id == marketplace.id # ) # ) # supplier_stock_subquery = ( # select( # func.sum(SupplierProduct.supplier_stock).label('supplier_stock'), # Product.id.label('product_id') # ) # .join( # Product # ) # .where( # SupplierProduct.supplier_id.in_(supplier_ids) # ) # .group_by( # Product.id # ) # .subquery() # ) # # warehouse_stock_subquery = ( # select( # func.count(CompanyWarehouseProduct.is_sold).label('warehouse_stock'), # CompanyWarehouseProduct.product_id.label('product_id') # ) # .where( # CompanyWarehouseProduct.is_sold == False, # CompanyWarehouseProduct.company_warehouse_id.in_(company_warehouse_ids) # ) # .group_by( # CompanyWarehouseProduct.product_id # ) # .subquery() # ) async def get_stocks_data(session: AsyncSession, marketplace: Marketplace): company = marketplace.company suppliers, company_warehouses = get_marketplace_suppliers_and_company_warehouses(marketplace) supplier_ids = [supplier.id for supplier in suppliers] company_warehouse_ids = [warehouse.id for warehouse in company_warehouses] sell_mixes: bool = marketplace.sell_mixes sell_blocks: bool = marketplace.sell_blocks sell_warehouse_products: bool = marketplace.sell_warehouse_products sell_from_price: int = marketplace.sell_from_price supplier_stock_subquery = ( select( func.sum(SupplierProduct.supplier_stock).label('supplier_stock'), SupplierProduct.product_id.label('product_id') ) .select_from(SupplierProduct) .join(Product) .where(SupplierProduct.supplier_id.in_(supplier_ids)) .group_by(SupplierProduct.product_id) .subquery() ) warehouse_stock_subquery = ( select( func.count(CompanyWarehouseProduct.is_sold).label('warehouse_stock'), CompanyWarehouseProduct.product_id.label('product_id') ) .select_from(CompanyWarehouseProduct) .where( CompanyWarehouseProduct.is_sold == False, CompanyWarehouseProduct.company_warehouse_id.in_(company_warehouse_ids) ) .group_by(CompanyWarehouseProduct.product_id) .subquery() ) mix_stock_first_subquery = ( select( func.sum(SupplierProduct.supplier_stock).label('master_stock'), SupplierProduct.product_id.label('product_id') ) .select_from(SupplierProduct) .where(SupplierProduct.supplier_id.in_(supplier_ids)) .group_by(SupplierProduct.product_id) .subquery() ) mix_stock_full_subquery = ( select( func.min(SupplierProduct.in_block).label('mix_stock'), Product.id.label('product_id') ) .select_from(Product) .join(SupplierProduct) .join(ProductRelation, Product.id == ProductRelation.slave_product_id) .join(mix_stock_first_subquery, mix_stock_first_subquery.c.product_id == ProductRelation.master_product_id) .where( ProductRelation.relation_type == 5, mix_stock_first_subquery.c.master_stock > 0 ) .group_by(Product.id) .subquery() ) is_master_first_subquery = ( select( ProductRelation.master_product_id, (func.count(ProductRelation.master_product_id) > 0).label('is_master') ) .where( ProductRelation.relation_type == 5 ) .group_by(ProductRelation.master_product_id) .subquery() ) is_master_subquery = ( select( Product.id.label('product_id'), func.coalesce(is_master_first_subquery.c.is_master, False).label('is_master') ) .select_from( Product ) .outerjoin( is_master_first_subquery, Product.id == is_master_first_subquery.c.master_product_id ) .subquery() ) in_block_subquery = ( select( Product.id.label('product_id'), func.min(SupplierProduct.in_block).label('in_block_value') ) .select_from(Product) .join(SupplierProduct) .where( SupplierProduct.supplier_id.in_(supplier_ids), SupplierProduct.supplier_stock > 0 ) .group_by(Product.id) .subquery() ) slaves_stock_first_subquery = ( select( ProductRelation.master_product_id.label('product_id'), func.sum(SupplierProduct.supplier_stock).label('slaves_stock') ) .select_from(ProductRelation) .join(SupplierProduct, and_( ProductRelation.slave_product_id == SupplierProduct.product_id, ProductRelation.relation_type == 7 )) .where(SupplierProduct.supplier_id.in_(supplier_ids)) .group_by(ProductRelation.master_product_id) .subquery() ) slaves_stock_subquery = ( select( Product.id.label('product_id'), slaves_stock_first_subquery.c.slaves_stock.label('slaves_stock') ) .select_from(Product) .join(slaves_stock_first_subquery, slaves_stock_first_subquery.c.product_id == Product.id) .subquery() ) stmt = ( select( MarketplaceProduct, func.coalesce(Product.article, cast(Product.denco_article, String)).label('denco_article'), MarketplaceProduct.mp_price_bought.label('price_purchase'), supplier_stock_subquery.c.supplier_stock.label('supplier_stock'), warehouse_stock_subquery.c.warehouse_stock.label('warehouse_stock'), mix_stock_full_subquery.c.mix_stock.label('mix_stock'), in_block_subquery.c.in_block_value.label('in_block_value'), is_master_subquery.c.is_master.label('is_master'), slaves_stock_subquery.c.slaves_stock.label('slaves_stock'), MarketplaceProduct.price_recommended.label('price_recommended'), MarketplaceProduct.is_archived.label('is_archived') ) .select_from(MarketplaceProduct) .join(Product) .options(joinedload(MarketplaceProduct.product)) .where(MarketplaceProduct.marketplace_id == marketplace.id) .outerjoin(supplier_stock_subquery, supplier_stock_subquery.c.product_id == MarketplaceProduct.product_id) .outerjoin(warehouse_stock_subquery, warehouse_stock_subquery.c.product_id == MarketplaceProduct.product_id) .outerjoin(mix_stock_full_subquery, mix_stock_full_subquery.c.product_id == MarketplaceProduct.product_id) .outerjoin(in_block_subquery, in_block_subquery.c.product_id == MarketplaceProduct.product_id) .outerjoin(is_master_subquery, is_master_subquery.c.product_id == MarketplaceProduct.product_id) .outerjoin(slaves_stock_subquery, slaves_stock_subquery.c.product_id == MarketplaceProduct.product_id) ) print(stmt.compile(compile_kwargs={ 'literal_binds': True })) result = await session.execute(stmt) marketplace_products = result.all() result = [] for marketplace_product, denco_article, price_purchase, supplier_stock, warehouse_stock, mix_stock, in_block_value, is_master, slaves_stock, price_recommended, is_archived in marketplace_products: if is_archived or (sell_from_price > price_recommended): result.append({ 'denco_article': denco_article, 'full_stock': 0, # 'marketplace_product': marketplace_product, }) continue is_mix = mix_stock is not None in_block_value = in_block_value or 1 price_purchase = price_purchase or 0 supplier_stock = supplier_stock or 0 warehouse_stock = warehouse_stock or 0 mix_stock = mix_stock or 0 slaves_stock = slaves_stock or 0 if not sell_warehouse_products: warehouse_stock = 0 if all([is_mix, slaves_stock > 0]): mix_stock = 0 balance_limit = price_purchase > company.balance if balance_limit: supplier_stock = 0 full_stock = supplier_stock + warehouse_stock if all([not is_mix, not sell_blocks, in_block_value > 1]): full_stock = warehouse_stock if sell_mixes and (not balance_limit): full_stock += mix_stock if (not sell_mixes) and is_master: full_stock = warehouse_stock if (not sell_mixes) and is_mix: full_stock = warehouse_stock if 45 > company.balance: full_stock = 0 full_stock = max([0, full_stock]) result.append({ 'denco_article': denco_article, 'full_stock': full_stock, # 'marketplace_product': marketplace_product, }) return result @app.get("/") async def root( session: Annotated[AsyncSession, Depends(get_session)], marketplace_id: int ): marketplace = await session.get(Marketplace, marketplace_id, options=[ joinedload(Marketplace.warehouses).joinedload(Warehouse.suppliers), joinedload(Marketplace.warehouses).joinedload(Warehouse.company_warehouses), joinedload(Marketplace.company).joinedload(Company.warehouse) ]) data = await get_stocks_data(session, marketplace) data = sorted(data, key=lambda x: x['denco_article']) return {"message": data} @app.get("/hello/{name}") async def say_hello(name: str): return {"message": f"Hello {name}"}