Model Context Protocol (MCP) server for processing Request for Quotation (RFQ) operations, providing AI assistants with tools to manage the complete RFQ lifecycle.
The MCP RFQ Processor connects AI assistants to the ai_rfq_engine GraphQL backend, enabling intelligent automation of:
- RFQ Request Management: Submit, update, and track customer quotation requests with flexible item management
- Item & Inventory Search: Find available items and provider inventory with batch tracking
- Quote Generation: Create and manage detailed quotes with flexible item operations, pricing, and discounts
- Installment Planning: Set up payment schedules for quotes
- Document Management: Upload and track RFQ-related files
- Segment Management: Organize customers and providers into pricing segments
Current Version: 0.1.1
Total MCP Tools: 28 (implemented in mcp_configuration.py)
- Status-Aware Workflow Controls
- Requests, quotes, and installments enforce validated transitions with guard rails
- Auto-update request status to
in_progresswhen items change - Quotes auto-transition to
in_progresswhen items are created
- Automatic Business Rules
- Auto-disapprove quotes when a request is marked
modified - Auto-complete quotes when all installments are
paid, then auto-complete the request - When one quote is confirmed, competing quotes are disapproved (unless already terminal)
- Auto-disapprove quotes when a request is marked
- Provider Assignment Helpers
assign_provider_item_to_request_itemandremove_provider_item_from_request_itemmanage provider links on requests- Quote creation pulls assigned provider items to build quote items automatically
- Pricing Intelligence with Batch Optimization
calculate_quote_pricinguses email-based batch loaders to efficiently group request items by provider- Single GraphQL query retrieves all price tiers for all items using DataLoader pattern
get_item_price_tierssupports batch queries with email + quote_items arrayget_discount_promptsefficiently loads discount prompts from all hierarchical scopes
- Workflow Convenience
confirm_request_and_create_quotesandconfirm_quote_and_create_installmentswrap multi-step flows for quicker automation
See DEVELOPMENT_PLAN.md for complete workflow documentation.
graph TB
subgraph Clients
AI[AI Assistant<br/>Claude, etc.]
Browser[Browser / Custom Client]
end
subgraph MCP_Layer
MCPServer[MCP RFQ Processor<br/>this package]
Processors[Layered Processors<br/>Request | Item | Quote | Pricing | Installment]
end
subgraph Backend_Layer
GraphQL[ai_rfq_engine<br/>GraphQL API<br/>AWS Lambda]
Batch[Batch Loaders<br/>DataLoader Pattern]
end
subgraph Data_Layer
DDB[(DynamoDB<br/>RFQ Tables)]
S3[(S3<br/>File Storage)]
end
AI -->|MCP Protocol| MCPServer
Browser -->|MCP Protocol| MCPServer
MCPServer --> Processors
Processors -->|GraphQL Queries/Mutations| GraphQL
GraphQL --> Batch
Batch -->|Optimized Queries| DDB
GraphQL -->|Store/Retrieve Files| S3
AI Assistant (Claude, etc.)
↓ MCP Protocol (28 Tools)
MCP RFQ Processor (this package)
├── Request Processor (8 tools)
├── Item Processor (4 tools)
├── Quote Processor (5 tools)
├── Pricing Processor (3 tools)
├── Installment Processor (4 tools)
├── File Processor (2 tools)
└── Segment Processor (1 tool)
↓ GraphQL over AWS Lambda
ai_rfq_engine (backend)
├── Batch Loaders (v0.1.1)
├── Status Managers
└── Business Rules Engine
↓
DynamoDB Tables + S3 Storage
- Python >= 3.8
- AWS credentials with Lambda execution permissions
- Access to deployed
ai_rfq_engineGraphQL endpoint
cd mcp_rfq_processor
pip install -e .pip install boto3 humps pendulum silvaengine-utilityAdd to your MCP settings file (e.g., claude_desktop_config.json):
{
"mcpServers": {
"rfq_processor": {
"command": "python",
"args": ["-m", "mcp_rfq_processor"],
"env": {
"ENDPOINT_ID": "your-endpoint-id",
"AWS_REGION": "us-east-1",
"AWS_ACCESS_KEY_ID": "your-access-key",
"AWS_SECRET_ACCESS_KEY": "your-secret-key"
}
}
}
}When using as a Python module:
from mcp_rfq_processor import MCPRfqProcessor
import logging
logger = logging.getLogger(__name__)
processor = MCPRfqProcessor(
logger=logger,
region_name="us-east-1",
aws_access_key_id="your-access-key",
aws_secret_access_key="your-secret-key",
execute_mode="aws_lambda", # or "local" for testing
default_batch_expiration_filter_days=90, # Default: 90 days (~3 months)
installment_scheduled_day=15, # Default: 15th day of month for installment schedules
)
processor.endpoint_id = "your-endpoint-id"Configuration Options:
| Setting | Type | Default | Description |
|---|---|---|---|
region_name |
string | - | AWS region where Lambda functions are deployed |
aws_access_key_id |
string | - | AWS access key ID |
aws_secret_access_key |
string | - | AWS secret access key |
execute_mode |
string | - | Execution mode: aws_lambda or local |
default_batch_expiration_filter_days |
integer | 90 | Default minimum expiration days for get_provider_item_batches. When no expiration filters are provided, only returns batches expiring this many days or more in the future. |
installment_scheduled_day |
integer | 15 | Day of month (1-31) for scheduled installment dates in create_installments. If day doesn't exist in a month (e.g., Feb 31), uses last day of that month. |
All 28 tools are defined in mcp_configuration.py and exposed by MCPRfqProcessor.
graph TB
subgraph Request_Management[Request Management - 8 Tools]
R1[submit_rfq_request]
R2[update_rfq_request]
R3[get_rfq_request]
R4[search_rfq_requests]
R5[add_item_to_rfq_request]
R6[remove_item_from_rfq_request]
R7[assign_provider_item_to_request_item]
R8[remove_provider_item_from_request_item]
end
subgraph Item_Management[Item & Inventory - 4 Tools]
I1[search_items]
I2[get_item]
I3[get_provider_items]
I4[get_provider_item_batches]
end
subgraph Quote_Management[Quote Management - 5 Tools]
Q1[create_quote]
Q2[update_quote]
Q3[get_quote]
Q4[search_quotes]
Q5[update_quote_item]
end
subgraph Pricing[Pricing & Discounts - 3 Tools]
P1[get_item_price_tiers<br/>Batch-Optimized]
P2[get_discount_prompts<br/>Hierarchical Scopes]
P3[calculate_quote_pricing<br/>Groups by Provider]
end
subgraph Installment[Installment Management - 4 Tools]
IN1[create_installment]
IN2[update_installment]
IN3[create_installments]
IN4[get_installments]
end
subgraph Workflow[Workflow Helpers - 2 Tools]
W1[confirm_request_and_create_quotes]
W2[confirm_quote_and_create_installments]
end
subgraph Files[File Management - 2 Tools]
F1[upload_rfq_file]
F2[get_rfq_files]
end
subgraph Segments[Segment Management - 1 Tool]
S1[get_segment_contacts]
end
style Request_Management fill:#e1f5ff
style Item_Management fill:#fff4e1
style Quote_Management fill:#e1ffe1
style Pricing fill:#ffe1f5
style Installment fill:#f5e1ff
style Workflow fill:#e1fff4
style Files fill:#ffe1e1
style Segments fill:#f5ffe1
Submit a new RFQ request from a customer.
Default Status: initial - Request has been created but not yet being worked on.
Input:
{
"email": "customer@example.com",
"request_title": "Need 500 units of Product X",
"request_description": "Detailed requirements...",
"billing_address": {},
"shipping_address": {},
"items": [],
"notes": "Urgent order",
"expired_at": "2025-12-31T23:59:59Z",
"status": "initial"
}Output:
{
"request_uuid": "generated-uuid",
"status": "initial",
"created_at": "2025-11-05T10:30:00Z",
"items": []
}Update an existing RFQ request (title, description, addresses, items, status, etc.).
Status Transitions: All status changes are validated according to the request status flow.
Automatic Business Rules:
- When status changes to
modified, all related quotes are automatically set todisapproved - When items are modified while in
modifiedstatus, automatically transitions toin_progress
Input:
{
"request_uuid": "request-uuid-string",
"request_title": "Updated title",
"items": [...],
"status": "confirmed"
}Output: Updated request object.
Convenience method to add a single item to an existing request.
Input:
{
"request_uuid": "request-uuid-string",
"item": {
"item_uuid": "item-uuid",
"quantity": 100
}
}Output: Updated request with new item added.
Convenience method to remove a single item from an existing request.
Input:
{
"request_uuid": "request-uuid-string",
"item_uuid": "item-uuid-to-remove"
}Output: Updated request with item removed.
Attach a provider item (and optional batch/quantity) to a request item. Validates that the provider item belongs to the specified provider and updates status to in_progress when needed.
Remove provider assignments from a request item. Can target a specific provider item/batch or clear all provider items for the request item.
Retrieve details of an existing RFQ request.
Input:
{
"request_uuid": "request-uuid-string"
}Output: Complete request object with contact info and associated quotes.
Search and filter RFQ requests.
Input:
{
"contact_uuid": "optional-contact-uuid",
"statuses": ["pending", "quoted"],
"from_expired_at": "2025-01-01T00:00:00Z",
"to_expired_at": "2025-12-31T23:59:59Z",
"page_number": 1,
"limit": 20
}Output: Paginated list of matching requests.
Search for available items in the catalog.
Input:
{
"item_type": "product",
"item_name": "Widget",
"uoms": ["EA", "BOX"],
"page_number": 1,
"limit": 50
}Output: List of items with descriptions, types, and UOM options.
Get detailed information about a specific item.
Input:
{
"item_uuid": "item-uuid-string"
}Output: Complete item details including pricing tiers.
Search provider inventory with batch information merged.
For each provider item, automatically fetches and merges batch information including:
- batches: Array of batch details with slow_move_item flags and guardrail pricing
- Each batch includes: batch_no, expired_at, produced_at, slow_move_item, guardrail_price_per_uom
Optional batch filters (applied when fetching batches):
- expired_at_gt: Filter batches expiring after this date
- expired_at_lt: Filter batches expiring before this date
- slow_move_item: Filter for slow-moving inventory (default: false)
- in_stock: Filter for in-stock batches (default: true)
Input:
{
"item_uuid": "optional-item-uuid",
"provider_corp_external_id": "PROVIDER-001",
"min_base_price_per_uom": 10.00,
"max_base_price_per_uom": 50.00,
"expired_at_gt": "2025-11-05T00:00:00Z",
"slow_move_item": false,
"in_stock": true,
"page_number": 1,
"limit": 50
}Output: List of provider items with pricing, availability, and merged batch information.
Note: If no expiration filters provided, defaults to batches expiring 90+ days from now.
Get batch/lot information for provider items including slow_move_item flag and guardrail pricing.
Input:
{
"provider_item_uuid": "provider-item-uuid",
"in_stock": true,
"expired_at_gt": "2025-11-05T00:00:00Z"
}Output: List of batches with lot numbers, expiry dates, and stock levels.
Note: If neither expired_at_gt nor expired_at_lt is provided, defaults to filtering batches expiring 90+ days from now.
Generate a new quote for an RFQ request.
Default Status: initial - Quote has been created but not yet being worked on.
Requirements:
- Request must be in
confirmedstatus to create quotes
Note:
shipping_methodandshipping_amountcannot be set during creation - useupdate_quoteafter creationrounds(negotiation rounds) is auto-calculated by the backend- Quote items are created automatically from the provider assignments on the request for the selected provider
Input:
{
"request_uuid": "request-uuid",
"provider_corp_external_id": "PROVIDER-001",
"sales_rep_email": "sales@provider.com",
"status": "initial",
"notes": "Initial quote"
}Output:
{
"quote_uuid": "generated-quote-uuid",
"request_uuid": "request-uuid",
"rounds": 0,
"total_quote_amount": 0.00,
"status": "initial"
}Retrieve quote details.
Input:
{
"request_uuid": "request-uuid",
"quote_uuid": "quote-uuid"
}Output: Complete quote with line items, totals, and discount information.
Update quote metadata (shipping, status, notes).
Status Transitions: All status changes are validated according to the quote status flow.
Note: rounds (negotiation rounds) is auto-calculated by the backend and cannot be manually set.
Input:
{
"request_uuid": "request-uuid",
"quote_uuid": "quote-uuid",
"shipping_method": "express",
"shipping_amount": 75.00,
"status": "confirmed",
"notes": "Updated pricing and shipping"
}Output: Updated quote object with auto-calculated rounds.
Search and filter quotes.
Input:
{
"request_uuid": "optional-request-uuid",
"provider_corp_external_id": "PROVIDER-001",
"statuses": ["confirmed", "completed"],
"min_total_quote_amount": 1000.00,
"page_number": 1,
"limit": 20
}Output: Paginated list of matching quotes.
Update an existing quote item (discount amount only). Used to apply discounts after quote items are created.
Requirements:
- Quote must be in
in_progressstatus to apply discounts - Only discount modifications are allowed (discount amount adjustments)
Note: Only discount_amount can be updated. Other fields (qty, provider_item_uuid, etc.) are read-only after creation.
Input:
{
"quote_uuid": "quote-uuid",
"quote_item_uuid": "quote-item-uuid",
"discount_amount": 75.00
}Output: Updated quote item with recalculated totals.
Get tiered pricing for multiple items using batch loader optimization.
Batch-Optimized Approach: Uses customer email for segment lookup and efficiently loads price tiers for quote items with automatic quantity filtering. Returns only tiers matching each item's quantity range. Preferred for processing multiple items efficiently.
Input:
{
"email": "customer@example.com",
"quote_items": [
{
"item_uuid": "item-uuid",
"provider_item_uuid": "provider-item-uuid",
"qty": 100
}
]
}Parameters:
email: Customer email address for segment lookup (required)quote_items: List of quote items with item_uuid, provider_item_uuid, and qty. Each item will have its applicable price tiers returned based on quantity thresholds.
Output: List of price tiers with provider_item_batches merged.
{
"item_price_tiers": [
{
"item_uuid": "...",
"provider_item_uuid": "...",
"quantity_greater_then": 50,
"quantity_less_then": 200,
"price_per_uom": 10.5,
"margin_per_uom": 2.0,
"provider_item_batches": [
{
"batch_no": "LOT-2025-001",
"price_per_uom": 10.0
}
]
}
]
}Updated in v0.1.1: Refactored to use batch loaders with email-based segment lookup for better performance.
Get discount prompts for items using batch loader optimization.
Batch-Optimized Approach: Loads prompts from all hierarchical scopes (GLOBAL, SEGMENT, ITEM, PROVIDER_ITEM) and deduplicates. Returns combined discount prompts with conditions and rules. Preferred for processing multiple items efficiently.
Input:
{
"email": "customer@example.com",
"quote_items": [
{
"item_uuid": "item-uuid",
"provider_item_uuid": "provider-item-uuid"
}
]
}Parameters:
email: Customer email address for segment lookup (required)quote_items: List of quote items with item_uuid and provider_item_uuid to determine applicable prompts
Output: Combined discount prompts from all hierarchical scopes.
{
"discount_prompts": [
{
"scope": "SEGMENT",
"prompt": "Apply 5% discount for slow-moving items",
"conditions": "slow_move_item=true",
"max_discount_percentage": 5.0
}
]
}New in v0.1.1: Replaces get_discount_rules with batch-optimized prompt loading across hierarchical scopes.
Calculate pricing information for an RFQ request using batch-optimized queries.
Batch-Optimized Approach: Groups items by provider and provides subtotals and price tiers. Uses batch loaders for efficient multi-item processing. Returns pricing structure for decision-making.
Note: This reads from REQUEST (not quote) and groups items by provider_corp_external_id. Use this BEFORE creating quotes (Step 7 in workflow).
Input:
{
"request_uuid": "request-uuid",
"email": "customer@example.com"
}Parameters:
request_uuid: UUID of the RFQ request (required)email: Customer email for segment lookup and batch-optimized price tier queries (required)
Output: Grouped pricing structure with items grouped by provider.
{
"request_uuid": "req-uuid",
"groups": [
{
"provider_corp_external_id": "PROVIDER-001",
"items": [
{
"provider_item_uuid": "prov-item-uuid",
"item_uuid": "item-uuid",
"batch_no": "LOT-2025-001",
"qty": 500,
"price_per_uom": 9.50,
"guardrail_price_per_uom": 9.50,
"slow_move_item": true,
"expired_at": "2026-03-15T00:00:00Z",
"subtotal": 4750.00
}
],
"group_subtotal": 4750.00
}
]
}Key Features:
- Uses single batch-optimized GraphQL query for all price tiers
- Groups items by provider_corp_external_id for multi-provider comparison
- Includes batch-specific pricing with slow_move_item flags and guardrail pricing
- Returns pricing structure WITHOUT applying discounts (LLM can use get_discount_prompts separately)
Updated in v0.1.1: Refactored to use email-based batch loaders instead of segment_uuid. Price tiers and discount prompts now fetched separately via dedicated batch-optimized functions.
Set up a payment installment for a quote.
Requirements:
- Quote must be in
confirmedstatus to create installments
Workflow:
- Create installments with
status=pendingwhen quote status changes toconfirmed - Update installment
status=paidwhen payment is received - When all installments are
paid, quote status is automatically set tocompleted
Automatic Behavior:
- Amount: If
installment_amountnot provided, uses full remaining balance. If provided, usesmin(requested_amount, remaining_balance)(auto-caps at remaining balance) - Priority: Automatically set to
max(existing_priorities) + 1for sequential ordering (starts at 0 for first installment) - Due Date: Automatically sets to current time (no need to specify)
- installment_ratio: Auto-calculated by backend based on
installment_amount/final_total_quote_amount - Auto-Capping: Requested amount > remaining balance automatically uses remaining balance instead
Input Options:
Option 1: Full remaining balance (automatic)
{
"quote_uuid": "quote-uuid",
"request_uuid": "request-uuid",
"status": "pending"
}Option 2: Partial installment (custom amount)
{
"quote_uuid": "quote-uuid",
"request_uuid": "request-uuid",
"installment_amount": 3000.00,
"status": "pending"
}Installment Status Values:
pending: Payment scheduled but not yet received (default when quote is confirmed)paid: Payment has been received and verifiedcancelled: Payment was cancelled or refunded
Validation Rules:
- Without installment_amount: Uses full remaining balance (
final_total_quote_amount - existing_pending_paid_total) - With installment_amount: Must be > 0. If exceeds remaining balance, automatically capped at remaining balance
- If remaining balance ≤ 0 (quote fully covered), installment creation is blocked
- Cancelled installments are not counted in the total
- Supports multiple partial installments that add up to quote total
- Auto-capping ensures you can never exceed quote total (safe to request any amount)
Output: Installment record with auto-calculated amount, due_date, and installment_ratio.
Update installment status and sales order number.
Status Transitions: All status changes are validated according to the installment status flow.
Automatic Business Rules:
- When all installments are marked as
paid, the quote is automatically set tocompleted
Use Cases:
- Mark installment as
paidwhen payment is received - Mark installment as
cancelledif payment is cancelled or refunded - Link installment to a sales order number for tracking
Input:
{
"quote_uuid": "quote-uuid",
"installment_uuid": "installment-uuid",
"status": "paid",
"salesorder_no": "SO-12345"
}Common Usage:
// Mark as paid (triggers auto-complete check)
{
"quote_uuid": "quote-uuid",
"installment_uuid": "installment-uuid",
"status": "paid"
}
// Link to sales order
{
"quote_uuid": "quote-uuid",
"installment_uuid": "installment-uuid",
"salesorder_no": "SO-12345"
}
// Both at once
{
"quote_uuid": "quote-uuid",
"installment_uuid": "installment-uuid",
"status": "paid",
"salesorder_no": "SO-12345"
}Output: Updated installment record.
Create multiple payment installments for a quote based on a payment schedule. Automates the process of setting up installment plans (e.g., monthly payments over a year).
Workflow:
- Calculates remaining balance (
final_total_quote_amount - existing_pending_paid_total) - Divides remaining balance equally across
interval_numinstallments - Calculates scheduled dates based on
interval_numandtotal_pay_period - Creates all installments with
status=pending - Auto-increments priority for sequential ordering
Automatic Behavior:
- Amount per installment:
remaining_balance / interval_num(equal distribution) - Scheduled dates: First installment scheduled for the next payment period (not current period), then subsequent installments follow at regular intervals. All scheduled on the configured day of month (default: 15th) using
installment_scheduled_daysetting. If the day doesn't exist in a month (e.g., Feb 31), uses the last day of that month. Uses pendulum library for accurate date calculations. - Priority: Auto-increments sequentially for each installment
- Status: All installments created with
pendingstatus
Input:
{
"quote_uuid": "quote-uuid",
"request_uuid": "request-uuid",
"interval_num": 12,
"total_pay_period": 12
}Examples:
12 monthly payments over 1 year:
{
"quote_uuid": "quote-uuid",
"request_uuid": "request-uuid",
"interval_num": 12,
"total_pay_period": 12
}
// Creates 12 installments, scheduled monthly (every 1 month)
// First installment: Next month on 15th (or configured day)
// Last installment: 12 months from now on 15th
// Amount per installment: remaining_balance / 126 bi-monthly payments over 1 year:
{
"quote_uuid": "quote-uuid",
"request_uuid": "request-uuid",
"interval_num": 6,
"total_pay_period": 12
}
// Creates 6 installments, scheduled bi-monthly (every 2 months)
// First installment: 2 months from now on 15th
// Last installment: 12 months from now on 15th
// Amount per installment: remaining_balance / 64 quarterly payments over 2 years:
{
"quote_uuid": "quote-uuid",
"request_uuid": "request-uuid",
"interval_num": 4,
"total_pay_period": 24
}
// Creates 4 installments, scheduled every 6 months
// First installment: 6 months from now on 15th
// Last installment: 24 months from now on 15th
// Amount per installment: remaining_balance / 4Validation Rules:
interval_nummust be > 0total_pay_periodmust be > 0- Remaining balance must be > 0 (quote not already fully covered)
- If any installment creation fails, returns error with details of what was created
Output:
{
"installments": [ /* array of created installment objects */ ],
"total_created": 12,
"installment_amount_per": 833.33,
"total_installment_amount": 10000.00
}Retrieve installments for a quote.
Input:
{
"quote_uuid": "quote-uuid"
}Output: List of installments with payment schedule.
These helpers combine multiple operations and enforce the same business rules described above.
Sets a request to confirmed and creates quotes for a list of providers in one call. Uses provider assignments on the request to generate quote items. Sales rep emails can be supplied via settings (sales_rep_emails mapping).
Confirms a quote, disapproves competing quotes for the same request, and creates a single installment or an installment schedule.
Upload a document related to an RFQ request.
Input:
{
"request_uuid": "request-uuid",
"file_name": "specifications.pdf",
"file_url": "s3://bucket/path/to/file",
"file_type": "application/pdf",
"email": "requester@company.com",
"notes": "Technical specifications"
}Output: File record with metadata.
Retrieve files associated with a request.
Input:
{
"request_uuid": "request-uuid"
}Output: List of uploaded files with download URLs.
Note: Segments are typically managed through the backend admin interface. This tool provides read-only access to segment-contact associations for pricing lookups.
List contacts in a segment by consumer corporation or email.
Input:
{
"consumer_corp_external_id": "CUSTOMER-001",
"email": "buyer@customer.com",
"page_number": 1,
"limit": 50
}Output: List of contacts with their segment associations.
For the detailed 14-step workflow from customer inquiry to final quote confirmation, see DEVELOPMENT_PLAN.md - Complete RFQ to Quote Workflow.
Quick Overview: 0. Find Customer Segment
- Submit RFQ Request
- Lookup Items with End User
- Add Items to Request
- Lookup Provider Items for Each Item
- Lookup Batches for Each Provider Item (Optional)
- Assign Provider Items to Request Items
- Calculate Quote Pricing (NEW - groups by provider/segment, returns discount rules)
- Generate Quotes by Confirmation
- Negotiate with End User
- Apply Discounts with User Confirmation
- Update Quote with Shipping
- Confirm Quote and Generate Installment Plan
- Complete Quote and Process Payment
# Step 0: Find customer segment
segment_contacts = processor.get_segment_contacts(
consumer_corp_external_id="CUSTOMER-001",
email="buyer@customer.com"
)
segment_uuid = segment_contacts[0]["segment_uuid"]
# Step 1-3: Create request and add items
request = processor.submit_rfq_request(
email="buyer@customer.com",
request_title="Q1 Production Materials",
items=[]
)
request_uuid = request["request_uuid"]
processor.add_item_to_rfq_request(
request_uuid=request_uuid,
item={"item_uuid": "item-uuid-1", "qty": 500}
)
# Step 4-6: Assign provider items to request
current_request = processor.get_rfq_request(request_uuid=request_uuid)
updated_items = current_request["items"].copy()
updated_items[0]["provider_items"] = [
{
"provider_corp_external_id": "PROVIDER-001",
"provider_item_uuid": "prov-item-uuid-1",
"batch_no": "LOT-2025-001",
"qty": 500
}
]
processor.update_rfq_request(request_uuid=request_uuid, items=updated_items)
# Step 7: Calculate pricing with batch optimization (NEW)
pricing = processor.calculate_quote_pricing(
request_uuid=request_uuid,
email="buyer@customer.com" # Uses email instead of segment_uuid
)
# Returns grouped pricing structure with items by provider
# {
# "groups": [{
# "provider_corp_external_id": "PROVIDER-001",
# "items": [{
# "provider_item_uuid": "prov-item-uuid-1",
# "item_uuid": "item-uuid-1",
# "batch_no": "LOT-2025-001",
# "qty": 500,
# "price_per_uom": 9.50,
# "guardrail_price_per_uom": 9.50,
# "slow_move_item": true,
# "expired_at": "2026-03-15T00:00:00Z",
# "subtotal": 4750.00
# }],
# "group_subtotal": 4750.00
# }]
# }
# Optional: Get discount prompts separately
discount_prompts = processor.get_discount_prompts(
email="buyer@customer.com",
quote_items=[{
"item_uuid": "item-uuid-1",
"provider_item_uuid": "prov-item-uuid-1"
}]
)
# Step 8-10: Create quote (quote items are auto-created from provider assignments)
quote = processor.create_quote(
request_uuid=request_uuid,
provider_corp_external_id="PROVIDER-001",
sales_rep_email="sales@provider1.com"
)
# Apply discount to the created quote item
full_quote = processor.get_quote(
request_uuid=request_uuid,
quote_uuid=quote["quote_uuid"],
)
first_quote_item_uuid = full_quote["quote_items"][0]["quote_item_uuid"]
processor.update_quote_item(
quote_uuid=quote["quote_uuid"],
quote_item_uuid=first_quote_item_uuid,
request_uuid=request_uuid,
discount_amount=237.50 # 5% slow-move discount (user confirmed)
)
# Step 11: Add shipping
processor.update_quote(
request_uuid=request_uuid,
quote_uuid=quote["quote_uuid"],
shipping_method="express",
shipping_amount=75.00
)
# Step 12-13: Create installment plan and submit
# Installment automatically uses quote's final_total_quote_amount
processor.create_installment(
request_uuid=request_uuid,
quote_uuid=quote["quote_uuid"],
status="pending" # Default status when quote is confirmed
)
processor.update_quote(
request_uuid=request_uuid,
quote_uuid=quote["quote_uuid"],
status="confirmed"
)- LLM-Driven: LLM asks user questions at each step
- Segment-Based: Always identify customer segment first for correct pricing
- Information Provider:
calculate_quote_pricingprovides discount rules; LLM makes decisions with user input - User Confirmation: Apply discounts only after user confirms
- Multi-Provider: Create separate quotes per provider for comparison
User: I need a quote for 500 units of part ABC-123