ApiLogicServer 14.2.20__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 (100) hide show
  1. {ApiLogicServer-14.2.20.dist-info → ApiLogicServer-14.3.7.dist-info}/METADATA +2 -2
  2. {ApiLogicServer-14.2.20.dist-info → ApiLogicServer-14.3.7.dist-info}/RECORD +90 -69
  3. api_logic_server_cli/api_logic_server.py +5 -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__/api_logic_server_utils.cpython-312.pyc +0 -0
  7. api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
  8. api_logic_server_cli/create_from_model/__pycache__/ont_create.cpython-312.pyc +0 -0
  9. api_logic_server_cli/create_from_model/api_logic_server_utils.py +4 -0
  10. api_logic_server_cli/create_from_model/ont_build.py +53 -19
  11. api_logic_server_cli/create_from_model/ont_create.py +14 -5
  12. api_logic_server_cli/fragments/declare_logic.py +72 -0
  13. api_logic_server_cli/{prototypes/manager/system/genai/create_db_models_inserts/logic_discovery_prefix.py → fragments/declare_logic_begin.py} +2 -1
  14. api_logic_server_cli/fragments/declare_logic_end.py +52 -0
  15. api_logic_server_cli/genai/genai.py +25 -8
  16. api_logic_server_cli/genai/genai_logic_builder.py +14 -11
  17. api_logic_server_cli/genai/genai_svcs.py +104 -7
  18. api_logic_server_cli/manager.py +20 -16
  19. api_logic_server_cli/model_migrator/model_migrator_start.py +1 -1
  20. api_logic_server_cli/model_migrator/reposreader.py +9 -1
  21. api_logic_server_cli/model_migrator/rule_obj.py +24 -6
  22. api_logic_server_cli/prototypes/base/api/api_discovery/ontimize_api.py +4 -1
  23. api_logic_server_cli/prototypes/base/api/system/expression_parser.py +10 -4
  24. api_logic_server_cli/prototypes/base/config/activate_logicbank.py +8 -4
  25. api_logic_server_cli/prototypes/base/database/bind_dbs.py +1 -1
  26. api_logic_server_cli/prototypes/base/database/test_data/readme.md +5 -5
  27. api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +32 -8
  28. api_logic_server_cli/prototypes/base/integration/system/RowDictMapper.py +33 -16
  29. api_logic_server_cli/prototypes/base/logic/declare_logic.py +9 -3
  30. api_logic_server_cli/prototypes/base/logic/load_verify_rules.py +217 -0
  31. api_logic_server_cli/prototypes/base/logic/logic_discovery/auto_discovery.py +22 -13
  32. api_logic_server_cli/prototypes/genai_demo/api/customize_api.py +9 -11
  33. api_logic_server_cli/prototypes/genai_demo/database/.DS_Store +0 -0
  34. api_logic_server_cli/prototypes/genai_demo/database/db.sqlite +0 -0
  35. api_logic_server_cli/prototypes/genai_demo/database/models.py +52 -42
  36. api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/OrderB2B.py +4 -6
  37. api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/__pycache__/OrderB2B.cpython-312.pyc +0 -0
  38. api_logic_server_cli/prototypes/genai_demo/integration/row_dict_maps/row_dict_maps_readme.md +3 -0
  39. api_logic_server_cli/prototypes/genai_demo/logic/__pycache__/declare_logic.cpython-312.pyc +0 -0
  40. api_logic_server_cli/prototypes/genai_demo/logic/__pycache__/load_verify_rules.cpython-312.pyc +0 -0
  41. api_logic_server_cli/prototypes/genai_demo/logic/declare_logic.py +58 -62
  42. api_logic_server_cli/prototypes/genai_demo/logic/load_verify_rules.py +216 -0
  43. api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/__init__.cpython-312.pyc +0 -0
  44. api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/auto_discovery.cpython-312.pyc +0 -0
  45. api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/__pycache__/error_testing.cpython-312.pyc +0 -0
  46. api_logic_server_cli/prototypes/genai_demo/logic/logic_discovery/auto_discovery.py +52 -0
  47. api_logic_server_cli/prototypes/genai_demo/logic/readme_declare_logic.md +172 -0
  48. api_logic_server_cli/prototypes/genai_demo/security/__pycache__/declare_security.cpython-312.pyc +0 -0
  49. api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +86 -53
  50. api_logic_server_cli/prototypes/manager/.vscode/launch.json +1 -1
  51. api_logic_server_cli/prototypes/manager/README.md +19 -4
  52. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.prompt +4 -1
  53. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +34 -26
  54. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt +3 -0
  55. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/.DS_Store +0 -0
  56. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/000_you_are.prompt +1 -0
  57. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/001_logic_training.prompt +314 -0
  58. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/002_create_db_models.prompt +150 -0
  59. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/003_create_db_models.response +134 -0
  60. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/004_iteratio_logic.prompt +131 -0
  61. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/005_create_db_models.response-example +141 -0
  62. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/create_db_models.py +105 -0
  63. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/db.dbml +70 -0
  64. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/readme.md +6 -0
  65. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_iteration_discount/response.json +178 -0
  66. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/base_genai_demo_no_logic/logic/declare_logic.py +0 -1
  67. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/dev_demo_no_logic_fixed/logic/declare_logic.py +0 -1
  68. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/genai/examples/genai_demo/wg_dev_merge/base_genai_demo_no_logic/logic/declare_logic.py +0 -1
  69. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/genai/examples/genai_demo/wg_dev_merge/dev_demo_no_logic_fixed/logic/declare_logic.py +0 -1
  70. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/genai/examples/genai_demo/wg_dev_merge/wg_genai_demo_no_logic_fixed_from_CLI/logic/declare_logic.py +0 -1
  71. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/logic/declare_logic.py +0 -1
  72. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/system/genai/examples/genai_demo/wg_dev_merge/base_genai_demo_no_logic/logic/declare_logic.py +0 -1
  73. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/system/genai/examples/genai_demo/wg_dev_merge/dev_demo_no_logic_fixed/logic/declare_logic.py +0 -1
  74. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/wg_dev_merge/wg_demo_no_logic_fixed/system/genai/examples/genai_demo/wg_dev_merge/wg_genai_demo_no_logic_fixed_from_CLI/logic/declare_logic.py +0 -1
  75. api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/002_create_db_models.prompt +194 -0
  76. api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/003_create_db_models.response +298 -0
  77. api_logic_server_cli/prototypes/{genai_demo/database/chatgpt/sample_ai.sqlite → manager/system/genai/examples/time_tracking_billing/db.sqlite} +0 -0
  78. api_logic_server_cli/prototypes/manager/system/genai/examples/time_tracking_billing/readme.md +61 -0
  79. api_logic_server_cli/prototypes/manager/system/genai/learning_requests/logic_bank_api.prompt +29 -11
  80. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/iteration.prompt +2 -1
  81. api_logic_server_cli/prototypes/nw_no_cust/venv_setup/system_note.txt +1 -1
  82. api_logic_server_cli/prototypes/ont_app/templates/home_tree_template.html +9 -0
  83. api_logic_server_cli/prototypes/ont_app/templates/tree_routing.jinja +32 -0
  84. api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/__pycache__/codegen.cpython-312.pyc +0 -0
  85. api_logic_server_cli/sqlacodegen_wrapper/sqlacodegen/sqlacodegen/codegen.py +4 -2
  86. api_logic_server_cli/tools/mini_skel/logic/load_verify_rules.py +1 -1
  87. api_logic_server_cli/model_migrator/system/custom_endpoint.py +0 -545
  88. api_logic_server_cli/prototypes/base/database/test_data/z_test_data_rows.py +0 -98
  89. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/__pycache__/copilot_models.cpython-312.pyc +0 -0
  90. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/__pycache__/sample_ai_models.cpython-312.pyc +0 -0
  91. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai.chatgpt +0 -16
  92. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai.sql +0 -66
  93. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_items.sqlite +0 -0
  94. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_models.py +0 -156
  95. api_logic_server_cli/prototypes/genai_demo/database/chatgpt/sample_ai_models.sqlite +0 -0
  96. api_logic_server_cli/prototypes/genai_demo/logic/cocktail-napkin.jpg +0 -0
  97. {ApiLogicServer-14.2.20.dist-info → ApiLogicServer-14.3.7.dist-info}/LICENSE +0 -0
  98. {ApiLogicServer-14.2.20.dist-info → ApiLogicServer-14.3.7.dist-info}/WHEEL +0 -0
  99. {ApiLogicServer-14.2.20.dist-info → ApiLogicServer-14.3.7.dist-info}/entry_points.txt +0 -0
  100. {ApiLogicServer-14.2.20.dist-info → ApiLogicServer-14.3.7.dist-info}/top_level.txt +0 -0
@@ -23,21 +23,30 @@ def discover_logic():
23
23
  spec.loader.exec_module(each_logic_file) # runs "bare" module code (e.g., initialization)
24
24
  each_logic_file.declare_logic() # invoke create function
25
25
 
26
- if False and Path(__file__).parent.parent.parent.joinpath("docs/project_is_genai_demo.txt").exists():
27
- return # for genai_demo, logic is in logic/declare_logic.py (so ignore logic_discovery)
26
+ # if False and Path(__file__).parent.parent.parent.joinpath("docs/project_is_genai_demo.txt").exists():
27
+ # return # for genai_demo, logic is in logic/declare_logic.py (so ignore logic_discovery)
28
28
 
29
29
  wg_logic_path = Path(__file__).parent.parent.joinpath("wg_rules")
30
- for root, dirs, files in os.walk(wg_logic_path):
31
- for file in files:
32
- if file.endswith(".py"):
33
- spec = importlib.util.spec_from_file_location("module.name", wg_logic_path.joinpath(file))
34
- if file.endswith("auto_discovery.py"):
35
- pass
36
- else:
37
- logic.append(file)
38
- each_logic_file = importlib.util.module_from_spec(spec)
39
- spec.loader.exec_module(each_logic_file) # runs "bare" module code (e.g., initialization)
40
- each_logic_file.init_rule() # invoke create function
30
+ if wg_logic_path.exists():
31
+ run_local = os.environ.get("WG_PROJECT") is None # eg, running export locally
32
+ # run_local = False # for debug
33
+ if run_local:
34
+ wg_export_logic_path = Path(__file__).parent.parent.parent.joinpath("logic/wg_rules/active_rules_export.py")
35
+ if wg_export_logic_path.is_file():
36
+ spec = importlib.util.spec_from_file_location("module.name", wg_export_logic_path)
37
+ logic.append(str(wg_export_logic_path))
38
+ wg_export_logic_file = importlib.util.module_from_spec(spec)
39
+ spec.loader.exec_module(wg_export_logic_file) # runs "bare" module code (e.g., initialization)
40
+ wg_export_logic_file.declare_logic() # invoke create function
41
+ else:
42
+ for root, dirs, files in os.walk(wg_logic_path):
43
+ for file in files:
44
+ if file.endswith(".py") and 'active_rules_export.py' != file:
45
+ spec = importlib.util.spec_from_file_location("module.name", wg_logic_path.joinpath(file))
46
+ logic.append(file)
47
+ each_logic_file = importlib.util.module_from_spec(spec)
48
+ spec.loader.exec_module(each_logic_file) # runs "bare" module code (e.g., initialization)
49
+ each_logic_file.init_rule() # invoke create function
41
50
 
42
51
  app_logger.info(f"..discovered logic: {logic}")
43
52
  return
@@ -5,8 +5,8 @@ from flask import request, jsonify
5
5
  from safrs import jsonapi_rpc
6
6
  from database import models
7
7
  import integration.system.RowDictMapper as row_dict_mapper
8
- from integration.row_dict_maps.OrderShipping import OrderShipping
9
- from integration.row_dict_maps.OrderB2B import OrderB2B
8
+ # from integration.row_dict_maps.OrderShipping import OrderShipping
9
+ from integration.row_dict_maps.OrderB2B import OrderB2B # TODO - how to drive; B2B...
10
10
 
11
11
  # called by api_logic_server_run.py, to customize api (new end points, services).
12
12
  # separate from expose_api_models.py, to simplify merge if project recreated
@@ -140,15 +140,13 @@ class ServicesEndPoint(safrs.JABase):
140
140
  """ # yaml creates Swagger description
141
141
  args :
142
142
  order:
143
- Account: "Jane Smith"
143
+ Account: "Alice"
144
144
  Notes: "Please Rush"
145
145
  Items :
146
- - ProductName: "Widget A"
146
+ - ProductName: "Product 1"
147
147
  QuantityOrdered: 1
148
- - ProductName: "Gadget B"
148
+ - ProductName: "Product 2"
149
149
  QuantityOrdered: 2
150
- - ProductName: "Green Apples"
151
- QuantityOrdered: 3
152
150
  ---
153
151
 
154
152
  Note attribute alias, Lookup automation in OrderB2B
@@ -159,19 +157,19 @@ class ServicesEndPoint(safrs.JABase):
159
157
  $(venv) ApiLogicServer login --user=admin --password=p
160
158
  $(venv) ApiLogicServer curl "'POST' 'http://localhost:5656/api/ServicesEndPoint/OrderB2B'" --data '
161
159
  {"meta": {"args": {"order": {
162
- "Account": "Jane Smith",
160
+ "Account": "Alice",
163
161
  "Notes": "Please Rush",
164
162
  "Items": [
165
163
  {
166
- "ProductName": "Widget A",
164
+ "ProductName": "Product 1",
167
165
  "QuantityOrdered": 1
168
166
  },
169
167
  {
170
- "ProductName": "Gadget B",
168
+ "ProductName": "Product 2",
171
169
  "QuantityOrdered": 2
172
170
  },
173
171
  {
174
- "ProductName": "Gadget B",
172
+ "ProductName": "Green Apples",
175
173
  "QuantityOrdered": 2
176
174
  }
177
175
  ]
@@ -1,5 +1,6 @@
1
1
  # coding: utf-8
2
- from sqlalchemy import Boolean, Column, DECIMAL, DateTime, ForeignKey, Integer, Text, text
2
+ from sqlalchemy import DECIMAL, DateTime # API Logic Server GenAI assist
3
+ from sqlalchemy import Column, Date, ForeignKey, Integer, Numeric, String, Boolean
3
4
  from sqlalchemy.orm import relationship
4
5
  from sqlalchemy.ext.declarative import declarative_base
5
6
 
@@ -9,13 +10,13 @@ from sqlalchemy.ext.declarative import declarative_base
9
10
  # Alter this file per your database maintenance policy
10
11
  # See https://apilogicserver.github.io/Docs/Project-Rebuild/#rebuilding
11
12
  #
12
- # Created: May 03, 2024 22:23:08
13
- # Database: sqlite:////Users/val/dev/ApiLogicServer/ApiLogicServer-dev/clean/ApiLogicServer/genai_demo/database/db.sqlite
13
+ # Created: January 31, 2025 17:52:29
14
+ # Database: sqlite:////Users/val/dev/ApiLogicServer/ApiLogicServer-dev/build_and_test/ApiLogicServer/genai_demo/database/db.sqlite
14
15
  # Dialect: sqlite
15
16
  #
16
17
  # mypy: ignore-errors
17
18
  ########################################################################################################################
18
-
19
+
19
20
  from database.system.SAFRSBaseX import SAFRSBaseX, TestBase
20
21
  from flask_login import UserMixin
21
22
  import safrs, flask_sqlalchemy, os
@@ -42,72 +43,81 @@ else:
42
43
  print('*** Models.py Using TestBase ***')
43
44
 
44
45
 
45
- class Customer(Base):
46
- __tablename__ = 'Customers'
46
+
47
+ class Customer(Base): # type: ignore
48
+ """
49
+ description: Customer table with unique name, balance and credit_limit.
50
+ """
51
+ __tablename__ = 'customer'
47
52
  _s_collection_name = 'Customer' # type: ignore
48
53
 
49
- CustomerID = Column(Integer, primary_key=True)
50
- CustomerName = Column(Text, nullable=False)
51
- Address = Column(Text)
52
- Phone = Column(Text)
53
- Balance : DECIMAL = Column(DECIMAL(10, 2))
54
- CreditLimit : DECIMAL = Column(DECIMAL(10, 2), nullable=False)
54
+ id = Column(Integer, primary_key=True)
55
+ name = Column(String(255), unique=True)
56
+ balance = Column(Numeric)
57
+ credit_limit = Column(Numeric)
55
58
 
56
59
  # parent relationships (access parent)
57
60
 
58
61
  # child relationships (access children)
59
- OrderList : Mapped[List["Order"]] = relationship(back_populates="Customer")
62
+ OrderList : Mapped[List["Order"]] = relationship(back_populates="customer")
60
63
 
61
64
 
62
- class Product(Base):
63
- __tablename__ = 'Products'
64
- _s_collection_name = 'Product' # type: ignore
65
65
 
66
- ProductID = Column(Integer, primary_key=True)
67
- ProductName = Column(Text, nullable=False)
68
- UnitPrice : DECIMAL = Column(DECIMAL(10, 2), nullable=False)
69
- CarbonNeutral = Column(Boolean)
66
+ class Product(Base): # type: ignore
67
+ """
68
+ description: Product table with unit_price used for copying to Item.
69
+ """
70
+ __tablename__ = 'product'
71
+ _s_collection_name = 'Product' # type: ignore
70
72
 
73
+ id = Column(Integer, primary_key=True)
74
+ name = Column(String(255))
75
+ unit_price = Column(Numeric)
76
+ carbon_neutral = Column(Boolean)
71
77
  # parent relationships (access parent)
72
78
 
73
79
  # child relationships (access children)
74
- ItemList : Mapped[List["Item"]] = relationship(back_populates="Product")
80
+ ItemList : Mapped[List["Item"]] = relationship(back_populates="product")
75
81
 
76
82
 
77
83
 
78
- class Order(Base):
79
- __tablename__ = 'Orders'
84
+ class Order(Base): # type: ignore
85
+ """
86
+ description: Order table with a foreign key to Customer, a notes field, date_shipped and derived amount_total.
87
+ """
88
+ __tablename__ = 'order'
80
89
  _s_collection_name = 'Order' # type: ignore
81
90
 
82
- OrderID = Column(Integer, primary_key=True)
83
- CustomerID = Column(ForeignKey('Customers.CustomerID'))
84
- OrderDate = Column(DateTime, server_default=text("CURRENT_TIMESTAMP"))
85
- Notes = Column(Text)
86
- ShipDate = Column(DateTime)
87
- AmountTotal : DECIMAL = Column(DECIMAL(10, 2))
91
+ id = Column(Integer, primary_key=True)
92
+ customer_id = Column(ForeignKey('customer.id'))
93
+ date_shipped = Column(Date)
94
+ notes = Column(String(255))
95
+ amount_total = Column(Numeric)
88
96
 
89
97
  # parent relationships (access parent)
90
- Customer : Mapped["Customer"] = relationship(back_populates=("OrderList"))
98
+ customer : Mapped["Customer"] = relationship(back_populates=("OrderList"))
91
99
 
92
100
  # child relationships (access children)
93
- ItemList : Mapped[List["Item"]] = relationship(back_populates="Order")
101
+ ItemList : Mapped[List["Item"]] = relationship(back_populates="order")
94
102
 
95
103
 
96
104
 
97
- class Item(Base):
98
- __tablename__ = 'Items'
105
+ class Item(Base): # type: ignore
106
+ """
107
+ description: Item table with non-null quantity, derived amount and unit_price copied from Product.
108
+ """
109
+ __tablename__ = 'item'
99
110
  _s_collection_name = 'Item' # type: ignore
100
111
 
101
- ItemID = Column(Integer, primary_key=True)
102
- OrderID = Column(ForeignKey('Orders.OrderID'))
103
- ProductID = Column(ForeignKey('Products.ProductID'))
104
- Quantity = Column(Integer, nullable=False)
105
- UnitPrice : DECIMAL = Column(DECIMAL(10, 2))
106
- Amount : DECIMAL = Column(DECIMAL(10, 2))
112
+ id = Column(Integer, primary_key=True)
113
+ order_id = Column(ForeignKey('order.id'))
114
+ product_id = Column(ForeignKey('product.id'))
115
+ quantity = Column(Integer, nullable=False)
116
+ unit_price = Column(Numeric)
117
+ amount = Column(Numeric)
107
118
 
108
119
  # parent relationships (access parent)
109
- Order : Mapped["Order"] = relationship(back_populates=("ItemList"))
110
- Product : Mapped["Product"] = relationship(back_populates=("ItemList"))
120
+ order : Mapped["Order"] = relationship(back_populates=("ItemList"))
121
+ product : Mapped["Product"] = relationship(back_populates=("ItemList"))
111
122
 
112
123
  # child relationships (access children)
113
-
@@ -19,15 +19,13 @@ class OrderB2B(RowDictMapper):
19
19
  order = super(OrderB2B, self).__init__(
20
20
  model_class=models.Order
21
21
  , alias = "order"
22
- , fields = [(models.Order.Notes)]
23
- , parent_lookups = [( models.Customer,
24
- [(models.Customer.CustomerName, 'Account')]
25
- )]
22
+ , fields = [(models.Order.notes, "Notes")]
23
+ , parent_lookups = [( models.Customer, [(models.Customer.name, 'Account')] )]
26
24
  , related = [
27
25
  (RowDictMapper(model_class=models.Item
28
26
  , alias="Items"
29
- , fields = [(models.Item.Quantity, "QuantityOrdered")]
30
- , parent_lookups = [( models.Product, [models.Product.ProductName] )]
27
+ , fields = [(models.Item.quantity, "QuantityOrdered")]
28
+ , parent_lookups = [( models.Product, [(models.Product.name, 'ProductName')] )]
31
29
  )
32
30
  )
33
31
  ]
@@ -0,0 +1,3 @@
1
+ Create definitions here to configure mappings for row <-> dicts, typically for application integration.
2
+
3
+ To see a Sample Integration, [click here](https://apilogicserver.github.io/Docs/Sample-Integration/).
@@ -1,16 +1,15 @@
1
- import datetime
1
+ import datetime, os
2
2
  from decimal import Decimal
3
3
  from logic_bank.exec_row_logic.logic_row import LogicRow
4
4
  from logic_bank.extensions.rule_extensions import RuleExtension
5
5
  from logic_bank.logic_bank import Rule
6
- from database.models import *
7
- from database.models import Customer, Order, Item, Product
6
+ from logic_bank.logic_bank import DeclareRule
7
+ import database.models as models
8
8
  import api.system.opt_locking.opt_locking as opt_locking
9
- from security.system.authorization import Grant
10
- import logging, os
11
- from integration.row_dict_maps.OrderShipping import OrderShipping
12
- from confluent_kafka import Producer, KafkaException
9
+ from security.system.authorization import Grant, Security
10
+ from logic.load_verify_rules import load_verify_rules
13
11
  import integration.kafka.kafka_producer as kafka_producer
12
+ import logging
14
13
 
15
14
  app_logger = logging.getLogger(__name__)
16
15
 
@@ -22,94 +21,91 @@ def declare_logic():
22
21
  Brief background: see readme_declare_logic.md
23
22
 
24
23
  Your Code Goes Here - Use code completion (Rule.) to declare rules
25
-
26
- GenAI: Paste the following into Copilot Chat, and paste the result below.
27
-
28
- Use Logic Bank to enforce these requirements:
29
-
30
- Enforce the Check Credit requirement (do not generate check constraints):
31
- 1. Customer.Balance <= CreditLimit
32
- 2. Customer.Balance = Sum(Order.AmountTotal where date shipped is null)
33
- 3. Order.AmountTotal = Sum(Items.Amount)
34
- 4. Items.Amount = Quantity * UnitPrice
35
- 5. Store the Items.UnitPrice as a copy from Product.UnitPrice
36
24
  '''
37
25
 
38
- from logic_bank.logic_bank import Rule
26
+ if os.environ.get("WG_PROJECT"):
27
+ # Inside WG: Load rules from docs/expprt/export.json
28
+ load_verify_rules()
29
+ else:
30
+ # Outside WG: load declare_logic function
31
+ from logic.logic_discovery.auto_discovery import discover_logic
32
+ discover_logic()
39
33
 
40
- from logic.logic_discovery.auto_discovery import discover_logic
41
- discover_logic()
34
+ # Logic from GenAI: (or, use your IDE w/ code completion)
35
+ from database.models import Product, Customer, Item, Order
42
36
 
43
- # Logic from GenAI: (or, use your IDE w/ code completion)n
44
- Rule.sum(derive=Customer.Balance, as_sum_of=Order.AmountTotal, where=lambda row: row.ShipDate is None)
45
- Rule.sum(derive=Order.AmountTotal, as_sum_of=Item.Amount)
46
- # Rule.formula(derive=Item.amount, as_expression=lambda row: row.quantity * row.unit_price)
47
- Rule.copy(derive=Item.UnitPrice, from_parent=Product.UnitPrice)
37
+ # Ensure that Customer balance does not exceed credit_limit.
48
38
  Rule.constraint(validate=Customer,
49
- as_condition=lambda row: row.Balance <= row.CreditLimit,
50
- error_msg="Customer balance ({row.Balance}) exceeds credit limit ({row.CreditLimit})")
39
+ as_condition=lambda row: row.balance <= row.credit_limit,
40
+ error_msg="Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})")
51
41
 
52
- # End Logic from GenAI
42
+ # Customer.balance is the sum of Order.amount_total for orders not yet shipped.
43
+ Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total, where=lambda row: row.date_shipped is None)
44
+
45
+ # Order.amount_total is the sum of Item.amount.
46
+ Rule.sum(derive=Order.amount_total, as_sum_of=Item.amount)
53
47
 
54
- def derive_amount(row: Item, old_row: Item, logic_row: LogicRow):
48
+ def derive_amount(row: models.Item, old_row: models.Item, logic_row: LogicRow):
55
49
  amount = row.Quantity * row.UnitPrice
56
50
  if row.Product.CarbonNeutral == True and row.Quantity >= 10:
57
51
  amount = amount * Decimal(0.9) # breakpoint here
58
52
  return amount
59
53
 
60
- # 4. Items.Amount = Quantity * UnitPrice
61
- Rule.formula(derive=Item.Amount, calling=derive_amount)
54
+ # Items.Amount = Quantity * UnitPrice with discount for CarbonNeutral products.
55
+ Rule.formula(derive=models.Item.Amount,
56
+ calling=derive_amount)
62
57
 
63
- #als: Demonstrate that logic == Rules + Python (for extensibility)
58
+ # Item.unit_price is copied from Product.unit_price.
59
+ Rule.copy(derive=Item.unit_price, from_parent=Product.unit_price)
64
60
 
65
- def send_order_to_shipping(row: Order, old_row: Order, logic_row: LogicRow):
66
- """ #als: Send Kafka message formatted by OrderShipping RowDictMapper
67
-
68
- Format row per shipping requirements, and send (e.g., a message)
69
-
70
- NB: the after_flush event makes Order.Id avaible. Contrast to congratulate_sales_rep().
71
-
72
- Args:
73
- row (Order): inserted Order
74
- old_row (Order): n/a
75
- logic_row (LogicRow): bundles curr/old row, with ins/upd/dlt logic
76
- """
77
- if logic_row.is_inserted():
78
- kafka_producer.send_kafka_message(logic_row=logic_row,
79
- row_dict_mapper=OrderShipping,
80
- kafka_topic="order_shipping",
81
- kafka_key=str(row.OrderID),
82
- msg="Sending Order to Shipping")
83
-
84
- Rule.after_flush_row_event(on_class=Order, calling=send_order_to_shipping) # see above
61
+ # Send the Order to Kafka topic 'order_shipping' if the date_shipped is not None.
62
+ Rule.after_flush_row_event(on_class=Order, calling=kafka_producer.send_row_to_kafka,
63
+ if_condition=lambda row: row.date_shipped is not None,
64
+ with_args={'topic': 'order_shipping'})
85
65
 
66
+ # End Logic from GenAI
86
67
 
87
68
 
88
- def handle_all(logic_row: LogicRow): # OPTIMISTIC LOCKING, [TIME / DATE STAMPING]
69
+ def handle_all(logic_row: LogicRow): # #als: TIME / DATE STAMPING, OPTIMISTIC LOCKING
89
70
  """
90
71
  This is generic - executed for all classes.
91
72
 
92
- Invokes optimistic locking.
73
+ Invokes optimistic locking, and checks Grant permissions.
93
74
 
94
- You can optionally do time and date stamping here, as shown below.
75
+ Also provides user/date stamping.
95
76
 
96
77
  Args:
97
78
  logic_row (LogicRow): from LogicBank - old/new row, state
98
79
  """
99
80
 
100
- if not os.getenv("APILOGICPROJECT_NO_FLASK") is not None:
81
+ if os.getenv("APILOGICPROJECT_NO_FLASK") is not None:
82
+ print("\ndeclare_logic.py Using TestBase\n")
101
83
  return # enables rules to be used outside of Flask, e.g., test data loading
102
84
 
103
85
  if logic_row.is_updated() and logic_row.old_row is not None and logic_row.nest_level == 0:
104
86
  opt_locking.opt_lock_patch(logic_row=logic_row)
105
- enable_creation_stamping = False # CreatedOn time stamping
106
- if enable_creation_stamping:
87
+
88
+ Grant.process_updates(logic_row=logic_row)
89
+
90
+ did_stamping = False
91
+ if enable_stamping := False: # #als: DATE / USER STAMPING
107
92
  row = logic_row.row
108
93
  if logic_row.ins_upd_dlt == "ins" and hasattr(row, "CreatedOn"):
109
94
  row.CreatedOn = datetime.datetime.now()
110
- logic_row.log("early_row_event_all_classes - handle_all sets 'Created_on"'')
111
- Grant.process_updates(logic_row=logic_row)
112
-
95
+ did_stamping = True
96
+ if logic_row.ins_upd_dlt == "ins" and hasattr(row, "CreatedBy"):
97
+ row.CreatedBy = Security.current_user().id
98
+ # if Config.SECURITY_ENABLED == True else 'public'
99
+ did_stamping = True
100
+ if logic_row.ins_upd_dlt == "upd" and hasattr(row, "UpdatedOn"):
101
+ row.UpdatedOn = datetime.datetime.now()
102
+ did_stamping = True
103
+ if logic_row.ins_upd_dlt == "upd" and hasattr(row, "UpdatedBy"):
104
+ row.UpdatedBy = Security.current_user().id \
105
+ if Config.SECURITY_ENABLED == True else 'public'
106
+ did_stamping = True
107
+ if did_stamping:
108
+ logic_row.log("early_row_event_all_classes - handle_all did stamping")
113
109
  Rule.early_row_event_all_classes(early_row_event_all_classes=handle_all)
114
110
 
115
111
  #als rules report