arch-atlas

VendorService — Physical Products Slice

core/services/vendor_service.dart · physical-products + inventory + files

data

Overview

Subset of VendorService dedicated to physical products: getPhysicalProducts, getPhysicalProductsRaw, getPhysicalProduct, createPhysicalProduct, updatePhysicalProduct, deletePhysicalProduct, plus inventory and file-upload helpers.

User Flow

  1. getPhysicalProductsRaw returns the raw response list — used by the list controller to skip Product.fromJson.
  2. createPhysicalProduct builds the full product including options, variants and pricing.
  3. uploadPublicFile (multipart) posts to /vendor/files and returns a public URL used as image src.
  4. setInventoryItemQuantity attaches stock to a variant at a stock location.

Cases & Edge Cases

  • deletePhysicalProduct cascades to variants + inventory items server-side; clients still need to refetch.
  • uploadPublicFile uses a separate Dio config — multipart can't share JSON defaults.
  • Stock locations are per-seller (getStockLocations / createStockLocation) — auto-bootstrapped on first product create.

Code References

  • lib/src/core/services/vendor_service.dart:176 // getPhysicalProducts
  • lib/src/core/services/vendor_service.dart:230 // createPhysicalProduct
  • lib/src/core/services/vendor_service.dart:250 // updatePhysicalProduct
  • lib/src/core/services/vendor_service.dart:271 // deletePhysicalProduct
  • lib/src/core/services/vendor_service.dart:650 // uploadPublicFile

API Calls

  • GET/vendor/products?type=physicalno status

    Typed list of the seller's physical products (Product[]).

    Response
    { products: Product[] } /* typed */
    lib/src/core/services/vendor_service.dart:176 // getPhysicalProducts

    auth: seller. Consumed by seller_products_screen.dart.

  • GET/vendor/products?type=physicalno status

    Raw-map variant used to skip Product.fromJson when the screen only needs a subset.

    Response
    List<Map<string, any>> raw
    lib/src/core/services/vendor_service.dart // getPhysicalProductsRaw

    auth: seller. Same URL as the typed version, different parsing path.

  • GET/vendor/products/:idno status

    Preload a single product for the edit screen.

    Response
    { product: Product }
    lib/src/features/seller/products/edit_product_screen.dart

    auth: seller.

  • POST/vendor/productsno status

    Create a new physical product with options + variants + images.

    Request
    { title, description, status, options: [{ title, values }], variants: [{ title, sku, prices: [{ currency_code, amount }], options: { <title>: <value> } }], images: [{ url }], thumbnail, ... }
    Response
    { product: { id: string, variants: [{ id, inventory_item_id }, ...] } }
    lib/src/features/seller/products/create_product_screen.dart // via vendor_service.dart:230

    auth: seller. Returned inventory_item_ids are needed for the subsequent location-levels calls.

  • POST/vendor/products/:idno status

    Update product fields (partial).

    Request
    Partial product fields
    Response
    { product: Product }
    lib/src/features/seller/products/edit_product_screen.dart // via vendor_service.dart:250

    auth: seller.

  • DELETE/vendor/products/:idno status

    Delete a physical product.

    Response
    200 (no body)
    lib/src/features/seller/products/seller_products_screen.dart // Delete confirm

    auth: seller.

  • GET/vendor/stock-locationsno status

    Bootstrap the list of stock locations (warehouse / store).

    Response
    { stock_locations: [{ id, name, ... }] }
    lib/src/features/seller/products/create_product_screen.dart // location bootstrap

    auth: seller.

  • POST/vendor/stock-locationsno status

    Create a first-time stock location.

    Request
    { name: string, address?: any }
    Response
    { stock_location: StockLocation }
    lib/src/features/seller/products/create_product_screen.dart // first-time creation

    auth: seller.

  • POST/vendor/inventory-items/:id/location-levelsno status

    Set initial stocked_quantity for a variant at a stock location.

    Request
    { location_id: string, stocked_quantity: number }
    Response
    { ... }
    lib/src/features/seller/products/create_product_screen.dart

    auth: seller. Called per variant post product-create.

  • POST/vendor/inventory-items/:id/location-levels/:levelIdno status

    Update a variant's stocked_quantity at an existing location level.

    Request
    { stocked_quantity: number }
    Response
    { ... }
    lib/src/features/seller/products/edit_product_screen.dart // variant stock change

    auth: seller.

  • POST/vendor/product-location/:productIdno status

    Attach a geographic location (lat/lng/address) to a product.

    Request
    { lat: number, lng: number, address?: string }
    Response
    { ... }
    lib/src/features/seller/products/create_product_screen.dart // post-create

    auth: seller.

  • POST/vendor/filesno status

    Multipart upload of a product image to the vendor files endpoint.

    Request
    FormData({ file: File, purpose: 'public' })
    Response
    { url: string }
    lib/src/core/services/vendor_service.dart:650 // uploadPublicFile

    auth: seller. Used by both create + edit product screens for image upload.

Notes

Same VendorService is shared with seller-services (provisions slice) and seller-balance (Stripe slice). The class has grown to ~770 lines — splitting by domain is on the TODO list.