Sfoglia il codice sorgente

Dealing with the problem of multiple read_dir calls on checkout page. Introduced products.yaml as a table of product_id to product_path for faster processing of orders.

main.py - removed extra read_dir calls and replaced them with new logic

db.py - added get/write methods for the products.yaml

template.py - added calls to get product paths

cart.py - updated several functions to use new logic.
slow_tiger 1 anno fa
parent
commit
e82ee349b5
4 ha cambiato i file con 64 aggiunte e 62 eliminazioni
  1. 15 16
      app/cart.py
  2. 36 19
      app/db.py
  3. 10 24
      app/main.py
  4. 3 3
      app/template.py

+ 15 - 16
app/cart.py

@@ -5,7 +5,8 @@ import shortuuid
 
 from app.schema import CartUpdate, DocumentProduct, CartSessionItem, Settings, ProductInfoCode
 from app.template import make_product_info_code
-from app.db import get_product_by_product_id
+from app.db import get_product_by_product_id, get_products_id_db
+from app.parser import parse_file
 
 
 def product_exist_in_cart(
@@ -45,7 +46,7 @@ def initialize_cart(session, currency: str) -> dict[int, str] | NoReturn:
         }
 
 
-def get_inventory_amount(session_item, products) -> int | None:
+def get_inventory_amount(session_item, products, settings) -> int | None:
     """Returns the inventory amount value for any product by matching it
     against the list of selected products in the cart. We need to make
     use of the selected product's style and size options in order to
@@ -53,23 +54,18 @@ def get_inventory_amount(session_item, products) -> int | None:
     """
     inventory_amount = None
 
-    for product in products:
-        if product.meta.product_id == session_item["product_id"]:
-            for inventory in product.meta.inventory:
-                if (
-                    inventory.size == session_item["options"]["size"]
-                    and inventory.style == session_item["options"]["style"]
-                ):
-                    inventory_amount = inventory.amount
 
-    if inventory_amount:
-        return inventory_amount
+    product = parse_file(settings.git_repo, Path(products["products"][session_item["product_id"]]), settings.block_types)
+
+    for variation in product.meta.inventory:
+        if variation.product_variation_id == session_item["options"]["product_variation_id"]:
+            return variation.amount
 
 
 def update_cart_meta(
         session,
         shipping_amount: int,
-        products: list[DocumentProduct] | None = None
+        settings,
 ) -> NoReturn:
     """Update Meta key of Session Cart (subtotal, shipping, total).
 
@@ -81,6 +77,7 @@ def update_cart_meta(
     session_meta_item_amount = 0
     session_meta_subtotal = 0
     session_meta_weight = 0
+    products = get_products_id_db(settings)
 
     for item in session["items"].values():
         if products is not None:
@@ -90,7 +87,7 @@ def update_cart_meta(
             # - or adjust user's cart to the max available number of
             #   items set in the inventory of the given item
 
-            inventory_amount = get_inventory_amount(item, products)
+            inventory_amount = get_inventory_amount(item, products, settings)
 
             if inventory_amount == 0:
                 # if inventory amount for given item has meanwhile gone to 0,
@@ -146,6 +143,7 @@ def update_cart(
     shipping_amount: int,
     quantity: int,
     inventory_amount: int,
+    settings,
 ) -> NoReturn:
     """Update (add / remove) Session Cart with given product_id + options
     item: if Cart contains the product, increase / decrease product's
@@ -212,7 +210,7 @@ def update_cart(
 
                 session["items"][product_id] = update_data
 
-    update_cart_meta(session, shipping_amount)
+    update_cart_meta(session, shipping_amount, settings)
 
 
 def clear_cart(session, currency: str) -> NoReturn:
@@ -263,9 +261,10 @@ def create_product_list(settings: Settings, cart_items: dict[CartSessionItem]) -
     """
 
     product_list = []
+    products = get_products_id_db()
     
     for item in cart_items.values():
-        product = get_product_by_product_id(settings, item.product_id)
+        product = get_product_by_product_id(settings, item.product_id, products)
 
         product_path = str(Path(product.meta.path).stem)
         item = ProductInfoCode(path=product_path,

+ 36 - 19
app/db.py

@@ -134,6 +134,36 @@ def create_variation_id(product: DocumentProduct):
     return None # returns None in case there are no variations of the product or single variant only
 
 
+def get_products_id_db(settings) -> dict:
+    """Returns collection of product_ids and paths associated with it"""
+
+    product_data = {}
+
+    filepath = f'{Path(settings.git_repo)}/products.yaml'
+    p = Path(filepath)
+
+    if p.exists():
+        with open(p, 'r') as f:
+            product_data = yaml.safe_load(f)
+
+    return product_data
+
+
+def write_product_id_db(product:DocumentProduct, settings, products_data = {}):
+    """Adds product_id - path relation to the products.md in product folder"""
+
+    filepath = f'{Path(settings.git_repo)}/products.yaml'
+    product_file_path = f'{Path(settings.git_repo)}/{product.meta.path}/index.md'
+    p = Path(filepath)
+    products_data.setdefault("products", {})
+
+    if product.meta.product_id not in products_data["products"] or not p.exists():
+        products_data["products"][product.meta.product_id] = product_file_path
+
+        with open(p, "w") as f:
+            yaml.dump(products_data, f, default_flow_style = False)
+
+
 def write_variation_id(product:DocumentProduct, settings):
     """ Generate and write IDs for variation of the product into file"""
 
@@ -197,27 +227,14 @@ def get_products_by_category(settings):
 def get_product_by_product_id(
     settings: Settings, 
     product_id: str,
-    products = []
+    products: dict,
 ) -> DocumentProduct:
     """Fetch a product by its product-id."""
-    if not products:
-        products = read_dir(
-            settings.git_repo,
-            settings.document_match,
-            settings.document_exclude,
-            settings.block_types,
-            exclude_doc="products",
-            tree="products",
-    )
-
-    product = None
-
-    for p in products:
-        if p.meta.product_id == product_id:
-            return p
-
-    return product
-
+    if products:
+        product = parse_file(settings.git_repo, Path(products["products"][product_id]), settings.block_types)
+        return product
+    else:
+        return None
 
 def get_docs_by_category(category: str, settings):
     """Read a directory of directories and return a sublist with only the

+ 10 - 24
app/main.py

@@ -42,6 +42,8 @@ from app.db import (
     update_status_order,
     write_variation_id,
     get_variation_id,
+    write_product_id_db,
+    get_products_id_db,
 )
 from app.email import send_email
 from app.parser import md, read_dir, read_file
@@ -106,9 +108,11 @@ async def lifespan(app: FastAPI):
         tree="products",
     )
 
+    products_data = get_products_id_db(settings)
+
     for single_product in products_list:
         write_variation_id(single_product, settings)
-
+        write_product_id_db(single_product, settings, products_data)
 
     yield
 
@@ -364,25 +368,16 @@ async def checkout(request: Request):
         settings.git_repo, filename, settings.document_match, settings.block_types
     )
 
-    products = read_dir(
-        settings.git_repo,
-        settings.document_match,
-        settings.document_exclude,
-        settings.block_types,
-        exclude_doc="products",
-        tree="products",
-    )
-
     session_data = request.session
     initialize_cart(session_data, settings.currency.default)
 
     update_cart_meta(
-        session_data["cart"], session_data["cart"]["meta"]["shipping"], products
+        session_data["cart"], session_data["cart"]["meta"]["shipping"], settings
     )
 
     cart = CartSession(**request.session["cart"])
     
-    checkout_data = prepare_checkout(cart, settings, doc, products)
+    checkout_data = prepare_checkout(cart, settings, doc)
 
     site = read_file(
         settings.git_repo,
@@ -484,6 +479,7 @@ async def checkout_update(
         shipping_amount,
         quantity,
         inventory_amount,
+        settings,
     )
 
     cart = CartSession(**request.session["cart"])
@@ -512,17 +508,8 @@ async def checkout_update(
                 settings.block_types,
             )
 
-            products = read_dir(
-                settings.git_repo,
-                settings.document_match,
-                settings.document_exclude,
-                settings.block_types,
-                exclude_doc="products",
-                tree="products",
-            )
-
             checkout_data = prepare_checkout(
-                cart, settings, doc, products, js_update=False
+                cart, settings, doc,  js_update=False
             )
 
             cart_items = [
@@ -580,7 +567,6 @@ async def checkout_shipping(request: Request,
     ):
         raise HTTPException(status_code=403, detail="Shipping info are incorrect.")
 
-
     shipping_rate = calculate_shipping_cost(country, weight, settings.currency.default)
 
     if shipping_rate:
@@ -589,7 +575,7 @@ async def checkout_shipping(request: Request,
         session_data = request.session
         initialize_cart(session_data, settings.currency.default)
 
-        update_cart_meta(session_data["cart"], shipping_rate.price)
+        update_cart_meta(session_data["cart"], shipping_rate.price, settings)
         cart = CartSession(**request.session['cart'])
 
         if js:

+ 3 - 3
app/template.py

@@ -1,7 +1,5 @@
-import os
 import random
 import hashlib
-import time
 from pathlib import Path
 from typing import Literal
 
@@ -12,6 +10,7 @@ from app.db import (
     check_product_availability,
     get_docs_by_category,
     get_product_by_product_id,
+    get_products_id_db,
 )
 from app.parser import read_file
 from app.schema import (
@@ -94,7 +93,7 @@ def prepare_checkout(
     cart: CartSession,
     settings: Settings,
     doc: DocumentCheckout,
-    products: list[DocumentProduct],
+    product_id: str = None,
     js_update: bool = False,
 ) -> dict[str, list[str] | dict[str, str | int] | DocumentCheckout]:
     """Return dictionary with necessary data to display the Checkout view:
@@ -114,6 +113,7 @@ def prepare_checkout(
     show_checkout = []
 
     # map over each item in the cart and create a new item object
+    products = get_products_id_db(settings)
     checkout_items = []
     for item in cart.items.values():
         product = get_product_by_product_id(settings, item.product_id, products)