ApiLogicServer 14.3.25__py3-none-any.whl → 14.4.0__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 (90) hide show
  1. api_logic_server_cli/api_logic_server.py +4 -14
  2. api_logic_server_cli/api_logic_server_info.yaml +3 -3
  3. api_logic_server_cli/cli.py +16 -7
  4. api_logic_server_cli/create_from_model/__pycache__/create_db_from_model.cpython-312.pyc +0 -0
  5. api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
  6. api_logic_server_cli/create_from_model/__pycache__/ont_create.cpython-312.pyc +0 -0
  7. api_logic_server_cli/create_from_model/create_db_from_model.py +2 -0
  8. api_logic_server_cli/create_from_model/ont_build.py +19 -14
  9. api_logic_server_cli/create_from_model/ont_create.py +5 -5
  10. api_logic_server_cli/create_from_model/safrs-react-admin-npm-build/static/.DS_Store +0 -0
  11. api_logic_server_cli/database/nw-gold-fix.sql +62 -0
  12. api_logic_server_cli/database/nw-gold.sqlite +0 -0
  13. api_logic_server_cli/{prototypes/manager/webgenai → fragments}/docker-compose.yml +1 -1
  14. api_logic_server_cli/genai/genai.py +42 -11
  15. api_logic_server_cli/genai/genai_graphics.py +252 -38
  16. api_logic_server_cli/genai/genai_svcs.py +20 -12
  17. api_logic_server_cli/manager.py +19 -10
  18. api_logic_server_cli/prototypes/.DS_Store +0 -0
  19. api_logic_server_cli/prototypes/base/.DS_Store +0 -0
  20. api_logic_server_cli/prototypes/base/.vscode/launch.json +19 -0
  21. api_logic_server_cli/prototypes/base/api/expose_api_models.py +3 -1
  22. api_logic_server_cli/prototypes/base/api_logic_server_run.py +5 -2
  23. api_logic_server_cli/prototypes/base/config/activate_logicbank.py +1 -0
  24. api_logic_server_cli/prototypes/base/config/config.py +57 -14
  25. api_logic_server_cli/prototypes/base/config/logging.yml +1 -0
  26. api_logic_server_cli/prototypes/base/config/server_setup.py +33 -1
  27. api_logic_server_cli/prototypes/base/database/test_data/readme.md +3 -1
  28. api_logic_server_cli/prototypes/base/devops/docker-standard-image/docker-compose-standard-image.yml +7 -2
  29. api_logic_server_cli/prototypes/base/docs/training/logic_bank_api.prompt +314 -0
  30. api_logic_server_cli/prototypes/base/docs/training/logic_example.py +41 -0
  31. api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +7 -3
  32. api_logic_server_cli/prototypes/base/integration/system/FlaskKafka.py +5 -1
  33. api_logic_server_cli/prototypes/base/ui/templates/bar_chart.jinja +64 -0
  34. api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +1 -1
  35. api_logic_server_cli/prototypes/manager/README.md +26 -4
  36. api_logic_server_cli/prototypes/manager/system/genai/.DS_Store +0 -0
  37. api_logic_server_cli/prototypes/manager/system/genai/examples/.DS_Store +0 -0
  38. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/.DS_Store +0 -0
  39. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.prompt +0 -10
  40. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +32 -10
  41. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/002_create_db_models.prompt +4 -4
  42. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/003_create_db_models.response +77 -47
  43. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt +1 -1
  44. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/dashboard_services.jinja +83 -0
  45. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_dashboard_WIP.py +34 -0
  46. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/{graphics_services.py → graphics_services_api_xxx.py} +0 -9
  47. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db.jinja +46 -0
  48. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db_each_method.jinja +36 -0
  49. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/graphics.prompt +7 -3
  50. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/response_format.prompt +8 -1
  51. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.ps1 +100 -0
  52. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.sh +116 -0
  53. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/readme.md +7 -0
  54. api_logic_server_cli/prototypes/manager/system/style-guide.yaml +2 -2
  55. api_logic_server_cli/prototypes/manager/webgenai/README.md +6 -0
  56. api_logic_server_cli/prototypes/nw/docs/graphics/count_orders_by_category.prompt +1 -0
  57. api_logic_server_cli/prototypes/nw/docs/graphics/order_count_by_month.prompt +1 -0
  58. api_logic_server_cli/prototypes/nw/docs/graphics/request copy.json +892 -0
  59. api_logic_server_cli/prototypes/nw/docs/graphics/request.json +6 -0
  60. api_logic_server_cli/prototypes/nw/docs/graphics/response.json +17 -0
  61. api_logic_server_cli/prototypes/nw/docs/graphics/response.yaml +59 -0
  62. api_logic_server_cli/prototypes/nw/docs/graphics/sales_by_category.prompt +1 -0
  63. api_logic_server_cli/prototypes/nw/ui/admin/home.js +5 -4
  64. api_logic_server_cli/prototypes/nw/ui/app_model_custom.yaml +851 -1082
  65. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/count_orders_by_category.prompt +1 -0
  66. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/sales_by_employee.prompt +1 -0
  67. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/1_langchain_loader.py +19 -0
  68. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/2_gpt_mcp_prompt.txt +19 -0
  69. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/3_executor_test_agent.py +38 -0
  70. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/README.md +17 -0
  71. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/resources/curl.txt +4 -0
  72. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/resources/nw_swagger_3.yaml +16660 -0
  73. api_logic_server_cli/prototypes/nw_no_cust/integration/mcp/run_executor.py +23 -0
  74. api_logic_server_cli/prototypes/ont_app/ontimize_seed/nginx/nginx.conf +2 -2
  75. api_logic_server_cli/prototypes/ont_app/ontimize_seed/package.json +6 -6
  76. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/app/app.config.ts +2 -1
  77. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.prod.ts +5 -5
  78. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.ts +5 -5
  79. api_logic_server_cli/prototypes/ont_app/templates/app_config.jinja +1 -1
  80. api_logic_server_cli/prototypes/ont_app/templates/detail_template.html +1 -1
  81. api_logic_server_cli/prototypes/ont_app/templates/new_template.html +16 -16
  82. apilogicserver-14.4.0.dist-info/METADATA +76 -0
  83. {apilogicserver-14.3.25.dist-info → apilogicserver-14.4.0.dist-info}/RECORD +87 -56
  84. {apilogicserver-14.3.25.dist-info → apilogicserver-14.4.0.dist-info}/WHEEL +1 -1
  85. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/service_template_jsonapi_rpc.jinja +0 -37
  86. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/service_template_unused.jinja +0 -38
  87. apilogicserver-14.3.25.dist-info/METADATA +0 -167
  88. {apilogicserver-14.3.25.dist-info → apilogicserver-14.4.0.dist-info}/entry_points.txt +0 -0
  89. {apilogicserver-14.3.25.dist-info → apilogicserver-14.4.0.dist-info}/licenses/LICENSE +0 -0
  90. {apilogicserver-14.3.25.dist-info → apilogicserver-14.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sales by Region</title>
7
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
8
+ <style>
9
+ body {
10
+ margin: 0;
11
+ padding: 0;
12
+ display: flex;
13
+ overflow: hidden;
14
+ justify-content: center;
15
+ align-items: center;
16
+ height: 100%;
17
+ box-sizing: border-box;
18
+ }
19
+ canvas {
20
+ display: block;
21
+ }
22
+ </style>
23
+ </head>
24
+ <body>
25
+ <canvas id="salesChart" width="200" height="200"></canvas>
26
+ <script>
27
+ const labels = [];
28
+ const data = [];
29
+ result = {{ result | tojson }};
30
+ console.log(result);
31
+ const type = result.chart_type;
32
+ const title = result.title;
33
+ const columns = result.columns;
34
+ console.log(JSON.stringify(result));
35
+ result.results.forEach(item => {
36
+ labels.push(item[columns[0]]);
37
+ data.push(parseFloat(item[columns[1]]));
38
+ });
39
+ const ctx = document.getElementById('salesChart').getContext('2d');
40
+ const salesChart = new Chart(ctx, {
41
+ type: type,
42
+ data: {
43
+ labels: labels,
44
+ datasets: [{
45
+ label: title,
46
+ data: data,
47
+ backgroundColor: {{ color | tojson }},
48
+ borderColor: 'rgba(75, 192, 192, 1)',
49
+ borderWidth: 1
50
+ }]
51
+ },
52
+ options: {
53
+ responsive: true,
54
+ maintainAspectRatio: false,
55
+ scales: {
56
+ y: {
57
+ beginAtZero: true
58
+ }
59
+ }
60
+ }
61
+ });
62
+ </script>
63
+ </body>
64
+ </html>
@@ -135,7 +135,7 @@ settings:
135
135
  new_mode: dialog
136
136
  pick_style: list
137
137
  row_height: small,
138
- serviceType: OntimizeEE
138
+ serviceType: JSONAPI
139
139
  startSessionPath: /auth/login
140
140
  style: light
141
141
  thousand_separator: ','
@@ -165,20 +165,28 @@ Verify it's operating properly:
165
165
 
166
166
  <summary> You can iterate the logic and data model</summary>
167
167
 
168
- <br>Logic iterations are particuarly useful. For example, here we take the basic check-credit logic, and add:
168
+ <br>The approach for an iteration is to create a new project from an existing one:
169
+
170
+ 1. add another prompt to an existing projects `docs` directory, specifying your changes
171
+ 2. use `als genai`, specifying
172
+ * `--using` existing projects `docs` directory, and
173
+ * `--project-name` as the output project
174
+
175
+ **Logic iterations** are particuarly useful. For example, here we take the basic check-credit logic, and add:
169
176
 
170
177
  > Provide a 10% discount when buying more than 10 carbon neutral products.<br><br>The Item carbon neutral is copied from the Product carbon neutral
171
178
 
172
- Explore [genai_demo_iteration_discount](system/genai/examples/genai_demo/genai_demo_iteration_discount). This will add carbon_neutral to the data model, and update the logic to provide the discount:
179
+ Explore [genai_demo_iteration_discount](system/genai/examples/genai_demo/genai_demo_iteration_discount). It's an iteration of basic_demo (see system/genai/examples/genai_demo/genai_demo_iteration_discount/002_create_db_models.prompt). This will add carbon_neutral to the data model, and update the logic to provide the discount:
173
180
 
174
181
  ```bash title='Iterate Business Logic'
175
182
  # Iterate with data model and logic
176
- als genai --project-name='genai_demo_with_logic' --using=system/genai/examples/genai_demo/genai_demo_iteration
183
+ als genai --project-name='genai_demo_with_discount' --using=system/genai/examples/genai_demo/genai_demo_iteration_discount
177
184
  # open Docs/db.dbml
178
185
  ```
186
+
179
187
  <br>
180
188
 
181
- You can add new columns/tables, while keeping the prior model intact:
189
+ You can perform **model iterations:** add new columns/tables, while keeping the prior model intact. First, we create a project with no logic, perhaps just to see the screens (this step is optional, provided just to illustrate that iterations create new projects from existing ones):
182
190
 
183
191
  ```bash title='Iterate Without Logic'
184
192
  # Step 1 - create without logic
@@ -186,6 +194,8 @@ als genai --project-name='genai_demo_no_logic' --using=system/genai/examples/gen
186
194
  # open Docs/db.dbml
187
195
  ```
188
196
 
197
+ Then, we would create another prompt in the docs directory with our model changes. We've already created these for you in `system/genai/examples/genai_demo/genai_demo_iteration` - we use that to alter the data model (see `system/genai/examples/genai_demo/genai_demo_iteration/004_iteration_renames_logic.prompt`):
198
+
189
199
  ```bash title='Iterate With Logic'
190
200
  # Iterate with data model and logic
191
201
  als genai --project-name='genai_demo_with_logic' --using=system/genai/examples/genai_demo/genai_demo_iteration
@@ -502,6 +512,18 @@ als create --project-name=sample_ai --from-model=sample_ai.py --db-url=sqlite
502
512
 
503
513
  4. This will create your database, create an API Logic Project from it, and launch your IDE.
504
514
 
515
+ 5. Create business logic
516
+
517
+ * You can create logic with either your IDE (and code completion), or Natural Language
518
+ * To use Natural Language:
519
+
520
+ 1. Use the CoPilot chat,
521
+ 2. Paste the logic above
522
+ 3. Copy it to `logic/declare_logic.py` after `discover_logic()`
523
+
524
+ * Alert: Table and Column Names may require correction to conform to the model
525
+ * Alert: you may to apply [defaulting](https://apilogicserver.github.io/Docs/Logic-Use/#insert-defaulting), and initialize derived attributes in your database
526
+
505
527
  </details>
506
528
  </br>
507
529
 
@@ -2,8 +2,6 @@ Create a system with customers, orders, items and products.
2
2
 
3
3
  Include a notes field for orders.
4
4
 
5
- Use LogicBank to enforce business logic.
6
-
7
5
  Use case: Check Credit
8
6
  1. The Customer's balance is less than the credit limit
9
7
  2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
@@ -13,11 +11,3 @@ Use case: Check Credit
13
11
 
14
12
  Use case: App Integration
15
13
  1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
16
-
17
- Graph sales by month.
18
-
19
- Ensure each customer and product has a unique name.
20
-
21
- Ensure each Item quantity is not null.
22
-
23
- Ensure each order has a valid customer_id that exists in the Customer table.
@@ -71,25 +71,47 @@
71
71
  ],
72
72
  "graphics": [
73
73
  {
74
- "sqlalchemy_query": "sales_by_month = (session.query(func.strftime('%Y-%m', Order.date_shipped).label('Month'), func.sum(Item.amount)) .join(Item, Order.id == Item.order_id) .group_by(func.strftime('%Y-%m', Order.date_shipped)) .order_by(func.strftime('%Y-%m', Order.date_shipped)))",
75
- "classes_used": "Order, Item",
76
- "name": "sales_by_month",
77
- "html_code": "function drawSalesByMonthChart(result) {\n const labels = result.map(entry => entry.Month);\n const data = result.map(entry => entry.TotalSales);\n const ctx = document.getElementById('salesByMonthChart').getContext('2d');\n new Chart(ctx, {\n type: 'bar',\n data: {\n labels: labels,\n datasets: [{\n label: 'Sales by Month',\n data: data,\n backgroundColor: '#42A5F5',\n borderColor: '#1E88E5',\n borderWidth: 1\n }]\n },\n options: {\n scales: {\n yAxes: [{\n ticks: {\n beginAtZero: true\n }\n }]\n }\n }\n });\n}"
74
+ "sqlalchemy_query": "session.query(Product.name, func.sum(Item.amount).label('TotalSales')).join(Item, Product.id == Item.product_id).filter(Order.date_shipped.isnot(None)).group_by(Product.name).order_by(func.sum(Item.amount).desc())",
75
+ "sql_query": "SELECT Product.name, SUM(Item.amount) AS TotalSales FROM Product JOIN Item ON Product.id = Item.product_id JOIN Order ON Item.order_id = Order.id WHERE Order.date_shipped IS NOT NULL GROUP BY Product.name ORDER BY TotalSales DESC",
76
+ "classes_used": "Product, Item, Order",
77
+ "class_x_axis": "Product",
78
+ "name": "sales_by_product",
79
+ "prompt": "Graph Sales by Product",
80
+ "title": "Sales by Product",
81
+ "xAxis": "Product",
82
+ "yAxis": "Total Sales",
83
+ "dashboard": true,
84
+ "graph_type": "Bar",
85
+ "html_code": "var data = result.result; var categories = data.map(item => item[0]); var totals = data.map(item => item[1]); var ctx = document.getElementById('salesByProductChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: categories, datasets: [{label: 'Sales by Product', data: totals}]}});"
86
+ },
87
+ {
88
+ "sqlalchemy_query": "session.query(Customer.name, func.sum(Order.amount_total).label('TotalCustomerSales')).join(Order, Customer.id == Order.customer_id).filter(Order.date_shipped.isnot(None)).group_by(Customer.name).order_by(func.sum(Order.amount_total).desc())",
89
+ "sql_query": "SELECT Customer.name, SUM(Order.amount_total) AS TotalCustomerSales FROM Customer JOIN Order ON Customer.id = Order.customer_id WHERE Order.date_shipped IS NOT NULL GROUP BY Customer.name ORDER BY TotalCustomerSales DESC",
90
+ "classes_used": "Customer, Order",
91
+ "class_x_axis": "Customer",
92
+ "name": "sales_by_customer",
93
+ "prompt": "Graph Sales by Customer",
94
+ "title": "Sales by Customer",
95
+ "xAxis": "Customer",
96
+ "yAxis": "Total Sales",
97
+ "dashboard": true,
98
+ "graph_type": "Bar",
99
+ "html_code": "var data = result.result; var customers = data.map(item => item[0]); var sales = data.map(item => item[1]); var ctx = document.getElementById('salesByCustomerChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: customers, datasets: [{label: 'Sales by Customer', data: sales}]}});"
78
100
  }
79
101
  ],
80
102
  "test_data": "This is the test data generated for Customers, Orders, Items, and Products in the new system.",
81
103
  "test_data_rows": [
82
104
  {
83
105
  "test_data_row_variable": "customer1",
84
- "code": "customer1 = Customer(name=\"Alice\", balance=1000.00, credit_limit=5000.00)"
106
+ "code": "customer1 = Customer(name=\"Alice\", balance=90.00, credit_limit=5000.00)"
85
107
  },
86
108
  {
87
109
  "test_data_row_variable": "customer2",
88
- "code": "customer2 = Customer(name=\"Bob\", balance=2000.00, credit_limit=3000.00)"
110
+ "code": "customer2 = Customer(name=\"Bob\", balance=0.00, credit_limit=3000.00)"
89
111
  },
90
112
  {
91
113
  "test_data_row_variable": "customer3",
92
- "code": "customer3 = Customer(name=\"Charlie\", balance=500.00, credit_limit=2000.00)"
114
+ "code": "customer3 = Customer(name=\"Charlie\", balance=220.00, credit_limit=2000.00)"
93
115
  },
94
116
  {
95
117
  "test_data_row_variable": "customer4",
@@ -113,15 +135,15 @@
113
135
  },
114
136
  {
115
137
  "test_data_row_variable": "order1",
116
- "code": "order1 = Order(notes=\"First Order\", customer_id=1, date_shipped=date(2023, 3, 22), amount_total=300.00)"
138
+ "code": "order1 = Order(notes=\"First Order\", customer_id=2, date_shipped=date(2023, 3, 22), amount_total=300.00)"
117
139
  },
118
140
  {
119
141
  "test_data_row_variable": "order2",
120
- "code": "order2 = Order(notes=\"Second Order\", customer_id=2, date_shipped=None, amount_total=0.00)"
142
+ "code": "order2 = Order(notes=\"Second Order\", customer_id=1, date_shipped=None, amount_total=90.00)"
121
143
  },
122
144
  {
123
145
  "test_data_row_variable": "order3",
124
- "code": "order3 = Order(notes=\"Pending Shipment\", customer_id=3, date_shipped=None, amount_total=300.00)"
146
+ "code": "order3 = Order(notes=\"Pending Shipment\", customer_id=3, date_shipped=None, amount_total=220.00)"
125
147
  },
126
148
  {
127
149
  "test_data_row_variable": "order4",
@@ -5,8 +5,6 @@ Create a system with customers, orders, items and products.
5
5
 
6
6
  Include a notes field for orders.
7
7
 
8
- Use LogicBank to enforce these requirements (do not generate check constraints); be sure to update the data model and *all* test data with any attributes used in the logic:
9
-
10
8
  Use case: Check Credit
11
9
  1. The Customer's balance is less than the credit limit
12
10
  2. The Customer's balance is the sum of the Order amount_total where date_shipped is null
@@ -17,12 +15,14 @@ Use case: Check Credit
17
15
  Use case: App Integration
18
16
  1. Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
19
17
 
20
- Ensure each customer and product has a unique name.
18
+ Ensure each customer has a unique name.
21
19
 
22
20
  Ensure each Item quantity is not null.
23
21
 
24
22
  Ensure each order has a valid customer_id that exists in the Customer table.
25
- .
23
+
24
+ Graph sales by month, for dashboard.
25
+ Graph Sales by Product, for dashboard.
26
26
  </Requirements>
27
27
 
28
28
  Hints: use autonum keys (for all tables - including for link/join/junction/intersection tables), allow nulls, foreign keys, no check constraints.
@@ -2,140 +2,170 @@
2
2
  "models": [
3
3
  {
4
4
  "classname": "Customer",
5
- "code": "class Customer(Base):\n __tablename__ = 'customer'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String(255), unique=True)\n credit_limit = Column(DECIMAL)\n balance = Column(DECIMAL)\n",
6
- "description": "Represents a customer entity with unique name, credit limit, and balance.",
7
- "name": "customer"
5
+ "code": "class Customer(Base):\n __tablename__ = 'customer'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, unique=True)\n balance = Column(DECIMAL)\n credit_limit = Column(DECIMAL)",
6
+ "description": "Defines the Customer entity with a unique name, balance, and credit limit.",
7
+ "name": "Customer"
8
8
  },
9
9
  {
10
10
  "classname": "Order",
11
- "code": "class Order(Base):\n __tablename__ = 'order'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n customer_id = Column(Integer, ForeignKey('customer.id'))\n date_shipped = Column(DateTime)\n amount_total = Column(DECIMAL)\n notes = Column(String(255))\n",
12
- "description": "Represents an order entity linked to a customer with a note field.",
13
- "name": "order"
11
+ "code": "class Order(Base):\n __tablename__ = 'order'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n notes = Column(String)\n customer_id = Column(Integer, ForeignKey('customer.id'), nullable=False)\n date_shipped = Column(Date)\n amount_total = Column(DECIMAL)",
12
+ "description": "Defines the Order entity which belongs to a customer. Includes notes and amount total.",
13
+ "name": "Order"
14
14
  },
15
15
  {
16
16
  "classname": "Item",
17
- "code": "class Item(Base):\n __tablename__ = 'item'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n order_id = Column(Integer, ForeignKey('order.id'))\n product_id = Column(Integer, ForeignKey('product.id'))\n quantity = Column(Integer, nullable=False)\n unit_price = Column(DECIMAL)\n amount = Column(DECIMAL)\n",
18
- "description": "Represents an item within an order, linked to a product with mandatory quantity.",
19
- "name": "item"
17
+ "code": "class Item(Base):\n __tablename__ = 'item'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n order_id = Column(Integer, ForeignKey('order.id'))\n product_id = Column(Integer, ForeignKey('product.id'), nullable=False)\n quantity = Column(Integer, nullable=False)\n amount = Column(DECIMAL)\n unit_price = Column(DECIMAL)",
18
+ "description": "Defines the Item entity with quantity, amounts, and unit price details.",
19
+ "name": "Item"
20
20
  },
21
21
  {
22
22
  "classname": "Product",
23
- "code": "class Product(Base):\n __tablename__ = 'product'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String(255), unique=True)\n unit_price = Column(DECIMAL)\n",
24
- "description": "Represents a product entity with unique name and unit price.",
25
- "name": "product"
23
+ "code": "class Product(Base):\n __tablename__ = 'product'\n\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, unique=True)\n unit_price = Column(DECIMAL)",
24
+ "description": "Defines the Product entity with a unique name and unit price.",
25
+ "name": "Product"
26
26
  }
27
27
  ],
28
28
  "rules": [
29
29
  {
30
- "name": "Check Balance Constraint",
31
- "description": "Ensure customer balance is within credit limit.",
30
+ "name": "Customer Balance Constraint",
31
+ "description": "Ensure the customer's balance is less than their credit limit.",
32
32
  "use_case": "Check Credit",
33
33
  "entity": "Customer",
34
- "code": "Rule.constraint(validate=Customer, \n as_condition=lambda row: row.balance <= row.credit_limit, \n error_msg=\"Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})\")"
34
+ "code": "Rule.constraint(validate=Customer, as_condition=lambda row: row.balance <= row.credit_limit, error_msg=\"Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})\")"
35
35
  },
36
36
  {
37
- "name": "Customer Balance Sum",
38
- "description": "Sum of order amount totals where date shipped is null.",
37
+ "name": "Customer Balance Derivation",
38
+ "description": "Derive the customer's balance as the sum of order totals where not yet shipped.",
39
39
  "use_case": "Check Credit",
40
40
  "entity": "Customer",
41
- "code": "Rule.sum(derive=Customer.balance, \n as_sum_of=Order.amount_total, \n where=lambda row: row.date_shipped is None)"
41
+ "code": "Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total, where=lambda row: row.date_shipped is None)"
42
42
  },
43
43
  {
44
- "name": "Order Amount Total Sum",
45
- "description": "Sum of item amounts for each order.",
44
+ "name": "Order Total Derivation",
45
+ "description": "Derive the order's total amount from the sum of item amounts.",
46
46
  "use_case": "Check Credit",
47
47
  "entity": "Order",
48
- "code": "Rule.sum(derive=Order.amount_total, \n as_sum_of=Item.amount)"
48
+ "code": "Rule.sum(derive=Order.amount_total, as_sum_of=Item.amount)"
49
49
  },
50
50
  {
51
- "name": "Item Amount Formula",
52
- "description": "Calculate item amount as quantity times unit price.",
51
+ "name": "Item Amount Calculation",
52
+ "description": "Calculate item amount based on quantity and unit price.",
53
53
  "use_case": "Check Credit",
54
54
  "entity": "Item",
55
- "code": "Rule.formula(derive=Item.amount, \n as_expression=lambda row: row.quantity * row.unit_price)"
55
+ "code": "Rule.formula(derive=Item.amount, as_expression=lambda row: row.quantity * row.unit_price)"
56
56
  },
57
57
  {
58
- "name": "Copy Unit Price",
58
+ "name": "Item Unit Price Copy",
59
59
  "description": "Copy unit price from product to item.",
60
60
  "use_case": "Check Credit",
61
61
  "entity": "Item",
62
- "code": "Rule.copy(derive=Item.unit_price, \n from_parent=Product.unit_price)"
62
+ "code": "Rule.copy(derive=Item.unit_price, from_parent=Product.unit_price)"
63
63
  },
64
64
  {
65
- "name": "Order Shipping Kafka Event",
66
- "description": "Send orders to Kafka when shipped date is not None.",
65
+ "name": "Order Kafka Notification",
66
+ "description": "Send order details to Kafka if order is shipped.",
67
67
  "use_case": "App Integration",
68
68
  "entity": "Order",
69
- "code": "Rule.after_flush_row_event(on_class=Order, \n calling=kafka_producer.send_row_to_kafka, \n if_condition=lambda row: row.date_shipped is not None, \n with_args={\"topic\": \"order_shipping\"})"
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'})"
70
70
  }
71
71
  ],
72
- "test_data": "# Customer Test Data Rows\ncustomer1 = Customer(id=1, name=\"John Doe\", credit_limit=1000, balance=0)\ncustomer2 = Customer(id=2, name=\"Jane Roe\", credit_limit=2000, balance=0)\ncustomer3 = Customer(id=3, name=\"Acme Corp\", credit_limit=5000, balance=0)\ncustomer4 = Customer(id=4, name=\"Globex Inc\", credit_limit=3000, balance=0)\n\n# Product Test Data Rows\nproduct1 = Product(id=1, name=\"Widget\", unit_price=10)\nproduct2 = Product(id=2, name=\"Gadget\", unit_price=20)\nproduct3 = Product(id=3, name=\"Doodad\", unit_price=15)\nproduct4 = Product(id=4, name=\"Thingamajig\", unit_price=25)\n\n# Order Test Data Rows\norder1 = Order(id=1, customer_id=1, amount_total=0, notes=\"First order\")\norder2 = Order(id=2, customer_id=2, amount_total=0, notes=\"Second order\")\norder3 = Order(id=3, customer_id=3, amount_total=0, notes=\"Third order\")\norder4 = Order(id=4, customer_id=4, amount_total=0, notes=\"Fourth order\")\n\n# Item Test Data Rows\nitem1 = Item(id=1, order_id=1, product_id=1, quantity=2, unit_price=10, amount=20)\nitem2 = Item(id=2, order_id=2, product_id=2, quantity=1, unit_price=20, amount=20)\nitem3 = Item(id=3, order_id=3, product_id=3, quantity=3, unit_price=15, amount=45)\nitem4 = Item(id=4, order_id=4, product_id=4, quantity=4, unit_price=25, amount=100)",
72
+ "graphics": [
73
+ {
74
+ "sqlalchemy_query": "session.query(Product.name, func.sum(Item.amount).label('TotalSales')).join(Item, Product.id == Item.product_id).filter(Order.date_shipped.isnot(None)).group_by(Product.name).order_by(func.sum(Item.amount).desc())",
75
+ "sql_query": "SELECT Product.name, SUM(Item.amount) AS TotalSales FROM Product JOIN Item ON Product.id = Item.product_id JOIN Order ON Item.order_id = Order.id WHERE Order.date_shipped IS NOT NULL GROUP BY Product.name ORDER BY TotalSales DESC",
76
+ "classes_used": "Product, Item, Order",
77
+ "class_x_axis": "Product",
78
+ "name": "sales_by_product",
79
+ "prompt": "Graph Sales by Product",
80
+ "title": "Sales by Product",
81
+ "xAxis": "Product",
82
+ "yAxis": "Total Sales",
83
+ "dashboard": true,
84
+ "graph_type": "Bar",
85
+ "html_code": "var data = result.result; var categories = data.map(item => item[0]); var totals = data.map(item => item[1]); var ctx = document.getElementById('salesByProductChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: categories, datasets: [{label: 'Sales by Product', data: totals}]}});"
86
+ },
87
+ {
88
+ "sqlalchemy_query": "session.query(Customer.name, func.sum(Order.amount_total).label('TotalCustomerSales')).join(Order, Customer.id == Order.customer_id).filter(Order.date_shipped.isnot(None)).group_by(Customer.name).order_by(func.sum(Order.amount_total).desc())",
89
+ "sql_query": "SELECT Customer.name, SUM(Order.amount_total) AS TotalCustomerSales FROM Customer JOIN Order ON Customer.id = Order.customer_id WHERE Order.date_shipped IS NOT NULL GROUP BY Customer.name ORDER BY TotalCustomerSales DESC",
90
+ "classes_used": "Customer, Order",
91
+ "class_x_axis": "Customer",
92
+ "name": "sales_by_customer",
93
+ "prompt": "Graph Sales by Customer",
94
+ "title": "Sales by Customer",
95
+ "xAxis": "Customer",
96
+ "yAxis": "Total Sales",
97
+ "dashboard": true,
98
+ "graph_type": "Bar",
99
+ "html_code": "var data = result.result; var customers = data.map(item => item[0]); var sales = data.map(item => item[1]); var ctx = document.getElementById('salesByCustomerChart').getContext('2d'); new Chart(ctx, {type: 'bar', data: {labels: customers, datasets: [{label: 'Sales by Customer', data: sales}]}});"
100
+ }
101
+ ],
102
+ "test_data": "This is the test data generated for Customers, Orders, Items, and Products in the new system.",
73
103
  "test_data_rows": [
74
104
  {
75
105
  "test_data_row_variable": "customer1",
76
- "code": "customer1 = Customer(id=1, name=\"John Doe\", credit_limit=1000, balance=0)"
106
+ "code": "customer1 = Customer(name=\"Alice\", balance=1000.00, credit_limit=5000.00)"
77
107
  },
78
108
  {
79
109
  "test_data_row_variable": "customer2",
80
- "code": "customer2 = Customer(id=2, name=\"Jane Roe\", credit_limit=2000, balance=0)"
110
+ "code": "customer2 = Customer(name=\"Bob\", balance=2000.00, credit_limit=3000.00)"
81
111
  },
82
112
  {
83
113
  "test_data_row_variable": "customer3",
84
- "code": "customer3 = Customer(id=3, name=\"Acme Corp\", credit_limit=5000, balance=0)"
114
+ "code": "customer3 = Customer(name=\"Charlie\", balance=500.00, credit_limit=2000.00)"
85
115
  },
86
116
  {
87
117
  "test_data_row_variable": "customer4",
88
- "code": "customer4 = Customer(id=4, name=\"Globex Inc\", credit_limit=3000, balance=0)"
118
+ "code": "customer4 = Customer(name=\"Diana\", balance=0.00, credit_limit=1000.00)"
89
119
  },
90
120
  {
91
121
  "test_data_row_variable": "product1",
92
- "code": "product1 = Product(id=1, name=\"Widget\", unit_price=10)"
122
+ "code": "product1 = Product(name=\"Gadget\", unit_price=150.00)"
93
123
  },
94
124
  {
95
125
  "test_data_row_variable": "product2",
96
- "code": "product2 = Product(id=2, name=\"Gadget\", unit_price=20)"
126
+ "code": "product2 = Product(name=\"Widget\", unit_price=90.00)"
97
127
  },
98
128
  {
99
129
  "test_data_row_variable": "product3",
100
- "code": "product3 = Product(id=3, name=\"Doodad\", unit_price=15)"
130
+ "code": "product3 = Product(name=\"Thingamajig\", unit_price=75.00)"
101
131
  },
102
132
  {
103
133
  "test_data_row_variable": "product4",
104
- "code": "product4 = Product(id=4, name=\"Thingamajig\", unit_price=25)"
134
+ "code": "product4 = Product(name=\"Doodad\", unit_price=110.00)"
105
135
  },
106
136
  {
107
137
  "test_data_row_variable": "order1",
108
- "code": "order1 = Order(id=1, customer_id=1, amount_total=0, notes=\"First order\")"
138
+ "code": "order1 = Order(notes=\"First Order\", customer_id=1, date_shipped=date(2023, 3, 22), amount_total=300.00)"
109
139
  },
110
140
  {
111
141
  "test_data_row_variable": "order2",
112
- "code": "order2 = Order(id=2, customer_id=2, amount_total=0, notes=\"Second order\")"
142
+ "code": "order2 = Order(notes=\"Second Order\", customer_id=2, date_shipped=None, amount_total=0.00)"
113
143
  },
114
144
  {
115
145
  "test_data_row_variable": "order3",
116
- "code": "order3 = Order(id=3, customer_id=3, amount_total=0, notes=\"Third order\")"
146
+ "code": "order3 = Order(notes=\"Pending Shipment\", customer_id=3, date_shipped=None, amount_total=300.00)"
117
147
  },
118
148
  {
119
149
  "test_data_row_variable": "order4",
120
- "code": "order4 = Order(id=4, customer_id=4, amount_total=0, notes=\"Fourth order\")"
150
+ "code": "order4 = Order(notes=\"Urgent Order\", customer_id=4, date_shipped=date(2023, 7, 15), amount_total=220.00)"
121
151
  },
122
152
  {
123
153
  "test_data_row_variable": "item1",
124
- "code": "item1 = Item(id=1, order_id=1, product_id=1, quantity=2, unit_price=10, amount=20)"
154
+ "code": "item1 = Item(order_id=1, product_id=1, quantity=2, amount=300.00, unit_price=150.00)"
125
155
  },
126
156
  {
127
157
  "test_data_row_variable": "item2",
128
- "code": "item2 = Item(id=2, order_id=2, product_id=2, quantity=1, unit_price=20, amount=20)"
158
+ "code": "item2 = Item(order_id=2, product_id=2, quantity=1, amount=90.00, unit_price=90.00)"
129
159
  },
130
160
  {
131
161
  "test_data_row_variable": "item3",
132
- "code": "item3 = Item(id=3, order_id=3, product_id=3, quantity=3, unit_price=15, amount=45)"
162
+ "code": "item3 = Item(order_id=3, product_id=4, quantity=2, amount=220.00, unit_price=110.00)"
133
163
  },
134
164
  {
135
165
  "test_data_row_variable": "item4",
136
- "code": "item4 = Item(id=4, order_id=4, product_id=4, quantity=4, unit_price=25, amount=100)"
166
+ "code": "item4 = Item(order_id=4, product_id=3, quantity=4, amount=300.00, unit_price=75.00)"
137
167
  }
138
168
  ],
139
- "test_data_sqlite": "INSERT INTO customer (id, name, credit_limit, balance) VALUES (1, \"John Doe\", 1000, 0);\nINSERT INTO customer (id, name, credit_limit, balance) VALUES (2, \"Jane Roe\", 2000, 0);\nINSERT INTO customer (id, name, credit_limit, balance) VALUES (3, \"Acme Corp\", 5000, 0);\nINSERT INTO customer (id, name, credit_limit, balance) VALUES (4, \"Globex Inc\", 3000, 0);\n\nINSERT INTO product (id, name, unit_price) VALUES (1, \"Widget\", 10);\nINSERT INTO product (id, name, unit_price) VALUES (2, \"Gadget\", 20);\nINSERT INTO product (id, name, unit_price) VALUES (3, \"Doodad\", 15);\nINSERT INTO product (id, name, unit_price) VALUES (4, \"Thingamajig\", 25);\n\nINSERT INTO \"order\" (id, customer_id, amount_total, notes) VALUES (1, 1, 0, \"First order\");\nINSERT INTO \"order\" (id, customer_id, amount_total, notes) VALUES (2, 2, 0, \"Second order\");\nINSERT INTO \"order\" (id, customer_id, amount_total, notes) VALUES (3, 3, 0, \"Third order\");\nINSERT INTO \"order\" (id, customer_id, amount_total, notes) VALUES (4, 4, 0, \"Fourth order\");\n\nINSERT INTO item (id, order_id, product_id, quantity, unit_price, amount) VALUES (1, 1, 1, 2, 10, 20);\nINSERT INTO item (id, order_id, product_id, quantity, unit_price, amount) VALUES (2, 2, 2, 1, 20, 20);\nINSERT INTO item (id, order_id, product_id, quantity, unit_price, amount) VALUES (3, 3, 3, 3, 15, 45);\nINSERT INTO item (id, order_id, product_id, quantity, unit_price, amount) VALUES (4, 4, 4, 4, 25, 100);",
169
+ "test_data_sqlite": "INSERT INTO customer (name, balance, credit_limit) VALUES ('Alice', 1000.00, 5000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Bob', 2000.00, 3000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Charlie', 500.00, 2000.00);\nINSERT INTO customer (name, balance, credit_limit) VALUES ('Diana', 0.00, 1000.00);\n\nINSERT INTO product (name, unit_price) VALUES ('Gadget', 150.00);\nINSERT INTO product (name, unit_price) VALUES ('Widget', 90.00);\nINSERT INTO product (name, unit_price) VALUES ('Thingamajig', 75.00);\nINSERT INTO product (name, unit_price) VALUES ('Doodad', 110.00);\n\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('First Order', 1, '2023-03-22', 300.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Second Order', 2, NULL, 0.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Pending Shipment', 3, NULL, 300.00);\nINSERT INTO [order] (notes, customer_id, date_shipped, amount_total) VALUES ('Urgent Order', 4, '2023-07-15', 220.00);\n\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (1, 1, 2, 300.00, 150.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (2, 2, 1, 90.00, 90.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (3, 4, 2, 220.00, 110.00);\nINSERT INTO item (order_id, product_id, quantity, amount, unit_price) VALUES (4, 3, 4, 300.00, 75.00);",
140
170
  "name": "CustomerOrderSystem"
141
171
  }
@@ -16,4 +16,4 @@ Ensure each customer has a unique name.
16
16
 
17
17
  Ensure each Item quantity is not null.
18
18
 
19
- Ensure each order has a valid customer_id that exists in the Customer table.
19
+ Ensure: each order has a valid customer_id that exists in the Customer table.
@@ -0,0 +1,83 @@
1
+ from database import models
2
+ import logging
3
+ from safrs import jsonapi_attr
4
+ from sqlalchemy.orm import relationship, remote, foreign
5
+ from functools import wraps # This convenience func preserves name and docstring
6
+ import decimal as decimal
7
+ from sqlalchemy import extract, func
8
+ from flask import request, jsonify
9
+ from safrs import jsonapi_rpc, SAFRSAPI
10
+ from database import models
11
+ import safrs
12
+ from pathlib import Path
13
+
14
+ """
15
+ Called by iFrame in home.js when admin app is loaded
16
+
17
+ Returns iFrame for ui/admin/home.js, with entries like this to populate the dashboard:
18
+ <iframe src="http://localhost:5656/chart_graphics/sales_per_category" style="flex: 1; border: none; width: 90%; height: 200px;">
19
+
20
+ curl -X GET "http://localhost:5656/dashboard"
21
+
22
+ You typically do not alter this file - it is rebuilt on `als genai-graphics`
23
+
24
+ """
25
+
26
+ app_logger = logging.getLogger(__name__)
27
+ dashboard_result = {}
28
+
29
+
30
+ def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
31
+ pass
32
+
33
+ @app.route('/dashboard', methods=['GET','OPTIONS'])
34
+ def dashboard():
35
+
36
+
37
+ if request.method == 'OPTIONS':
38
+ return jsonify({"result": "ok"})
39
+
40
+ server = request.host_url
41
+
42
+ iframe_template = '<div class="dashboard-iframe"><iframe src="{url}" style="flex: 1; border: none; width: 90%; height: 200px;"></iframe></div>'
43
+ {% for iframe in iframe_templates %}
44
+ {{iframe}}
45
+ {% endfor %}
46
+
47
+ {% if has_iframe %}
48
+ return f'<div style="display: flex; flex-direction: row; gap: 10px; border: none; ">{{ iframe_links }}</div>'
49
+ {% endif %}
50
+ {% if has_iframe == false %}
51
+ return jsonify({})
52
+ {% endif %}
53
+
54
+ @app.route('/chart_graphics/<path:path>', methods=['GET','OPTIONS'])
55
+ def chart_graphics(path):
56
+ if request.method == 'OPTIONS':
57
+ return jsonify({"result": "ok"})
58
+
59
+ dashboards = get_dashboards()
60
+ if len(dashboards) == 0:
61
+ return jsonify({"result": "No dashboards Found"}), 404
62
+ if path in dashboards:
63
+ return dashboards[path]
64
+ return jsonify({"result": "not found"}), 404
65
+
66
+
67
+ ##############################
68
+ # generated queries follow
69
+ ##############################
70
+
71
+ def get_dashboards():
72
+ if len(dashboard_result) > 0:
73
+ return dashboard_result
74
+
75
+ from jinja2 import Environment, FileSystemLoader
76
+ env = Environment(loader = FileSystemLoader('ui/templates'))
77
+ template = env.get_template('bar_chart.jinja')
78
+
79
+ {% for dashboard in dashboards %}
80
+ {{dashboard}}
81
+ {% endfor %}
82
+
83
+ return dashboard_result
@@ -0,0 +1,34 @@
1
+ from functools import wraps
2
+ import logging
3
+ from flask_jwt_extended import get_jwt, jwt_required, verify_jwt_in_request
4
+ from config.config import Config, Args
5
+ from security.system.authorization import Security
6
+ import api.system.api_utils as api_utils
7
+ from typing import List
8
+ import safrs
9
+ import sqlalchemy
10
+ from flask import request, jsonify
11
+ from safrs import jsonapi_rpc, SAFRSAPI
12
+ from sqlalchemy.ext.hybrid import hybrid_property
13
+ from sqlalchemy.orm import object_mapper
14
+ from sqlalchemy import extract, func
15
+ from database import models
16
+ from flask_cors import cross_origin
17
+ from logic_bank.rule_bank.rule_bank import RuleBank
18
+ import integration.system.RowDictMapper as row_dict_mapper
19
+
20
+ # called by home.js to populate dashboard iFrame with results of all dsahboard queries
21
+
22
+ app_logger = logging.getLogger("api_logic_server_app")
23
+
24
+ def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
25
+ pass
26
+
27
+ api.expose_object(GraphicsDashboard) # Swagger-visible services
28
+
29
+
30
+ class GraphicsDashboard(safrs.JABase):
31
+ """GraphicsDashboard service - results of all dsahboard queries"""
32
+ result = []
33
+
34
+ {{dashboard_lines}}