ApiLogicServer 15.2.3__py3-none-any.whl → 15.2.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. api_logic_server_cli/api_logic_server.py +3 -1
  2. api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +114 -52
  3. api_logic_server_cli/prototypes/base/docs/training/testing.md +95 -9
  4. api_logic_server_cli/prototypes/base/test/api_logic_server_behave/behave_logic_report.py +19 -6
  5. api_logic_server_cli/prototypes/basic_demo/.github/.copilot-instructions.md +744 -0
  6. api_logic_server_cli/prototypes/basic_demo/customizations/logic/declare_logic.py +17 -1
  7. api_logic_server_cli/prototypes/basic_demo/readme.md +13 -5
  8. api_logic_server_cli/prototypes/basic_demo/tutor.md +1436 -0
  9. api_logic_server_cli/prototypes/manager/.github/.copilot-instructions.md +50 -23
  10. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/.github/.copilot-instructions.md +3 -0
  11. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/customizations/logic/declare_logic.py +17 -1
  12. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/docs/training/testing.md +95 -9
  13. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/iteration/logic/declare_logic.py +17 -1
  14. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/logic/declare_logic.py +38 -1
  15. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/features/order_processing.feature +59 -50
  16. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/features/steps/order_processing_steps.py +395 -248
  17. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/behave.log +66 -62
  18. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Carbon_Neutral_Discount_A.log +51 -41
  19. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Change_Order_Customer.log +29 -0
  20. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Change_Product_in_Item.log +35 -0
  21. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Delete_Item_Reduces_Order.log +39 -19
  22. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Exceed_Credit_Limit_Rejec.log +36 -45
  23. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Good_Order_Placed_via_B2B.log +50 -40
  24. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Item_Quantity_Change.log +33 -0
  25. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Multi-Item_Order_via_B2B_.log +67 -0
  26. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Ship_Order_Excludes_from_.log +24 -14
  27. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Transaction_Processing.log +26 -17
  28. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/logs/scenario_logic_logs/Unship_Order_Includes_in_.log +24 -14
  29. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/test/api_logic_server_behave/reports/Behave Logic Report.md +361 -146
  30. api_logic_server_cli/prototypes/manager/system/ApiLogicServer-Internal-Dev/copilot-dev-context.md +270 -2
  31. {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/METADATA +25 -16
  32. {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/RECORD +36 -30
  33. {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/WHEEL +0 -0
  34. {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/entry_points.txt +0 -0
  35. {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/licenses/LICENSE +0 -0
  36. {apilogicserver-15.2.3.dist-info → apilogicserver-15.2.10.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,49 @@
1
+ ---
2
+ title: Copilot Instructions for Manager Workspace
3
+ Description: Manager-level instructions for creating projects
4
+ Source: ApiLogicServer-src/prototypes/manager/.github/.copilot-instructions.md
5
+ Propagation: BLT process → Manager workspace
6
+ Usage: AI assistants read this when user opens Manager workspace
7
+ version: 2.1
8
+ changelog:
9
+ - 2.1 (Oct 2025) - Added "What is the Project Manager?" orientation, friendly collaborative tone, conditional Quick Start for returning users
10
+ - 2.0 (Oct 2025) - OBX improvements, strengthen basic_demo as default path
11
+ - 1.0 (Initial) - Established project creation methods
12
+ ---
13
+
1
14
  # GitHub Copilot Instructions for GenAI-Logic (aka API Logic Server) - Project Manager
2
15
 
3
- ⚠️ **IMPORTANT FOR AI ASSISTANTS**: Always read and follow these instructions when helping users with this project.
16
+ ⚠️ **IMPORTANT FOR AI ASSISTANTS**: Always read and follow these instructions when helping with this project.
17
+
18
+ ## What is the Project Manager?
19
+
20
+ Welcome! This is the **Project Manager** - think of it as your workspace for creating and managing API Logic Server projects.
21
+
22
+ **What's here:**
23
+ - Sample databases you can use to create projects (`samples/dbs/`)
24
+ - Training materials and examples (`system/genai/examples/`)
25
+ - A shared virtual environment for all your projects (`venv/`)
26
+ - A place to create new projects (they'll appear as subdirectories)
4
27
 
5
- The Project Manager contains genai training, a virtual environment, and provides a convenient place to create projects.
28
+ **What you'll do here:**
29
+ Create projects from databases - each project becomes a complete, working microservice with API, Admin UI, and business logic support. Once created, you'll work inside that project to customize and extend it.
6
30
 
7
- > Note: your virtual environment is automatically configured in most cases; verify it with `genai-logic` - it it's not there, activate the `venv` in this project.
31
+ > Note: Your virtual environment is automatically configured in most cases; verify it with `genai-logic` - if it's not there, activate the `venv` in this project.
8
32
 
9
- ## Quick Start for New Users
33
+ ## Quick Start
10
34
 
11
- **ALWAYS start new users with the basic_demo** - it's the best introduction to the system.
35
+ **First time here?** Let's start with the 20-minute basic_demo tutorial - it's the best way to see what GenAI-Logic can do.
12
36
 
13
- It's a small sqlite database, and provides a readme that explores the project, and how to customize it:
37
+ Run this command:
14
38
 
15
39
  ```bash
16
40
  genai-logic create --project_name=basic_demo --db_url=basic_demo
17
41
  ```
42
+
43
+ After it runs, the project will auto-open with its own README and I'll guide you through a hands-on tour.
44
+
45
+ **Already have basic_demo?** Open it and say "Guide me through basic_demo" for the hands-on tour, or ask me what else we can work on.
46
+
18
47
  <br>
19
48
 
20
49
  ## Creating Projects
@@ -27,7 +56,7 @@ There are multiple ways to create projects (aka systems, microservices) - see th
27
56
 
28
57
  ### Method 1: Create Projects from an existing database (Infrastructure Only)
29
58
 
30
- If the user provides a database reference, use the command below. (Note: sqlite sample databases at `samples/dbs`).
59
+ If you have a database reference, I can create a project from it. (Sample databases are in `samples/dbs`).
31
60
 
32
61
  ```bash
33
62
  genai-logic create --project_name=nw --db_url=sqlite:///samples/dbs/nw.sqlite
@@ -35,13 +64,11 @@ genai-logic create --project_name=nw --db_url=sqlite:///samples/dbs/nw.sqlite
35
64
 
36
65
  **Important:** This creates the project structure, API, Admin App, and database models, but **NO business logic rules**.
37
66
 
38
- **To add logic:** Users must add rules separately using:
39
- - Natural language with Copilot/AI assistant in `logic/declare_logic.py`, or
40
- - Manual coding with IDE code completion
67
+ **To add logic:** We can add rules together using natural language in `logic/declare_logic.py`, or you can code them manually with IDE autocomplete.
41
68
 
42
69
  ### Method 2: Create Projects with GenAI (Complete System with Logic)
43
70
 
44
- **Use this when the user provides both database AND business logic requirements.**
71
+ **Use this when you have both database AND business logic requirements.**
45
72
 
46
73
  Describe database and logic in Natural Language in a prompt file.
47
74
 
@@ -58,25 +85,25 @@ genai-logic genai --using=system/genai/examples/genai_demo/genai_demo.prompt --p
58
85
  4. Creates test data
59
86
  5. Creates API, Admin App, and complete project structure
60
87
 
61
- **When to use:** User provides requirements like "Customer balance is sum of orders" or "Check credit limit" - the LLM will generate the corresponding `Rule.sum`, `Rule.constraint`, etc.
88
+ **When to use:** When you have requirements like "Customer balance is sum of orders" or "Check credit limit" - the LLM will generate the corresponding `Rule.sum`, `Rule.constraint`, etc.
62
89
 
63
90
  ### Method 3: Create Projects with new databases (Manual Approach)
64
91
 
65
- If the user provides a description but you want to create the database manually:
92
+ If you provide a description but want to create the database manually:
66
93
 
67
- 1. Create a sqlite database from the description. Be sure to include foreign keys. The system works well with `id INTEGER PRIMARY KEY AUTOINCREMENT`.
68
- 2. Then, use the `genai-logic create` command above.
69
- 3. If logic is provided, translate it using Copilot or `system/genai/learning_requests/logic_bank_api.prompt`.
94
+ 1. I'll create a sqlite database from your description. I'll be sure to include foreign keys. The system works well with `id INTEGER PRIMARY KEY AUTOINCREMENT`.
95
+ 2. Then, I'll use the `genai-logic create` command above.
96
+ 3. If you have logic requirements, we can translate them together using `system/genai/learning_requests/logic_bank_api.prompt`.
70
97
 
71
- ## AI Assistant Guidelines
98
+ ## Working Together
72
99
 
73
- When users ask "what do I do now?" or similar questions:
100
+ When you ask "what should I do now?" or similar:
74
101
 
75
- 1. **Always recommend starting with basic_demo** using the command above
76
- 2. **Use CLI commands** (genai-logic) not Docker scripts for project creation
77
- 3. **Refer to existing sample databases** in `samples/dbs/` for examples
78
- 4. **Point to GenAI examples** in `system/genai/examples/` for AI-generated projects
79
- 5. **Emphasize the 20-minute evaluation workflow** described in the main README
102
+ 1. **I'll recommend starting with basic_demo** using the command above
103
+ 2. **I'll use CLI commands** (genai-logic) not Docker scripts for project creation
104
+ 3. **I'll point you to sample databases** in `samples/dbs/` for examples
105
+ 4. **I'll show you GenAI examples** in `system/genai/examples/` for AI-generated projects
106
+ 5. **We'll follow the 20-minute workflow** described in the main README
80
107
 
81
108
  ## Available Databases
82
109
  - `basic_demo` - Best for first-time users
@@ -26,6 +26,9 @@ This is a **GenAI-Logic (aka API Logic Server) project** - a complete, working m
26
26
 
27
27
  3. **Automatic Business Logic**: All APIs (standard and custom) automatically inherit LogicBank rules without additional code.
28
28
 
29
+ 4. **CLI Commands**: Use `genai-logic --help` to see all available commands. When CLI commands exist for a task (e.g., `add-auth`, `genai-add-mcp-client`, `genai-add-app`), ALWAYS use them instead of manual configuration - they handle all setup correctly.
30
+
31
+
29
32
  ## ⚠️ IMPORTANT: What's Already Built
30
33
 
31
34
  **DO NOT recreate these - they're already working:**
@@ -32,7 +32,23 @@ def declare_logic():
32
32
  from logic.logic_discovery.auto_discovery import discover_logic
33
33
  discover_logic()
34
34
 
35
- # Logic from GenAI: (or, use your IDE w/ code completion)
35
+ # Logic from GenAI
36
+ '''
37
+ You can enter logic in 2 ways:
38
+ 1. Using your IDE and code completion (Rule.)
39
+
40
+ 2. Use your AI Assistant and enter logic in Natural Language, e.g.:
41
+ Create Business Logic for Use Case = Check Credit:
42
+ 1. The Customer's balance is less than the credit limit
43
+ 2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
44
+ 3. The Order's amount_total is the sum of the Item amount
45
+ 4. The Item amount is the quantity * unit_price
46
+ 5. The Item unit_price is copied from the Product unit_price
47
+
48
+ Use case: App Integration
49
+ 1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
50
+ Also, using logic/logic_discovery is a Best Practice - see logic/readme_logic.md
51
+ '''
36
52
  from database.models import Product, Order, Item, Customer, SysEmail
37
53
 
38
54
  # Ensure the customer's balance is less than their credit limit
@@ -32,6 +32,9 @@ Step 5. SUGGEST how to run tests (DO NOT run automatically)
32
32
  - [ ] @when patterns: carbon neutral > multi-item > single-item
33
33
  - [ ] @given patterns: multi-item > single-item
34
34
  - [ ] Use `grep -n "@when('.*with" steps/*.py` to verify order
35
+ - [ ] **Clear scenario language?** (Rule #13: Action-oriented wording)
36
+ - [ ] Use "Order is created" not "Order exists" (shows when rules fire)
37
+ - [ ] Makes test flow obvious: setup → action → verify
35
38
  - [ ] Test data uses timestamps? (Rule #0: Repeatability)
36
39
  - [ ] Security config read? (SECURITY_ENABLED value)
37
40
 
@@ -167,7 +170,7 @@ def step_impl(context, qty):
167
170
  r = requests.patch(url=patch_uri, json=patch_data)
168
171
  ```
169
172
 
170
- ## The 6 Critical Rules (Read FIRST!)
173
+ ## The Critical Rules (Read FIRST!)
171
174
 
172
175
  ### Rule #0: TEST REPEATABILITY (MOST CRITICAL!) ⚠️
173
176
 
@@ -386,18 +389,65 @@ Scenario: Exceed Credit (Constraint FAIL - negative test)
386
389
 
387
390
  **CRITICAL:** Check `logic/declare_logic.py` for custom Python logic affecting calculations (e.g., discounts, adjustments) before writing constraint test expectations!
388
391
 
389
- ### Rule #5: Security Configuration
392
+ ### Rule #5: Security Configuration - JWT Authentication
393
+
394
+ **CRITICAL:** When `SECURITY_ENABLED=True`, tests MUST obtain JWT token and include Authorization header.
395
+
390
396
  ```python
391
- # Read config/default.env FIRST
392
- SECURITY_ENABLED = False # or True
397
+ from pathlib import Path
398
+ import os
399
+ from dotenv import load_dotenv
393
400
 
394
- # Match in test code
395
- if SECURITY_ENABLED == False:
396
- headers = {} # Empty
397
- else:
398
- headers = test_utils.login()
401
+ # Load config to check SECURITY_ENABLED
402
+ config_path = Path(__file__).parent.parent.parent.parent.parent / 'config' / 'default.env'
403
+ load_dotenv(config_path)
404
+
405
+ # Cache for auth token (obtained once per test session)
406
+ _auth_token = None
407
+
408
+ def get_auth_token():
409
+ """Login and get JWT token if security is enabled"""
410
+ global _auth_token
411
+
412
+ if _auth_token is not None:
413
+ return _auth_token
414
+
415
+ # Login with default admin credentials
416
+ login_url = f'{BASE_URL}/api/auth/login'
417
+ login_data = {'username': 'admin', 'password': 'p'}
418
+
419
+ response = requests.post(login_url, json=login_data)
420
+ if response.status_code == 200:
421
+ _auth_token = response.json().get('access_token')
422
+ return _auth_token
423
+ else:
424
+ raise Exception(f"Login failed: {response.status_code}")
425
+
426
+ def get_headers():
427
+ """Get headers including auth token if security is enabled"""
428
+ security_enabled = os.getenv('SECURITY_ENABLED', 'false').lower() not in ['false', 'no']
429
+
430
+ headers = {'Content-Type': 'application/json'}
431
+
432
+ if security_enabled:
433
+ token = get_auth_token()
434
+ if token:
435
+ headers['Authorization'] = f'Bearer {token}'
436
+
437
+ return headers
438
+
439
+ # Use in ALL API requests
440
+ response = requests.post(url=api_url, json=data, headers=get_headers())
441
+ response = requests.get(url=api_url, headers=get_headers())
442
+ response = requests.patch(url=api_url, json=data, headers=get_headers())
399
443
  ```
400
444
 
445
+ **Key Points:**
446
+ - Tests DO NOT automatically include auth - you must code the pattern above
447
+ - Token is cached globally to avoid repeated login calls
448
+ - Works for both `SECURITY_ENABLED=True` and `SECURITY_ENABLED=False`
449
+ - See complete example: `test/api_logic_server_behave/features/steps/order_processing_steps.py`
450
+
401
451
  ### Rule #6: Logic Logging
402
452
  ```python
403
453
  @when('Good Order Placed')
@@ -535,6 +585,40 @@ def step_impl(context):
535
585
  return # Skip gracefully
536
586
  ```
537
587
 
588
+ ### Rule #13: Use Clear, Action-Oriented Scenario Language ⚠️ NEW
589
+ ```gherkin
590
+ # ❌ AMBIGUOUS - "exists" is passive, doesn't show when balance changes
591
+ Scenario: Ship Order Excludes from Balance
592
+ Given Customer "Charlie" with balance 0 and credit limit 2000
593
+ And Order exists for "Charlie" with 2 Widget
594
+ When Order is shipped
595
+ Then Customer balance should be 0
596
+
597
+ # Question: How can Charlie have balance 0 AND an order for widgets?
598
+ # Answer: The order EXISTS at test start, but balance calculation is unclear
599
+
600
+ # ✅ CLEAR - "is created" shows action that triggers rule
601
+ Scenario: Ship Order Excludes from Balance
602
+ Given Customer "Charlie" with balance 0 and credit limit 2000
603
+ And Order is created for "Charlie" with 2 Widget # Action! Balance becomes 180
604
+ When Order is shipped # Action! Balance drops to 0
605
+ Then Customer balance should be 0 # Verification
606
+
607
+ # Now it's obvious:
608
+ # 1. Customer starts with balance 0
609
+ # 2. Creating unshipped order → rule fires → balance becomes 180
610
+ # 3. Shipping order → WHERE clause excludes it → balance drops to 0
611
+
612
+ # More examples:
613
+ # ❌ "And Shipped order exists for..."
614
+ # ✅ "And Shipped order is created for..."
615
+
616
+ # Why this matters:
617
+ # - Shows WHEN rules fire (on creation, not just existence)
618
+ # - Makes test flow obvious (setup → action → verify)
619
+ # - Clarifies that declarative rules execute automatically on changes
620
+ ```
621
+
538
622
  ## Complete Phase 2 Example
539
623
 
540
624
  ### .feature File
@@ -631,6 +715,8 @@ def step_impl(context, expected):
631
715
  | **"balance: expected 570, got 0.0"** | **Step ordering issue (Rule #0.5)! Multi-item pattern after single-item** |
632
716
  | **"context has no attribute 'item_id'"** | **Step ordering issue! Specific pattern defined after general pattern** |
633
717
  | "Order created but no items" | Check if wrong step matched (print debug in step) |
718
+ | **"expected 810, got 900"** (carbon neutral) | **Rule #10: Verify actual database values! Check product flags with SQL first** |
719
+ | **"How can balance be 0 with an order?"** | **Rule #13: Use "is created" not "exists" - shows when rules fire** |
634
720
 
635
721
  ### Debugging Step Ordering Issues
636
722
 
@@ -32,7 +32,23 @@ def declare_logic():
32
32
  from logic.logic_discovery.auto_discovery import discover_logic
33
33
  discover_logic()
34
34
 
35
- # Logic from GenAI: (or, use your IDE w/ code completion)
35
+ # Logic from GenAI
36
+ '''
37
+ You can enter logic in 2 ways:
38
+ 1. Using your IDE and code completion (Rule.)
39
+
40
+ 2. Use your AI Assistant and enter logic in Natural Language, e.g.:
41
+ Create Business Logic for Use Case = Check Credit:
42
+ 1. The Customer's balance is less than the credit limit
43
+ 2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
44
+ 3. The Order's amount_total is the sum of the Item amount
45
+ 4. The Item amount is the quantity * unit_price
46
+ 5. The Item unit_price is copied from the Product unit_price
47
+
48
+ Use case: App Integration
49
+ 1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
50
+ Also, using logic/logic_discovery is a Best Practice - see logic/readme_logic.md
51
+ '''
36
52
  from database.models import Product, Order, Item, Customer
37
53
 
38
54
  # Ensure the customer's balance is less than their credit limit
@@ -31,6 +31,43 @@ def declare_logic():
31
31
  from logic.logic_discovery.auto_discovery import discover_logic
32
32
  discover_logic()
33
33
 
34
+ # Logic from GenAI: (or, use your IDE w/ code completion)
35
+ from database.models import Product, Order, Item, Customer
36
+
37
+
38
+
39
+ # ************ Python Customization Example ****************
40
+
41
+ # Send order details to Kafka if order is shipped.
42
+ # Formeraly, we had this rule:
43
+ # Rule.after_flush_row_event(on_class=Order, calling=kafka_producer.send_row_to_kafka, if_condition=lambda row: row.date_shipped is not None, with_args={'topic': 'order_shipping'})
44
+ # If the integration were more complex, we could use Python, like this:
45
+ #als: Demonstrate that logic == Rules + Python (for extensibility)
46
+
47
+ def send_order_to_shipping(row: models.Order, old_row: models.Order, logic_row: LogicRow):
48
+ """ #als: Send Kafka message formatted by OrderShipping RowDictMapper
49
+
50
+ Format row per shipping requirements, and send (e.g., a message)
51
+
52
+ NB: the after_flush event makes Order.Id avaible.
53
+
54
+ Args:
55
+ row (models.Order): inserted Order
56
+ old_row (models.Order): n/a
57
+ logic_row (LogicRow): bundles curr/old row, with ins/upd/dlt logic
58
+ """
59
+ if logic_row.is_inserted():
60
+ kafka_producer.send_kafka_message(logic_row=logic_row,
61
+ row_dict_mapper=OrderShipping,
62
+ kafka_topic="order_shipping",
63
+ kafka_key=str(row.id),
64
+ msg="Sending Order to Shipping")
65
+
66
+ Rule.after_flush_row_event(on_class=models.Order, calling=send_order_to_shipping) # see above
67
+
68
+ # End Logic from GenAI
69
+
70
+
34
71
  def handle_all(logic_row: LogicRow): # #als: TIME / DATE STAMPING, OPTIMISTIC LOCKING
35
72
  """
36
73
  This is generic - executed for all classes.
@@ -53,7 +90,7 @@ def declare_logic():
53
90
  Grant.process_updates(logic_row=logic_row)
54
91
 
55
92
  did_stamping = False
56
- if enable_stamping := False: # #als: DATE / USER STAMPING
93
+ if enable_stamping := True: # #als: DATE / USER STAMPING
57
94
  row = logic_row.row
58
95
  if logic_row.ins_upd_dlt == "ins" and hasattr(row, "CreatedOn"):
59
96
  row.CreatedOn = datetime.datetime.now()
@@ -1,72 +1,81 @@
1
1
  Feature: Order Processing with Business Logic
2
2
 
3
- # Phase 2: CREATE using OrderB2B custom API
4
- # Phase 1: UPDATE/DELETE using CRUD for granular rule testing
3
+ # Tests all declarative rules:
4
+ # 1. Customer.balance = sum(Order.amount_total) WHERE date_shipped is None
5
+ # 2. Order.amount_total = sum(Item.amount)
6
+ # 3. Item.amount = quantity * unit_price (with 10% carbon neutral discount for qty >= 10)
7
+ # 4. Item.unit_price copied from Product.unit_price
8
+ # 5. Customer.balance <= credit_limit constraint
9
+ # 6. Kafka integration when order shipped
5
10
 
6
11
  Scenario: Good Order Placed via B2B API
7
- Given Customer "Alice" with balance 0 and credit limit 1000
12
+ Given Customer "Alice" with balance 0 and credit limit 5000
8
13
  When B2B order placed for "Alice" with 5 Widget
9
14
  Then Customer balance should be 450
10
15
  And Order amount_total should be 450
11
- And Order created successfully
16
+ And Item amount should be 450
17
+ And Item unit_price should be 90
12
18
 
13
- Scenario: Item Quantity Update Recalculates Amounts
14
- Given Customer "Bob" with balance 0 and credit limit 2000
15
- And Order exists for "Bob" with 5 Widget
19
+ Scenario: Multi-Item Order via B2B API
20
+ Given Customer "Bob" with balance 0 and credit limit 3000
21
+ When B2B order placed for "Bob" with 3 Widget and 2 Gadget
22
+ Then Customer balance should be 570
23
+ And Order amount_total should be 570
24
+
25
+ Scenario: Carbon Neutral Discount Applied
26
+ Given Customer "Diana" with balance 0 and credit limit 5000
27
+ When B2B order placed for "Diana" with 10 carbon neutral Gadget
28
+ Then Customer balance should be 1350
29
+ And Item amount should be 1350
30
+
31
+ Scenario: Item Quantity Change
32
+ Given Customer "Charlie" with balance 0 and credit limit 2000
33
+ And Order is created for "Charlie" with 5 Widget
16
34
  When Item quantity changed to 10
17
35
  Then Item amount should be 900
18
36
  And Order amount_total should be 900
19
37
  And Customer balance should be 900
20
38
 
21
- Scenario: Change Order Customer Adjusts Both Balances
22
- Given Customer "Charlie" with balance 0 and credit limit 1500
23
- And Customer "Diana" with balance 0 and credit limit 2000
24
- And Order exists for "Charlie" with 2 Gadget
25
- When Order customer changed to "Diana"
26
- Then Customer "Charlie" balance should be 0
27
- And Customer "Diana" balance should be 300
39
+ Scenario: Change Product in Item
40
+ Given Customer "Alice" with balance 0 and credit limit 5000
41
+ And Order is created for "Alice" with 5 Widget
42
+ When Item product changed to "Gadget"
43
+ Then Item unit_price should be 150
44
+ And Item amount should be 750
45
+ And Order amount_total should be 750
46
+ And Customer balance should be 750
28
47
 
29
- Scenario: Delete Item Reduces Order Total and Customer Balance
30
- Given Customer "TestCustomer" with balance 0 and credit limit 3000
31
- And Order exists for "TestCustomer" with 3 Widget and 2 Gadget
32
- When First item deleted
48
+ Scenario: Delete Item Reduces Order
49
+ Given Customer "Bob" with balance 0 and credit limit 3000
50
+ And Order is created for "Bob" with 3 Widget and 2 Gadget
51
+ When First item is deleted
33
52
  Then Order amount_total should be 300
34
53
  And Customer balance should be 300
35
54
 
36
- Scenario: Ship Order Excludes from Balance (WHERE exclude)
37
- Given Customer "ShipTest" with balance 0 and credit limit 5000
38
- And Order exists for "ShipTest" with 10 Widget
55
+ Scenario: Change Order Customer
56
+ Given Customer "Alice" with balance 0 and credit limit 5000
57
+ And Customer "Bob" with balance 0 and credit limit 3000
58
+ And Order is created for "Alice" with 5 Widget
59
+ When Order customer changed to "Bob"
60
+ Then Customer "Alice" balance should be 0
61
+ And Customer "Bob" balance should be 450
62
+
63
+ Scenario: Ship Order Excludes from Balance
64
+ Given Customer "Charlie" with balance 0 and credit limit 2000
65
+ And Order is created for "Charlie" with 2 Widget
39
66
  When Order is shipped
40
67
  Then Customer balance should be 0
68
+ And Order amount_total should be 180
41
69
 
42
- Scenario: Unship Order Includes in Balance (WHERE include)
43
- Given Customer "UnshipTest" with balance 0 and credit limit 5000
44
- And Shipped order exists for "UnshipTest" with 5 Gadget
70
+ Scenario: Unship Order Includes in Balance
71
+ Given Customer "Diana" with balance 0 and credit limit 5000
72
+ And Shipped order is created for "Diana" with 3 Gadget
45
73
  When Order is unshipped
46
- Then Customer balance should be 750
47
-
48
- Scenario: Exceed Credit Limit Rejected (Constraint FAIL)
49
- Given Customer "LimitTest" with balance 0 and credit limit 500
50
- When B2B order placed for "LimitTest" with 10 Gadget
51
- Then Order creation should fail
52
- And Error message should contain "credit limit"
53
-
54
- Scenario: Carbon Neutral Discount Applied (Custom Logic)
55
- Given Customer "GreenBuyer" with balance 0 and credit limit 2000
56
- When B2B order placed for "GreenBuyer" with 10 carbon neutral Gadget
57
- Then Item amount should be 1350
58
- And Order amount_total should be 1350
59
- And Customer balance should be 1350
60
-
61
- Scenario: Product Unit Price Copied to Item
62
- Given Customer "PriceCopy" with balance 0 and credit limit 3000
63
- When B2B order placed for "PriceCopy" with 1 Green
64
- Then Item unit_price should be 109
74
+ Then Customer balance should be 450
75
+ And Order amount_total should be 450
65
76
 
66
- Scenario: Change Product Updates Unit Price (FK Change)
67
- Given Customer "ProductChange" with balance 0 and credit limit 5000
68
- And Order exists for "ProductChange" with 2 Widget
69
- When Item product changed to "Gadget"
70
- Then Item unit_price should be 150
71
- And Item amount should be 300
72
- And Order amount_total should be 300
77
+ Scenario: Exceed Credit Limit Rejected
78
+ Given Customer "Silent" with balance 0 and credit limit 1000
79
+ When B2B order placed for "Silent" with 20 Widget
80
+ Then Order should be rejected
81
+ And Error message should contain "exceeds credit limit"