ApiLogicServer 14.3.0__py3-none-any.whl → 14.3.7__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 (55) hide show
  1. {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/METADATA +2 -2
  2. {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/RECORD +46 -43
  3. api_logic_server_cli/api_logic_server.py +2 -1
  4. api_logic_server_cli/api_logic_server_info.yaml +3 -3
  5. api_logic_server_cli/cli.py +5 -2
  6. api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
  7. api_logic_server_cli/create_from_model/ont_build.py +1 -1
  8. api_logic_server_cli/genai/genai.py +4 -0
  9. api_logic_server_cli/genai/genai_svcs.py +2 -0
  10. api_logic_server_cli/manager.py +20 -16
  11. api_logic_server_cli/prototypes/base/api/system/expression_parser.py +10 -4
  12. api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +32 -8
  13. api_logic_server_cli/prototypes/base/integration/system/RowDictMapper.py +33 -16
  14. api_logic_server_cli/prototypes/base/logic/declare_logic.py +1 -0
  15. api_logic_server_cli/prototypes/base/logic/load_verify_rules.py +2 -1
  16. api_logic_server_cli/prototypes/genai_demo/api/customize_api.py +9 -11
  17. api_logic_server_cli/prototypes/genai_demo/database/.DS_Store +0 -0
  18. api_logic_server_cli/prototypes/genai_demo/database/db.sqlite +0 -0
  19. api_logic_server_cli/prototypes/genai_demo/database/models.py +52 -42
  20. api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/OrderB2B.py +4 -6
  21. api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/__pycache__/OrderB2B.cpython-312.pyc +0 -0
  22. api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/row_dict_maps_readme.md +3 -0
  23. api_logic_server_cli/prototypes/genai_demo/logic/__pycache__/declare_logic.cpython-312.pyc +0 -0
  24. api_logic_server_cli/prototypes/genai_demo/logic/__pycache__/load_verify_rules.cpython-312.pyc +0 -0
  25. api_logic_server_cli/prototypes/genai_demo/logic/declare_logic.py +57 -69
  26. api_logic_server_cli/prototypes/genai_demo/logic/load_verify_rules.py +216 -0
  27. api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/__init__.cpython-312.pyc +0 -0
  28. api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/auto_discovery.cpython-312.pyc +0 -0
  29. api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/error_testing.cpython-312.pyc +0 -0
  30. api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/auto_discovery.py +52 -0
  31. api_logic_server_cli/prototypes/genai_demo/logic/readme_declare_logic.md +172 -0
  32. api_logic_server_cli/prototypes/genai_demo/security/__pycache__/declare_security.cpython-312.pyc +0 -0
  33. api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +86 -53
  34. api_logic_server_cli/prototypes/manager/.vscode/launch.json +1 -1
  35. api_logic_server_cli/prototypes/manager/README.md +1 -1
  36. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.prompt +4 -1
  37. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +15 -8
  38. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt +3 -0
  39. api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/readme.md +58 -5
  40. api_logic_server_cli/prototypes/manager/system/genai/learning_requests/logic_bank_api.prompt +15 -1
  41. api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/__pycache__/codegen.cpython-312.pyc +0 -0
  42. api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/codegen.py +2 -1
  43. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/__pycache__/copilot_models.cpython-312.pyc +0 -0
  44. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/__pycache__/sample_ai_models.cpython-312.pyc +0 -0
  45. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai.chatgpt +0 -16
  46. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai.sql +0 -66
  47. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai.sqlite +0 -0
  48. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_items.sqlite +0 -0
  49. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_models.py +0 -156
  50. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_models.sqlite +0 -0
  51. api_logic_server_cli/prototypes/genai_demo/logic/cocktail-napkin.jpg +0 -0
  52. {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/LICENSE +0 -0
  53. {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/WHEEL +0 -0
  54. {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/entry_points.txt +0 -0
  55. {ApiLogicServer-14.3.0.dist-info → ApiLogicServer-14.3.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,172 @@
1
+ This describes how to use Logic; for more information, [see here](https://apilogicserver.github.io/Docs/Logic-Why).
2
+
3
+ > Key Takeway - Logic: Multi-table Derivation and Constraint Rules, Extensible with Python
4
+ <br>Rules are:
5
+ <br>1. **Declared** in your IDE - 40X more concise
6
+ <br>2. **Activated** on server start
7
+ <br>3. **Executed** - *automatically* - on updates (using SQLAlchemy events)
8
+ <br>4. **Debugged** in your IDE, and with the console log
9
+ <br>For more on rules, [click here](https://apilogicserver.github.io/Docs/Logic-Why/).
10
+
11
+ &nbsp;
12
+
13
+ ## Examples
14
+ Examples from tutorial project:
15
+ * Examples drawn from [tutorial project](https://github.com/ApiLogicServer/demo/blob/main/logic/declare_logic.py)
16
+ * Use Shift + "." to view in project mode
17
+
18
+ You can [find the rules here](https://apilogicserver.github.io/Docs/Logic). Below, we explore the syntax of 3 typical rules.
19
+
20
+ &nbsp;
21
+
22
+ ### 1. Multi-Table Derivations
23
+
24
+ This declares the Customer.Balance as the sum of the unshipped Order.AmountTotal:
25
+
26
+ ```python
27
+ Rule.sum(derive=models.Customer.Balance,
28
+ as_sum_of=models.Order.AmountTotal,
29
+ where=lambda row: row.ShippedDate is None)
30
+ ```
31
+ It means the rule engine **watches** for these changes:
32
+ * Order inserted/deleted, or
33
+ * AmountTotal or ShippedDate or CustomerID changes
34
+
35
+ Iff changes are detected, the engine **reacts** by *adjusting* the Customer.Balance. SQLs are [optimized](#declarative-logic-important-notes).
36
+
37
+ This would **chain** to check the Customers' Constraint rule, described below.
38
+
39
+ &nbsp;
40
+
41
+ ### 2. Constraints: lambda or function
42
+
43
+ Constraints are multi-field conditions which must be true for transactions to succeed (else an exception is raised). You can express the condition as a lambda or a function:
44
+
45
+ **As a lambda:**
46
+ ```python
47
+ Rule.constraint(validate=models.Customer,
48
+ as_condition=lambda row: row.Balance <= row.CreditLimit, # parent references are supported
49
+ error_msg="balance ({row.Balance}) exceeds credit ({row.CreditLimit})")
50
+ ```
51
+
52
+ **Or, as a function:**
53
+ ```python
54
+ def check_balance(row: models.Customer, old_row: models.Customer, logic_row: LogicRow):
55
+ if logic_row.ins_upd_dlt != "dlt": # see also: logic_row.old_row
56
+ return row.Balance <= row.CreditLimit
57
+ else:
58
+ return True
59
+
60
+ Rule.constraint(validate=models.Customer,
61
+ calling=check_balance,
62
+ error_msg=f"balance ({row.Balance}) exceeds credit ({row.CreditLimit})")
63
+ ```
64
+
65
+ &nbsp;
66
+
67
+ ### 3. Row Events: Extensible with Python
68
+
69
+ Events are procedural Python code, providing extensibility for declarative rules:
70
+ ```python
71
+ def congratulate_sales_rep(row: models.Order, old_row: models.Order, logic_row: LogicRow):
72
+ pass # event code here - sending email, messages, etc.
73
+
74
+ Rule.commit_row_event(on_class=models.Order, calling=congratulate_sales_rep)
75
+ ```
76
+ Note there are multiple kinds of events, so you can control whether they run before or after rule execution. For more information, [see here](https://apilogicserver.github.io/Docs/Logic-Type-Constraint).
77
+
78
+ &nbsp;
79
+
80
+ ## LogicRow: old_row, verb, etc
81
+
82
+ A key argument to functions is `logic_row`:
83
+
84
+ * **Wraps row and old_row,** plus methods for insert, update and delete - rule enforcement
85
+
86
+ * **Additional instance variables:** ins_upd_dlt, nest_level, session, etc.
87
+
88
+ * **Helper Methods:** are_attributes_changed, set_same_named_attributes, get_parent_logic_row(role_name), get_derived_attributes, log, is_inserted, etc
89
+
90
+ Here is an example:
91
+
92
+ ```python
93
+ """
94
+ STATE TRANSITION LOGIC, using old_row
95
+ """
96
+ def raise_over_20_percent(row: models.Employee, old_row: models.Employee, logic_row: LogicRow):
97
+ if logic_row.ins_upd_dlt == "upd" and row.Salary > old_row.Salary:
98
+ return row.Salary >= Decimal('1.20') * old_row.Salary
99
+ else:
100
+ return True
101
+
102
+ Rule.constraint(validate=models.Employee,
103
+ calling=raise_over_20_percent,
104
+ error_msg="{row.LastName} needs a more meaningful raise")
105
+ ```
106
+
107
+ Note the `log` method, which enables you to write row/old_row into the log with a short message:
108
+
109
+ ```python
110
+ logic_row.log("no manager for this order's salesrep")
111
+ ```
112
+
113
+ &nbsp;
114
+
115
+ ## Declarative Logic: Important Notes
116
+
117
+ Logic *declarative*, which differs from conventional *procedural* logic:
118
+
119
+ 1. **Automatic Invocation:** you don't call the rules; they execute in response to updates (via SQLAlchemy events).
120
+
121
+ 2. **Automatic Ordering:** you don't order the rules; execution order is based on system-discovered depencencies.
122
+
123
+ 3. **Automatic Optimizations:** logic is optimized to reduce SQLs.
124
+
125
+ * Rule execution is *pruned* if dependent attributes are not altered
126
+ * SQL is optimized, e.g., `sum` rules operate by *adjustment*, not expensive SQL `select sum`
127
+
128
+ These simplify maintenance / iteration: you can be sure new logic is always called, in the correct order.
129
+
130
+ &nbsp;
131
+
132
+ ## Debugging
133
+
134
+ Debug rules using **system-generated logic log** and your **IDE debugger**; for more information, [see here](https://apilogicserver.github.io/Docs/Logic-Use).
135
+
136
+ &nbsp;
137
+
138
+ ### Using the debugger
139
+
140
+ Use the debugger as shown below. Note you can stop in lambda functions.
141
+
142
+ ![Logic Debugger](https://apilogicserver.github.io/Docs/images/logic/logic-debug.png)
143
+
144
+ &nbsp;
145
+
146
+ ### Logic Log
147
+
148
+ Logging is performed using standard Python logging, with a logger named `logic_logger`. Use `info` for tracing, and `debug` for additional information (e.g., all declared rules are logged).
149
+
150
+ In addition, the system logs all rules that fire, to aid in debugging. Referring the the screen shot above:
151
+
152
+ * Each line represents a rule execution, showing row state (old/new values), and the _{reason}_ that caused the update (e.g., client, sum adjustment)
153
+ * Log indention shows multi-table chaining
154
+
155
+ &nbsp;
156
+
157
+ ## How Logic works
158
+
159
+ *Activation* occurs in `api_logic_server_run.py`:
160
+ ```python
161
+ LogicBank.activate(session=session, activator=declare_logic, constraint_event=constraint_handler)
162
+ ```
163
+
164
+ This installs the rule engine as a SQLAlchemy event listener (`before_flush`). So, Logic *runs* automatically, in response to transaction commits (typically via the API).
165
+
166
+ Rules plug into SQLAlchemy events, and execute as follows:
167
+
168
+ | Logic Phase | Why It Matters |
169
+ |:-----------------------------|:---------------------|
170
+ | **Watch** for changes at the attribute level | Performance - Automatic Attribute-level Pruning |
171
+ | **React** by recomputing value | Ensures Reuse - Invocation is automatic<br>Derivations are optimized (e.g. *adjustment updates* - not aggregate queries) |
172
+ | **Chain** to other referencing data | Simplifies Maintenance - ordering is automatic<br>Multi-table logic automation |
@@ -1,109 +1,142 @@
1
1
  about:
2
- date: January 27, 2024 16:41:35
3
- merged:
4
- at: January 28, 2024 13:17:27
5
- new_attributes: 'Product.CarbonNeutral '
6
- new_resources: ''
7
- new_tab_groups: ''
2
+ date: February 02, 2025 11:44:16
8
3
  recent_changes: works with modified safrs-react-admin
9
4
  version: 0.0.0
10
5
  api_root: '{http_type}://{swagger_host}:{port}/{api}'
11
- authentication:
12
- endpoint: '{http_type}://{swagger_host}:{port}/api/auth/login'
6
+ authentication: '{system-default}'
13
7
  info:
14
8
  number_relationships: 3
15
9
  number_tables: 4
10
+ info_toggle_checked: true
16
11
  resources:
17
12
  Customer:
18
13
  attributes:
19
- - label: ' Customer Name*'
20
- name: CustomerName
21
- required: true
14
+ - label: ' name*'
15
+ name: name
22
16
  search: true
23
17
  sort: true
24
- - name: Address
25
- - name: Phone
26
- - name: Balance
27
- - name: CreditLimit
28
- required: true
29
- - name: CustomerID
18
+ - name: balance
19
+ type: DECIMAL
20
+ - name: credit_limit
21
+ type: DECIMAL
22
+ - name: id
23
+ description: Represents a customer in the system with unique name, balance, and
24
+ credit limit attributes.
25
+ info_list: Represents a customer in the system with unique name, balance, and
26
+ credit limit attributes.
30
27
  tab_groups:
31
28
  - direction: tomany
32
29
  fks:
33
- - CustomerID
30
+ - customer_id
34
31
  name: OrderList
35
32
  resource: Order
36
33
  type: Customer
37
- user_key: CustomerName
34
+ user_key: name
38
35
  Item:
39
36
  attributes:
40
- - label: ' Item I D*'
41
- name: ItemID
37
+ - label: ' id*'
38
+ name: id
42
39
  search: true
43
40
  sort: true
44
- - name: OrderID
45
- - name: ProductID
46
- - name: Quantity
41
+ - name: order_id
42
+ - name: product_id
43
+ - name: quantity
47
44
  required: true
48
- - name: UnitPrice
49
- - name: Amount
45
+ - name: unit_price
46
+ type: DECIMAL
47
+ - name: amount
48
+ type: DECIMAL
49
+ description: Represents an item in an order, including quantity and pricing details.
50
+ info_list: Represents an item in an order, including quantity and pricing details.
50
51
  tab_groups:
51
52
  - direction: toone
52
53
  fks:
53
- - OrderID
54
- name: Order
54
+ - order_id
55
+ name: order
55
56
  resource: Order
56
57
  - direction: toone
57
58
  fks:
58
- - ProductID
59
- name: Product
59
+ - product_id
60
+ name: product
60
61
  resource: Product
61
62
  type: Item
62
- user_key: ItemID
63
+ user_key: id
63
64
  Order:
64
65
  attributes:
65
- - label: ' Order I D*'
66
- name: OrderID
66
+ - label: ' id*'
67
+ name: id
67
68
  search: true
68
69
  sort: true
69
- - name: CustomerID
70
- - name: OrderDate
71
- - name: Notes
72
- - name: ShipDate
73
- - name: AmountTotal
70
+ - name: customer_id
71
+ - name: amount_total
72
+ type: DECIMAL
73
+ - name: notes
74
+ - name: date_shipped
75
+ type: DATE
76
+ description: Represents an order made by a customer, including a notes field.
77
+ info_list: Represents an order made by a customer, including a notes field.
74
78
  tab_groups:
75
79
  - direction: tomany
76
80
  fks:
77
- - OrderID
81
+ - order_id
78
82
  name: ItemList
79
83
  resource: Item
80
84
  - direction: toone
81
85
  fks:
82
- - CustomerID
83
- name: Customer
86
+ - customer_id
87
+ name: customer
84
88
  resource: Customer
85
89
  type: Order
86
- user_key: OrderID
90
+ user_key: id
87
91
  Product:
88
92
  attributes:
89
- - label: ' Product Name*'
90
- name: ProductName
91
- required: true
93
+ - label: ' name*'
94
+ name: name
92
95
  search: true
93
96
  sort: true
94
- - name: UnitPrice
95
- required: true
96
- - name: ProductID
97
- - name: CarbonNeutral
98
- type: Boolean
97
+ - name: unit_price
98
+ type: DECIMAL
99
+ - name: carbon_neutral
100
+ type: BOOLEAN
101
+ - name: id
102
+ description: Represents a product available in the system with a unit price.
103
+ info_list: Represents a product available in the system with a unit price.
99
104
  tab_groups:
100
105
  - direction: tomany
101
106
  fks:
102
- - ProductID
107
+ - product_id
103
108
  name: ItemList
104
109
  resource: Item
105
110
  type: Product
106
- user_key: ProductName
111
+ user_key: name
107
112
  settings:
108
- HomeJS: http://localhost:5656/admin-app/home.js
113
+ HomeJS: /admin-app/home.js
109
114
  max_list_columns: 8
115
+ style_guide:
116
+ applicationLocales:
117
+ - en
118
+ - es
119
+ currency_symbol: $
120
+ currency_symbol_position: left
121
+ date_format: LL
122
+ decimal_max: '1000000000'
123
+ decimal_min: '0'
124
+ decimal_separator: .
125
+ detail_mode: tab
126
+ edit_on_mode: dblclick
127
+ exclude_listpicker: false
128
+ include_translation: 'false'
129
+ keycloak_client_id: alsclient
130
+ keycloak_realm: kcals
131
+ keycloak_url: http://localhost:8080
132
+ locale: en
133
+ max_decimal_digits: '4'
134
+ min_decimal_digits: '2'
135
+ new_mode: dialog
136
+ pick_style: list
137
+ row_height: small,
138
+ serviceType: OntimizeEE
139
+ startSessionPath: /auth/login
140
+ style: light
141
+ thousand_separator: ','
142
+ use_keycloak: 'false'
@@ -730,7 +730,7 @@
730
730
  "id": "runProjectName",
731
731
  "type": "promptString",
732
732
  "description": "Project Name (folder) to run",
733
- "default": "samples/nw"
733
+ "default": "genai_demo"
734
734
  },
735
735
  {
736
736
  "id": "inputGenaiProjectName",
@@ -109,7 +109,7 @@ als genai --using=system/genai/examples/genai_demo/genai_demo.prompt --project-n
109
109
 
110
110
 
111
111
  ```bash
112
- als genai --repaired-response=system/genai/examples/genai_demo/genai_demo_iteration/005_create_db_models.response-example --project-name=genai_demo
112
+ als genai --repaired-response=system/genai/examples/genai_demo/genai_demo.response_example --project-name=genai_demo
113
113
  ```
114
114
 
115
115
  Verify it's operating properly:
@@ -4,13 +4,16 @@ Include a notes field for orders.
4
4
 
5
5
  Use LogicBank to enforce business logic.
6
6
 
7
- Use case: Check Credit
7
+ Use case: Check Credit
8
8
  1. The Customer's balance is less than the credit limit
9
9
  2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
10
10
  3. The Order's amount_total is the sum of the Item amount
11
11
  4. The Item amount is the quantity * unit_price
12
12
  5. The Item unit_price is copied from the Product unit_price
13
13
 
14
+ Use case: App Integration
15
+ 1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
16
+
14
17
  Ensure each customer has a unique name.
15
18
 
16
19
  Ensure each Item quantity is not null.
@@ -60,25 +60,32 @@
60
60
  "use_case": "Store the Item.unit_price as a copy from Product.unit_price",
61
61
  "entity": "Item",
62
62
  "code": "Rule.copy(derive=Item.unit_price, from_parent=Product.unit_price)"
63
+ },
64
+ {
65
+ "name": "Order Kafka Integration",
66
+ "description": "Sends the order to Kafka topic 'order_shipping' if the date shipped is not None.",
67
+ "use_case": "App Integration",
68
+ "entity": "Order",
69
+ "code": "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\"})"
63
70
  }
64
71
  ],
65
72
  "test_data": "Insert test data into the tables with values compatible with the derived logic.",
66
73
  "test_data_rows": [
67
74
  {
68
75
  "test_data_row_variable": "test_customer_1",
69
- "code": "test_customer_1 = Customer(name='Customer 1', balance=300, credit_limit=1000)"
76
+ "code": "test_customer_1 = Customer(name='Customer 1', balance=150, credit_limit=1000)"
70
77
  },
71
78
  {
72
79
  "test_data_row_variable": "test_customer_2",
73
- "code": "test_customer_2 = Customer(name='Customer 2', balance=500, credit_limit=750)"
80
+ "code": "test_customer_2 = Customer(name='Customer 2', balance=275, credit_limit=750)"
74
81
  },
75
82
  {
76
83
  "test_data_row_variable": "test_customer_3",
77
- "code": "test_customer_3 = Customer(name='Customer 3', balance=0, credit_limit=1500)"
84
+ "code": "test_customer_3 = Customer(name='Customer 3', balance=150, credit_limit=1500)"
78
85
  },
79
86
  {
80
87
  "test_data_row_variable": "test_customer_4",
81
- "code": "test_customer_4 = Customer(name='Customer 4', balance=200, credit_limit=1200)"
88
+ "code": "test_customer_4 = Customer(name='Customer 4', balance=0, credit_limit=1200)"
82
89
  },
83
90
  {
84
91
  "test_data_row_variable": "test_order_1",
@@ -86,11 +93,11 @@
86
93
  },
87
94
  {
88
95
  "test_data_row_variable": "test_order_2",
89
- "code": "test_order_2 = Order(customer_id=2, notes='Order 2 notes', amount_total=0)"
96
+ "code": "test_order_2 = Order(customer_id=2, notes='Order 2 notes', amount_total=225)"
90
97
  },
91
98
  {
92
99
  "test_data_row_variable": "test_order_3",
93
- "code": "test_order_3 = Order(customer_id=2, notes='Order 3 notes', amount_total=0)"
100
+ "code": "test_order_3 = Order(customer_id=2, notes='Order 3 notes', amount_total=50)"
94
101
  },
95
102
  {
96
103
  "test_data_row_variable": "test_order_4",
@@ -102,11 +109,11 @@
102
109
  },
103
110
  {
104
111
  "test_data_row_variable": "test_item_2",
105
- "code": "test_item_2 = Item(order_id=2, product_id=2, quantity=2, unit_price=0, amount=0)"
112
+ "code": "test_item_2 = Item(order_id=2, product_id=2, quantity=2, unit_price=25, amount=50)"
106
113
  },
107
114
  {
108
115
  "test_data_row_variable": "test_item_3",
109
- "code": "test_item_3 = Item(order_id=3, product_id=3, quantity=1, unit_price=0, amount=0)"
116
+ "code": "test_item_3 = Item(order_id=3, product_id=3, quantity=3, unit_price=75, amount=225)"
110
117
  },
111
118
  {
112
119
  "test_data_row_variable": "test_item_4",
@@ -11,6 +11,9 @@ Use case: Check Credit
11
11
  4. The Item amount is the quantity * unit_price
12
12
  5. The Item unit_price is copied from the Product unit_price
13
13
 
14
+ Use case: App Integration
15
+ 1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
16
+
14
17
  Ensure each customer has a unique name.
15
18
 
16
19
  Ensure each Item quantity is not null.
@@ -1,8 +1,61 @@
1
- This example illustrates that it's often a good idea to be more specific in the prompt,
2
- for example to specify exact table and column names. Here, we create a time-tracking system, being specific about tables and columns in the [002_create_db_models.prompt](./).
1
+ # Time Tracking and Billing
2
+ Here, we create a time-tracking system, being specific about tables and columns in the [002_create_db_models.prompt](./). Each table has additional attributes that are used to hold sums, counts, and formula. Each table has a Use Case definition that describes the business logic using natural language.
3
3
 
4
- To create this system:
4
+ ## Command Line - create this system:
5
5
  ```bash
6
- # create the time_tracking system
7
- als genai --project-name=track --using=system/genai/examples/time_tracking_billing/002_create_db_models.prompt
6
+ # create the time_track system
7
+ $als genai --project-name=time_track --using=system/genai/examples/time_tracking_billing/002_create_db_models.prompt
8
+ ```
9
+
10
+ ## Review the created system
11
+ Open the time_track in VSCode or CodeSpaces and start the ApiLogicServer (F5). This will start the server and the react-admin site (http://localhost:5656). You should see Client, Project, Task, Timesheet, Person, and Invoice with sample data generated by WebGenAI.
12
+
13
+ ## Review the Logic
14
+ The /logic directory contains the generated logic (/logic/wg_rules). This will show how natural language is translated into LogicBank rules (/logic/wg_rules/active_rules_export.py). The other rules[n].py in the wg_rules folder are used and tested by WebGenAI and can be ignored.
15
+
16
+ ```
17
+ # Exported Rules:
18
+ # Rule 1
19
+ # Total Hours entered is sum of timesheet hours worked
20
+ Rule.sum(derive=Person.total_hours_entered, as_sum_of=Timesheet.hours_worked)
21
+
22
+ ```
23
+
24
+ ## Add Security and Enable Defaults
25
+ The authentication service can be added using the command line
26
+ ```
27
+ $als add-auth --provider-type=sql # Local SQLIte
28
+ $als add-auth --provider-type=keycloak # Local KeyCloak (see docs)
29
+ $als add-auth --provider-type=sql --db-url={database config} # Use SQL database User/Role
30
+ ```
31
+ To ensure defaults are applied (impacts rules) we need to add a global environment variable in the environment and restart the application.
32
+ ALL_DEFAULTS=True
33
+
34
+ ## Add Ontimize Application
35
+ To create an angular Ontimize application, you need to follow these steps. Note the name 'app' is your project name which you can change or create another project.
36
+ ```
37
+ $cd timetrack
38
+ $als app-create --app=app #if the ui/app folder does not exist
39
+ $als app-build --app=app # generates pages from the API entities
40
+ $cd ui/app
41
+
42
+ $npm install && npm start # install and start the NodeJS/Angular app
43
+
44
+ # Launch your new Ontimize application (http://localhost:4299)
45
+
46
+ ```
47
+
48
+ ## Testing Time Tracker and Billing
49
+ You can delete the existing sample data or you can start by entering new data. To test the logic - follow these steps:
50
+ ```
51
+ 1. Enter new Client
52
+ 2. Enter new Person (works for Client)
53
+ 3. Enter new Project for client (enter billing rate)
54
+ 4. Enter new Task for Project
55
+ 5. Enter new Timesheet - enter task and person for client (enter hours worked)
56
+
57
+ Watch Rules fired in log and then review the sums, counts, formula and constraints.
58
+ Note: The Client total amount should be the same value as Project, Task, and Timesheet.
59
+
60
+ Bonus: Enter an Invoice for a Client/Project then add Invoice Item for a specific Client Task. Once the invoice is ready - we can add a new Event (logic) to send to Kafka.
8
61
  ```
@@ -1,6 +1,6 @@
1
1
  Here is the simplified API for LogicBank:
2
2
 
3
- Create a function called declare_logic(), consisting of calls to Rule methods.
3
+ Translate the user prompt into a series of calls to Rule methods, described here.
4
4
 
5
5
  Do not generate import statements.
6
6
 
@@ -126,6 +126,20 @@ class Rule:
126
126
  return Copy(derive=derive, from_parent=from_parent)
127
127
 
128
128
 
129
+ @staticmethod
130
+ def after_flush_row_event(on_class: object, calling: Callable = None,
131
+ if_condition: any = None,
132
+ when_condition: any = None,
133
+ with_args: dict = None):
134
+
135
+ Example:
136
+ Prompt:
137
+ Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None
138
+ Response:
139
+ Rule.after_flush_row_event(on_class=Order, calling=kafka_producer.send_row_to_kafka,
140
+ if_condition=lambda row: row.date_shipped is not None,
141
+ with_args={"topic": "order_shipping"})
142
+
129
143
  Expanded example:
130
144
 
131
145
  Prompt:
@@ -480,6 +480,7 @@ class ManyToOneRelationship(Relationship):
480
480
  parent_accessor_from_fk = True
481
481
  else:
482
482
  self.preferred_name = inflect_engine.singular_noun(tablename) or tablename
483
+ # TODO - consider using the target class name as the preferred name (lower case fk -> a_child.parent)
483
484
 
484
485
 
485
486
  # Add uselist=False to One-to-One relationships
@@ -1512,7 +1513,7 @@ else:
1512
1513
  child_accessor = f' {child_accessor_name} : Mapped[List["{reln.source_cls}"]] = '\
1513
1514
  f'relationship({multi_reln_fix}back_populates="{reln.parent_accessor_name}")\n'
1514
1515
 
1515
- if model.name in ["Employee", "CharacterClass"]: # Emp has Department and Department1
1516
+ if model.name in ["Item", "Employee", "CharacterClass"]: # Emp has Department and Department1
1516
1517
  debug_str = "nice breakpoint" # DND CharacterClass - check parent acceossor (class_ not class)
1517
1518
  model.rendered_parent_relationships += parent_accessor
1518
1519
  parent_model.rendered_child_relationships += child_accessor
@@ -1,16 +0,0 @@
1
-
2
- Create a sqlite database for customers, orders, items and product
3
-
4
- Hints: use autonum keys, allow nulls, Decimal types, foreign keys, no check constraints.
5
-
6
- Include a notes field for orders.
7
-
8
- Create a few rows of only customer and product data.
9
-
10
- Enforce the Check Credit requirement (do not generate check constraints):
11
-
12
- 1. Customer.Balance <= CreditLimit
13
- 2. Customer.Balance = Sum(Order.AmountTotal where date shipped is null)
14
- 3. Order.AmountTotal = Sum(Items.Amount)
15
- 4. Items.Amount = Quantity * UnitPrice
16
- 5. Store the Items.UnitPrice as a copy from Product.UnitPrice