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
@@ -0,0 +1,298 @@
1
+ {
2
+ "models": [
3
+ {
4
+ "classname": "Client",
5
+ "code": "class Client(Base):\n __tablename__ = 'client'\n\n id = Column(Integer, primary_key=True)\n name = Column(String, nullable=False)\n email = Column(String, nullable=False)\n phone = Column(String, nullable=False)\n total_hours = Column(DECIMAL(10, 2), default=0)\n total_amount = Column(DECIMAL(10, 2), default=0)\n budget_amount = Column(DECIMAL(10, 2), default=0)\n is_over_budget = Column(Boolean, default=False)",
6
+ "description": "Model representing clients for billing.",
7
+ "name": "Client"
8
+ },
9
+ {
10
+ "classname": "Project",
11
+ "code": "class Project(Base):\n __tablename__ = 'project'\n\n id = Column(Integer, primary_key=True)\n client_id = Column(Integer, ForeignKey('client.id'))\n name = Column(String, nullable=False)\n total_project_hours = Column(DECIMAL(10, 2), default=0)\n total_project_amount = Column(DECIMAL(10, 2), default=0)\n project_budget_amount = Column(DECIMAL(10, 2), default=0)\n is_over_budget = Column(Boolean, default=False)",
12
+ "description": "Model representing projects under a client.",
13
+ "name": "Project"
14
+ },
15
+ {
16
+ "classname": "Invoice",
17
+ "code": "class Invoice(Base):\n __tablename__ = 'invoice'\n\n id = Column(Integer, primary_key=True)\n invoice_date = Column(DateTime, nullable=False)\n project_id = Column(Integer, ForeignKey('project.id'))\n invoice_amount = Column(DECIMAL(10, 2), default=0)\n payment_total = Column(DECIMAL(10, 2), default=0)\n invoice_balance = Column(DECIMAL(10, 2), default=0)\n is_paid = Column(Boolean, default=False)",
18
+ "description": "Model representing invoices for projects.",
19
+ "name": "Invoice"
20
+ },
21
+ {
22
+ "classname": "Task",
23
+ "code": "class Task(Base):\n __tablename__ = 'task'\n\n id = Column(Integer, primary_key=True)\n project_id = Column(Integer, ForeignKey('project.id'))\n name = Column(String, nullable=False)\n description = Column(String, nullable=True)\n total_task_hours_worked = Column(DECIMAL(10, 2), default=0)\n total_task_amount_billed = Column(DECIMAL(10, 2), default=0)\n task_budget_hours = Column(DECIMAL(10, 2), default=0)\n is_over_budget = Column(Boolean, default=False)\n invoice_id = Column(Integer, ForeignKey('invoice.id'))",
24
+ "description": "Model representing tasks under a project.",
25
+ "name": "Task"
26
+ },
27
+ {
28
+ "classname": "Person",
29
+ "code": "class Person(Base):\n __tablename__ = 'person'\n\n id = Column(Integer, primary_key=True)\n client_id = Column(Integer, ForeignKey('client.id'))\n name = Column(String, nullable=False)\n email = Column(String, nullable=False)\n phone = Column(String, nullable=False)\n billing_rate = Column(DECIMAL(10, 2), default=0)\n total_hours_entered = Column(DECIMAL(10, 2), default=0)\n total_amount_billed = Column(DECIMAL(10, 2), default=0)",
30
+ "description": "Model representing personnel working with clients.",
31
+ "name": "Person"
32
+ },
33
+ {
34
+ "classname": "Timesheet",
35
+ "code": "class Timesheet(Base):\n __tablename__ = 'timesheet'\n\n id = Column(Integer, primary_key=True)\n task_id = Column(Integer, ForeignKey('task.id'))\n person_id = Column(Integer, ForeignKey('person.id'))\n date_worked = Column(DateTime, nullable=False)\n hours_worked = Column(DECIMAL(10, 2), default=0)\n month = Column(Integer)\n year = Column(Integer)\n billing_rate = Column(DECIMAL(10, 2), default=0)\n total_amount_billed = Column(DECIMAL(10, 2), default=0)",
36
+ "description": "Model representing timesheets for tasks.",
37
+ "name": "Timesheet"
38
+ },
39
+ {
40
+ "classname": "Payment",
41
+ "code": "class Payment(Base):\n __tablename__ = 'payment'\n\n id = Column(Integer, primary_key=True)\n invoice_id = Column(Integer, ForeignKey('invoice.id'))\n payment_amount = Column(DECIMAL(10, 2), default=0)\n payment_date = Column(Date, nullable=False)\n notes = Column(String, nullable=True)",
42
+ "description": "Model representing payments made against invoices.",
43
+ "name": "Payment"
44
+ }
45
+ ],
46
+ "rules": [
47
+ {
48
+ "name": "Sum Client Total Hours",
49
+ "description": "Total Hours is the sum of Project total project hours",
50
+ "use_case": "Client",
51
+ "entity": "Client",
52
+ "code": "Rule.sum(derive=Client.total_hours, as_sum_of=Project.total_project_hours)"
53
+ },
54
+ {
55
+ "name": "Sum Client Total Amount",
56
+ "description": "Total Amount is the sum of Project total amount",
57
+ "use_case": "Client",
58
+ "entity": "Client",
59
+ "code": "Rule.sum(derive=Client.total_amount, as_sum_of=Project.total_project_amount)"
60
+ },
61
+ {
62
+ "name": "Formula: Client Is Over Budget",
63
+ "description": "Is Over Budget is true when total amount exceeds budget amount",
64
+ "use_case": "Client",
65
+ "entity": "Client",
66
+ "code": "Rule.formula(derive=Client.is_over_budget, as_expression=lambda row: row.total_amount > row.budget_amount)"
67
+ },
68
+ {
69
+ "name": "Sum Project Total Project Hours",
70
+ "description": "Total project hours is the sum of Task total task hours worked",
71
+ "use_case": "Project",
72
+ "entity": "Project",
73
+ "code": "Rule.sum(derive=Project.total_project_hours, as_sum_of=Task.total_task_hours_worked)"
74
+ },
75
+ {
76
+ "name": "Sum Project Total Project Amount",
77
+ "description": "Total project amount is the sum of Task total amount billed",
78
+ "use_case": "Project",
79
+ "entity": "Project",
80
+ "code": "Rule.sum(derive=Project.total_project_amount, as_sum_of=Task.total_task_amount_billed)"
81
+ },
82
+ {
83
+ "name": "Formula: Project Is Over Budget",
84
+ "description": "Is Over Budget when total project amount exceeds project budget amount",
85
+ "use_case": "Project",
86
+ "entity": "Project",
87
+ "code": "Rule.formula(derive=Project.is_over_budget, as_expression=lambda row: row.total_project_amount > row.project_budget_amount)"
88
+ },
89
+ {
90
+ "name": "Sum Task Total Task Hours Worked",
91
+ "description": "Total task hours worked is the sum of the Timesheet hours worked",
92
+ "use_case": "Task",
93
+ "entity": "Task",
94
+ "code": "Rule.sum(derive=Task.total_task_hours_worked, as_sum_of=Timesheet.hours_worked)"
95
+ },
96
+ {
97
+ "name": "Sum Task Total Task Amount Billed",
98
+ "description": "Total task amount billed is the sum of the Timesheet total amount billed",
99
+ "use_case": "Task",
100
+ "entity": "Task",
101
+ "code": "Rule.sum(derive=Task.total_task_amount_billed, as_sum_of=Timesheet.total_amount_billed)"
102
+ },
103
+ {
104
+ "name": "Formula: Task Is Over Budget",
105
+ "description": "Formula: is Over Budget when total task hours worked exceeds task budget hours",
106
+ "use_case": "Task",
107
+ "entity": "Task",
108
+ "code": "Rule.formula(derive=Task.is_over_budget, as_expression=lambda row: row.total_task_hours_worked > row.task_budget_hours)"
109
+ },
110
+ {
111
+ "name": "Copy Timesheet Billing Rate",
112
+ "description": "Copy billing rate from Person billing rate",
113
+ "use_case": "Timesheet",
114
+ "entity": "Timesheet",
115
+ "code": "Rule.copy(derive=Timesheet.billing_rate, from_parent=Person.billing_rate)"
116
+ },
117
+ {
118
+ "name": "Formula Timesheet Total Amount Billed",
119
+ "description": "The total amount billed is the Person billing rate times hours worked",
120
+ "use_case": "Timesheet",
121
+ "entity": "Timesheet",
122
+ "code": "Rule.formula(derive=Timesheet.total_amount_billed, as_expression=lambda row: row.billing_rate * row.hours_worked)"
123
+ },
124
+ {
125
+ "name": "Timesheet Hours Constraint",
126
+ "description": "Hours worked must be greater than 0 and less than 15",
127
+ "use_case": "Timesheet",
128
+ "entity": "Timesheet",
129
+ "code": "Rule.constraint(validate=Timesheet, as_condition=lambda row: 0 < row.hours_worked < 15, error_msg='Hours worked must be > 0 and < 15')"
130
+ },
131
+ {
132
+ "name": "Sum Person Total Hours Entered",
133
+ "description": "Total Hours entered is sum of timesheet hours worked",
134
+ "use_case": "Person",
135
+ "entity": "Person",
136
+ "code": "Rule.sum(derive=Person.total_hours_entered, as_sum_of=Timesheet.hours_worked)"
137
+ },
138
+ {
139
+ "name": "Formula Person Total Amount Billed",
140
+ "description": "Total amount billed is total hours entered times billing rate",
141
+ "use_case": "Person",
142
+ "entity": "Person",
143
+ "code": "Rule.formula(derive=Person.total_amount_billed, as_expression=lambda row: row.total_hours_entered * row.billing_rate)"
144
+ },
145
+ {
146
+ "name": "Person Billing Rate Constraint",
147
+ "description": "Billing rate must be greater than 0 and less than 200",
148
+ "use_case": "Person",
149
+ "entity": "Person",
150
+ "code": "Rule.constraint(validate=Person, as_condition=lambda row: 0 < row.billing_rate < 200, error_msg='Billing rate must be > 0 and < 200')"
151
+ },
152
+ {
153
+ "name": "Sum Invoice Invoice Amount",
154
+ "description": "Invoice Amount is the sum of Task total amount billed",
155
+ "use_case": "Invoice",
156
+ "entity": "Invoice",
157
+ "code": "Rule.sum(derive=Invoice.invoice_amount, as_sum_of=Task.total_task_amount_billed)"
158
+ },
159
+ {
160
+ "name": "Sum Invoice Payment Total",
161
+ "description": "Payment total is the sum of Payment",
162
+ "use_case": "Invoice",
163
+ "entity": "Invoice",
164
+ "code": "Rule.sum(derive=Invoice.payment_total, as_sum_of=Payment.payment_amount)"
165
+ },
166
+ {
167
+ "name": "Formula Invoice Balance",
168
+ "description": "Invoice balance is invoice amount less payment total",
169
+ "use_case": "Invoice",
170
+ "entity": "Invoice",
171
+ "code": "Rule.formula(derive=Invoice.invoice_balance, as_expression=lambda row: row.invoice_amount - row.payment_total)"
172
+ },
173
+ {
174
+ "name": "Formula Invoice Is Paid",
175
+ "description": "Invoice is paid when invoice balance is zero",
176
+ "use_case": "Invoice",
177
+ "entity": "Invoice",
178
+ "code": "Rule.formula(derive=Invoice.is_paid, as_expression=lambda row: row.invoice_balance == 0)"
179
+ }
180
+ ],
181
+ "test_data": "# Test data for Client\nclient1 = Client(id=1, name=\"Acme Corp\", email=\"acme@acme.com\", phone=\"123-456-7890\", total_hours=20, total_amount=5000, budget_amount=10000)\nclient2 = Client(id=2, name=\"Beta LLC\", email=\"beta@beta.com\", phone=\"987-654-3210\", total_hours=15, total_amount=3000, budget_amount=5000)\nclient3 = Client(id=3, name=\"Gamma Industries\", email=\"gamma@gamma.com\", phone=\"456-123-6789\", total_hours=30, total_amount=12000, budget_amount=15000)\nclient4 = Client(id=4, name=\"Delta Services\", email=\"delta@delta.com\", phone=\"789-321-6540\", total_hours=45, total_amount=9000, budget_amount=20000)\n\n# Test data for Project\nproject1 = Project(id=1, client_id=1, name=\"Project X\", total_project_hours=50, total_project_amount=8000, project_budget_amount=10000)\nproject2 = Project(id=2, client_id=1, name=\"Project Y\", total_project_hours=25, total_project_amount=4000, project_budget_amount=7000)\nproject3 = Project(id=3, client_id=2, name=\"Project Z\", total_project_hours=30, total_project_amount=3000, project_budget_amount=4000)\nproject4 = Project(id=4, client_id=3, name=\"Project Alpha\", total_project_hours=60, total_project_amount=15000, project_budget_amount=20000)\n\n# Test data for Invoice\ninvoice1 = Invoice(id=1, project_id=1, invoice_date=date(2023, 2, 15), invoice_amount=5000, payment_total=3000, invoice_balance=2000)\ninvoice2 = Invoice(id=2, project_id=2, invoice_date=date(2023, 3, 20), invoice_amount=1000, payment_total=1000, invoice_balance=0)\ninvoice3 = Invoice(id=3, project_id=3, invoice_date=date(2023, 4, 11), invoice_amount=2000, payment_total=1500, invoice_balance=500)\ninvoice4 = Invoice(id=4, project_id=4, invoice_date=date(2023, 5, 9), invoice_amount=7000, payment_total=5000, invoice_balance=2000)\n\n# Test data for Task\ntask1 = Task(id=1, project_id=1, name=\"Design Phase\", description=\"Initial design work\", total_task_hours_worked=15, total_task_amount_billed=1500, task_budget_hours=20)\ntask2 = Task(id=2, project_id=2, name=\"Development Phase\", description=\"Coding and implementation\", total_task_hours_worked=30, total_task_amount_billed=3000, task_budget_hours=40)\ntask3 = Task(id=3, project_id=3, name=\"Testing Phase\", description=\"QA and testing\", total_task_hours_worked=10, total_task_amount_billed=1000, task_budget_hours=15)\ntask4 = Task(id=4, project_id=4, name=\"Deployment Phase\", description=\"Deployment and support\", total_task_hours_worked=20, total_task_amount_billed=2000, task_budget_hours=25)\n\n# Test data for Person\nperson1 = Person(id=1, client_id=1, name=\"Alice Smith\", email=\"alice@example.com\", phone=\"111-222-3333\", billing_rate=50, total_hours_entered=10, total_amount_billed=500)\nperson2 = Person(id=2, client_id=2, name=\"Bob Brown\", email=\"bob@example.com\", phone=\"444-555-6666\", billing_rate=75, total_hours_entered=8, total_amount_billed=600)\nperson3 = Person(id=3, client_id=3, name=\"Charlie Johnson\", email=\"charlie@example.com\", phone=\"777-888-9999\", billing_rate=60, total_hours_entered=12, total_amount_billed=720)\nperson4 = Person(id=4, client_id=4, name=\"Dana White\", email=\"dana@example.com\", phone=\"123-987-6543\", billing_rate=85, total_hours_entered=15, total_amount_billed=1275)\n\n# Test data for Timesheet\ntimesheet1 = Timesheet(id=1, task_id=1, person_id=1, date_worked=date(2023, 1, 10), hours_worked=5, month=1, year=2023, billing_rate=50, total_amount_billed=250)\ntimesheet2 = Timesheet(id=2, task_id=1, person_id=2, date_worked=date(2023, 1, 12), hours_worked=4, month=1, year=2023, billing_rate=75, total_amount_billed=300)\ntimesheet3 = Timesheet(id=3, task_id=2, person_id=3, date_worked=date(2023, 2, 15), hours_worked=8, month=2, year=2023, billing_rate=60, total_amount_billed=480)\ntimesheet4 = Timesheet(id=4, task_id=3, person_id=4, date_worked=date(2023, 3, 20), hours_worked=7, month=3, year=2023, billing_rate=85, total_amount_billed=595)\n\n# Test data for Payment\npayment1 = Payment(id=1, invoice_id=1, payment_amount=1000, payment_date=date(2023, 4, 1), notes=\"First payment\")\npayment2 = Payment(id=2, invoice_id=2, payment_amount=1000, payment_date=date(2023, 4, 5), notes=\"Full settlement\")\npayment3 = Payment(id=3, invoice_id=3, payment_amount=500, payment_date=date(2023, 4, 10), notes=\"Partial payment\")\npayment4 = Payment(id=4, invoice_id=4, payment_amount=2000, payment_date=date(2023, 4, 15), notes=\"Advance payment\")",
182
+ "test_data_rows": [
183
+ {
184
+ "test_data_row_variable": "client1",
185
+ "code": "client1 = Client(id=1, name=\"Acme Corp\", email=\"acme@acme.com\", phone=\"123-456-7890\", total_hours=20, total_amount=5000, budget_amount=10000)"
186
+ },
187
+ {
188
+ "test_data_row_variable": "client2",
189
+ "code": "client2 = Client(id=2, name=\"Beta LLC\", email=\"beta@beta.com\", phone=\"987-654-3210\", total_hours=15, total_amount=3000, budget_amount=5000)"
190
+ },
191
+ {
192
+ "test_data_row_variable": "client3",
193
+ "code": "client3 = Client(id=3, name=\"Gamma Industries\", email=\"gamma@gamma.com\", phone=\"456-123-6789\", total_hours=30, total_amount=12000, budget_amount=15000)"
194
+ },
195
+ {
196
+ "test_data_row_variable": "client4",
197
+ "code": "client4 = Client(id=4, name=\"Delta Services\", email=\"delta@delta.com\", phone=\"789-321-6540\", total_hours=45, total_amount=9000, budget_amount=20000)"
198
+ },
199
+ {
200
+ "test_data_row_variable": "project1",
201
+ "code": "project1 = Project(id=1, client_id=1, name=\"Project X\", total_project_hours=50, total_project_amount=8000, project_budget_amount=10000)"
202
+ },
203
+ {
204
+ "test_data_row_variable": "project2",
205
+ "code": "project2 = Project(id=2, client_id=1, name=\"Project Y\", total_project_hours=25, total_project_amount=4000, project_budget_amount=7000)"
206
+ },
207
+ {
208
+ "test_data_row_variable": "project3",
209
+ "code": "project3 = Project(id=3, client_id=2, name=\"Project Z\", total_project_hours=30, total_project_amount=3000, project_budget_amount=4000)"
210
+ },
211
+ {
212
+ "test_data_row_variable": "project4",
213
+ "code": "project4 = Project(id=4, client_id=3, name=\"Project Alpha\", total_project_hours=60, total_project_amount=15000, project_budget_amount=20000)"
214
+ },
215
+ {
216
+ "test_data_row_variable": "invoice1",
217
+ "code": "invoice1 = Invoice(id=1, project_id=1, invoice_date=date(2023, 2, 15), invoice_amount=5000, payment_total=3000, invoice_balance=2000)"
218
+ },
219
+ {
220
+ "test_data_row_variable": "invoice2",
221
+ "code": "invoice2 = Invoice(id=2, project_id=2, invoice_date=date(2023, 3, 20), invoice_amount=1000, payment_total=1000, invoice_balance=0)"
222
+ },
223
+ {
224
+ "test_data_row_variable": "invoice3",
225
+ "code": "invoice3 = Invoice(id=3, project_id=3, invoice_date=date(2023, 4, 11), invoice_amount=2000, payment_total=1500, invoice_balance=500)"
226
+ },
227
+ {
228
+ "test_data_row_variable": "invoice4",
229
+ "code": "invoice4 = Invoice(id=4, project_id=4, invoice_date=date(2023, 5, 9), invoice_amount=7000, payment_total=5000, invoice_balance=2000)"
230
+ },
231
+ {
232
+ "test_data_row_variable": "task1",
233
+ "code": "task1 = Task(id=1, project_id=1, name=\"Design Phase\", description=\"Initial design work\", total_task_hours_worked=15, total_task_amount_billed=1500, task_budget_hours=20)"
234
+ },
235
+ {
236
+ "test_data_row_variable": "task2",
237
+ "code": "task2 = Task(id=2, project_id=2, name=\"Development Phase\", description=\"Coding and implementation\", total_task_hours_worked=30, total_task_amount_billed=3000, task_budget_hours=40)"
238
+ },
239
+ {
240
+ "test_data_row_variable": "task3",
241
+ "code": "task3 = Task(id=3, project_id=3, name=\"Testing Phase\", description=\"QA and testing\", total_task_hours_worked=10, total_task_amount_billed=1000, task_budget_hours=15)"
242
+ },
243
+ {
244
+ "test_data_row_variable": "task4",
245
+ "code": "task4 = Task(id=4, project_id=4, name=\"Deployment Phase\", description=\"Deployment and support\", total_task_hours_worked=20, total_task_amount_billed=2000, task_budget_hours=25)"
246
+ },
247
+ {
248
+ "test_data_row_variable": "person1",
249
+ "code": "person1 = Person(id=1, client_id=1, name=\"Alice Smith\", email=\"alice@example.com\", phone=\"111-222-3333\", billing_rate=50, total_hours_entered=10, total_amount_billed=500)"
250
+ },
251
+ {
252
+ "test_data_row_variable": "person2",
253
+ "code": "person2 = Person(id=2, client_id=2, name=\"Bob Brown\", email=\"bob@example.com\", phone=\"444-555-6666\", billing_rate=75, total_hours_entered=8, total_amount_billed=600)"
254
+ },
255
+ {
256
+ "test_data_row_variable": "person3",
257
+ "code": "person3 = Person(id=3, client_id=3, name=\"Charlie Johnson\", email=\"charlie@example.com\", phone=\"777-888-9999\", billing_rate=60, total_hours_entered=12, total_amount_billed=720)"
258
+ },
259
+ {
260
+ "test_data_row_variable": "person4",
261
+ "code": "person4 = Person(id=4, client_id=4, name=\"Dana White\", email=\"dana@example.com\", phone=\"123-987-6543\", billing_rate=85, total_hours_entered=15, total_amount_billed=1275)"
262
+ },
263
+ {
264
+ "test_data_row_variable": "timesheet1",
265
+ "code": "timesheet1 = Timesheet(id=1, task_id=1, person_id=1, date_worked=date(2023, 1, 10), hours_worked=5, month=1, year=2023, billing_rate=50, total_amount_billed=250)"
266
+ },
267
+ {
268
+ "test_data_row_variable": "timesheet2",
269
+ "code": "timesheet2 = Timesheet(id=2, task_id=1, person_id=2, date_worked=date(2023, 1, 12), hours_worked=4, month=1, year=2023, billing_rate=75, total_amount_billed=300)"
270
+ },
271
+ {
272
+ "test_data_row_variable": "timesheet3",
273
+ "code": "timesheet3 = Timesheet(id=3, task_id=2, person_id=3, date_worked=date(2023, 2, 15), hours_worked=8, month=2, year=2023, billing_rate=60, total_amount_billed=480)"
274
+ },
275
+ {
276
+ "test_data_row_variable": "timesheet4",
277
+ "code": "timesheet4 = Timesheet(id=4, task_id=3, person_id=4, date_worked=date(2023, 3, 20), hours_worked=7, month=3, year=2023, billing_rate=85, total_amount_billed=595)"
278
+ },
279
+ {
280
+ "test_data_row_variable": "payment1",
281
+ "code": "payment1 = Payment(id=1, invoice_id=1, payment_amount=1000, payment_date=date(2023, 4, 1), notes=\"First payment\")"
282
+ },
283
+ {
284
+ "test_data_row_variable": "payment2",
285
+ "code": "payment2 = Payment(id=2, invoice_id=2, payment_amount=1000, payment_date=date(2023, 4, 5), notes=\"Full settlement\")"
286
+ },
287
+ {
288
+ "test_data_row_variable": "payment3",
289
+ "code": "payment3 = Payment(id=3, invoice_id=3, payment_amount=500, payment_date=date(2023, 4, 10), notes=\"Partial payment\")"
290
+ },
291
+ {
292
+ "test_data_row_variable": "payment4",
293
+ "code": "payment4 = Payment(id=4, invoice_id=4, payment_amount=2000, payment_date=date(2023, 4, 15), notes=\"Advance payment\")"
294
+ }
295
+ ],
296
+ "test_data_sqlite": "CREATE TABLE client (\n id INTEGER PRIMARY KEY,\n name TEXT NOT NULL,\n email TEXT NOT NULL,\n phone TEXT NOT NULL,\n total_hours DECIMAL(10,2) DEFAULT 0,\n total_amount DECIMAL(10,2) DEFAULT 0,\n budget_amount DECIMAL(10,2) DEFAULT 0,\n is_over_budget BOOLEAN DEFAULT FALSE\n);\n\nINSERT INTO client (id, name, email, phone, total_hours, total_amount, budget_amount, is_over_budget)\nVALUES (1, 'Acme Corp', 'acme@acme.com', '123-456-7890', 20, 5000, 10000, 0),\n (2, 'Beta LLC', 'beta@beta.com', '987-654-3210', 15, 3000, 5000, 0),\n (3, 'Gamma Industries', 'gamma@gamma.com', '456-123-6789', 30, 12000, 15000, 0),\n (4, 'Delta Services', 'delta@delta.com', '789-321-6540', 45, 9000, 20000, 0);\n\nCREATE TABLE project (\n id INTEGER PRIMARY KEY,\n client_id INTEGER,\n name TEXT NOT NULL,\n total_project_hours DECIMAL(10,2) DEFAULT 0,\n total_project_amount DECIMAL(10,2) DEFAULT 0,\n project_budget_amount DECIMAL(10,2) DEFAULT 0,\n is_over_budget BOOLEAN DEFAULT FALSE,\n FOREIGN KEY(client_id) REFERENCES client(id)\n);\n\nINSERT INTO project (id, client_id, name, total_project_hours, total_project_amount, project_budget_amount, is_over_budget)\nVALUES (1, 1, 'Project X', 50, 8000, 10000, 0),\n (2, 1, 'Project Y', 25, 4000, 7000, 0),\n (3, 2, 'Project Z', 30, 3000, 4000, 0),\n (4, 3, 'Project Alpha', 60, 15000, 20000, 0);\n\nCREATE TABLE invoice (\n id INTEGER PRIMARY KEY,\n project_id INTEGER,\n invoice_date DATE NOT NULL,\n invoice_amount DECIMAL(10,2) DEFAULT 0,\n payment_total DECIMAL(10,2) DEFAULT 0,\n invoice_balance DECIMAL(10,2) DEFAULT 0,\n is_paid BOOLEAN DEFAULT FALSE,\n FOREIGN KEY(project_id) REFERENCES project(id)\n);\n\nINSERT INTO invoice (id, project_id, invoice_date, invoice_amount, payment_total, invoice_balance, is_paid)\nVALUES (1, 1, '2023-02-15', 5000, 3000, 2000, 0),\n (2, 2, '2023-03-20', 1000, 1000, 0, 1),\n (3, 3, '2023-04-11', 2000, 1500, 500, 0),\n (4, 4, '2023-05-09', 7000, 5000, 2000, 0);\n\nCREATE TABLE task (\n id INTEGER PRIMARY KEY,\n project_id INTEGER,\n name TEXT NOT NULL,\n description TEXT,\n total_task_hours_worked DECIMAL(10,2) DEFAULT 0,\n total_task_amount_billed DECIMAL(10,2) DEFAULT 0,\n task_budget_hours DECIMAL(10,2) DEFAULT 0,\n is_over_budget BOOLEAN DEFAULT FALSE,\n invoice_id INTEGER,\n FOREIGN KEY(project_id) REFERENCES project(id),\n FOREIGN KEY(invoice_id) REFERENCES invoice(id)\n);\n\nINSERT INTO task (id, project_id, name, description, total_task_hours_worked, total_task_amount_billed, task_budget_hours, is_over_budget, invoice_id)\nVALUES (1, 1, 'Design Phase', 'Initial design work', 15, 1500, 20, 0, NULL),\n (2, 2, 'Development Phase', 'Coding and implementation', 30, 3000, 40, 0, NULL),\n (3, 3, 'Testing Phase', 'QA and testing', 10, 1000, 15, 0, NULL),\n (4, 4, 'Deployment Phase', 'Deployment and support', 20, 2000, 25, 0, NULL);\n\nCREATE TABLE person (\n id INTEGER PRIMARY KEY,\n client_id INTEGER,\n name TEXT NOT NULL,\n email TEXT NOT NULL,\n phone TEXT NOT NULL,\n billing_rate DECIMAL(10,2) DEFAULT 0,\n total_hours_entered DECIMAL(10,2) DEFAULT 0,\n total_amount_billed DECIMAL(10,2) DEFAULT 0,\n FOREIGN KEY(client_id) REFERENCES client(id)\n);\n\nINSERT INTO person (id, client_id, name, email, phone, billing_rate, total_hours_entered, total_amount_billed)\nVALUES (1, 1, 'Alice Smith', 'alice@example.com', '111-222-3333', 50, 10, 500),\n (2, 2, 'Bob Brown', 'bob@example.com', '444-555-6666', 75, 8, 600),\n (3, 3, 'Charlie Johnson', 'charlie@example.com', '777-888-9999', 60, 12, 720),\n (4, 4, 'Dana White', 'dana@example.com', '123-987-6543', 85, 15, 1275);\n\nCREATE TABLE timesheet (\n id INTEGER PRIMARY KEY,\n task_id INTEGER,\n person_id INTEGER,\n date_worked DATE NOT NULL,\n hours_worked DECIMAL(10,2) DEFAULT 0,\n month INTEGER,\n year INTEGER,\n billing_rate DECIMAL(10,2) DEFAULT 0,\n total_amount_billed DECIMAL(10,2) DEFAULT 0,\n FOREIGN KEY(task_id) REFERENCES task(id),\n FOREIGN KEY(person_id) REFERENCES person(id)\n);\n\nINSERT INTO timesheet (id, task_id, person_id, date_worked, hours_worked, month, year, billing_rate, total_amount_billed)\nVALUES (1, 1, 1, '2023-01-10', 5, 1, 2023, 50, 250),\n (2, 1, 2, '2023-01-12', 4, 1, 2023, 75, 300),\n (3, 2, 3, '2023-02-15', 8, 2, 2023, 60, 480),\n (4, 3, 4, '2023-03-20', 7, 3, 2023, 85, 595);\n\nCREATE TABLE payment (\n id INTEGER PRIMARY KEY,\n invoice_id INTEGER,\n payment_amount DECIMAL(10,2) DEFAULT 0,\n payment_date DATE NOT NULL,\n notes TEXT,\n FOREIGN KEY(invoice_id) REFERENCES invoice(id)\n);\n\nINSERT INTO payment (id, invoice_id, payment_amount, payment_date, notes)\nVALUES (1, 1, 1000, '2023-04-01', 'First payment'),\n (2, 2, 1000, '2023-04-05', 'Full settlement'),\n (3, 3, 500, '2023-04-10', 'Partial payment'),\n (4, 4, 2000, '2023-04-15', 'Advance payment');",
297
+ "name": "Time_Tracker_and_Billing_System"
298
+ }
@@ -0,0 +1,61 @@
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
+
4
+ ## Command Line - create this system:
5
+ ```bash
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.
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
 
@@ -113,7 +113,7 @@ class Rule:
113
113
  """
114
114
  Copy declares child column copied from parent column.
115
115
 
116
- Example
116
+ Example:
117
117
  Prompt
118
118
  Store the Item.unit_price as a copy from Product.unit_price
119
119
  Response
@@ -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:
@@ -190,7 +204,6 @@ Response is to create 2 rules - a derivation and a constraint, as follows:
190
204
  Intermediate sum/count values also work for counts. For example:
191
205
 
192
206
  Prompt:
193
-
194
207
  A airplane cannot have more passengers than its seating capacity.
195
208
 
196
209
  Response is to create 2 rules - a count derivation and a constraint, as follows:
@@ -212,12 +225,11 @@ Response is to create 2 rules - a derivation and a constraint, as follows:
212
225
  Rule.sum(derive=Employee.skill_rating_total, as_sum_of=EmployeeSkill.rating)
213
226
  And, be sure to create the second Rule:
214
227
  Rule.Formula(derive=Employee.skill_summary,
215
- as_condition=lambda row: row.skill_rating_total + 2 * row.years_of_service)
228
+ as_expression=lambda row: row.skill_rating_total + 2 * row.years_of_service)
216
229
 
217
230
 
218
231
  Prompt:
219
-
220
- A student cannot be an honor student unless they have mre than 2 service activities.
232
+ A student cannot be an honor student unless they have more than 2 service activities.
221
233
 
222
234
  Response is to create 2 rules - a count derivation and a constraint, as follows:
223
235
  First Rule to Create:
@@ -230,7 +242,6 @@ Response is to create 2 rules - a count derivation and a constraint, as follows:
230
242
  Here is an equivalent request:
231
243
 
232
244
  Prompt:
233
-
234
245
  A airplane's passengers must be less than its seating capacity.
235
246
 
236
247
  Response is to create 2 rules - a count derivation and a constraint, as follows:
@@ -244,20 +255,20 @@ Response is to create 2 rules - a count derivation and a constraint, as follows:
244
255
 
245
256
  For "more than" constraints, create columns with count rules:
246
257
 
247
- Prompt Reject Employees with more than 3 Felonies.
258
+ Prompt: Reject Employees with more than 3 Felonies.
248
259
 
249
260
  Response:
250
261
  First Rule is to create:
251
262
  Rule.count(derive=Employee.felony_count, as_count_of=Felonies)
252
263
  And, be sure to create the contraint rule:
253
264
  Rule.constraint(validate=Employee,
254
- as_condition=lambda row: row.felony_count>3,
265
+ as_condition=lambda row: row.felony_count<=3,
255
266
  error_msg="Employee has excessive Felonies")
256
267
 
257
268
 
258
269
  For "any" constraints, create columns with count rules:
259
270
 
260
- Prompt Reject Employees with any class 5 Felonies or more than 3 Felonies.
271
+ Prompt: Reject Employees with any class 5 Felonies or more than 3 Felonies.
261
272
 
262
273
  Response:
263
274
  First Rule is to create:
@@ -265,7 +276,7 @@ Response:
265
276
  Rule.count(derive=Employee.felony_count, as_count_of=Felonies)
266
277
  And, be sure to create the contraint rule:
267
278
  Rule.constraint(validate=Employee,
268
- as_condition=lambda row: row.class_5_felony_count > 0 or row.felony_count>3,
279
+ as_condition=lambda row: row.class_5_felony_count == 0 and row.felony_count<=3,
269
280
  error_msg="Employee has excessive Felonies")
270
281
 
271
282
  Formulas can reference parent values in 2 versions - choose formula vs copy as follows:
@@ -278,6 +289,13 @@ Formulas can reference parent values in 2 versions - choose formula vs copy as f
278
289
  Response
279
290
  Rule.copy(derive=Item.ready, from_parent=Order.ready)
280
291
 
292
+ Formulas can use Python conditions:
293
+ Prompt: Item amount is price * quantity, with a 10% discount for gold products
294
+ Response:
295
+ Rule.Formula(derive=Item.amount,
296
+ as_expression=lambda row: row.price * row.quantity if row.gold else .9 * row.price * row.quantity)
297
+ If the attributes are decimal, use the form Decimal('0.9')
298
+
281
299
  Sum and Count where clauses:
282
300
  1. must not restate the foreign key / primary key matchings
283
301
  2. Can only reference child attributes
@@ -1 +1,2 @@
1
- Update the prior response - be sure not to lose classes and test data already created.
1
+ Update the prior response - be sure not to lose classes, rules and test data already created.
2
+ If there is more than one derivation for the same column, use the last one provided.
@@ -1 +1 @@
1
- Project created as nw+ (nw, no customizations)
1
+ Project created as nw- (nw, no customizations)
@@ -0,0 +1,9 @@
1
+ <div fxLayout="row" fxLayoutAlign="center start" fxFlexFill class="container">
2
+ <o-tree #tree service="{{ service }}" entity="{{ entity }}"
3
+ keys="{{ keys }}" root-title="{{ entity }}" columns="{{ columns }}"
4
+ visible-columns="{{ favorite }}" route=":{{ keys }}" fxFlex="20">
5
+ </o-tree>
6
+ <div fxLayout="column" fxLayoutAlign="center stretch" fxFlex="80">
7
+ <router-outlet></router-outlet>
8
+ </div>
9
+ </div>
@@ -0,0 +1,32 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { RouterModule, Routes } from '@angular/router';
3
+ import { {{ entity_first_cap }}HomeComponent } from './home/{{ entity }}-home.component';
4
+ import { {{ entity_first_cap }}NewComponent } from './new/{{ entity }}-new.component';
5
+ import { {{ entity_first_cap }}DetailComponent } from './detail/{{ entity }}-detail.component';
6
+
7
+ const routes: Routes = [
8
+ {path: '', component: {{ entity_first_cap }}HomeComponent,
9
+ children: [
10
+ { path: 'new', component: {{ entity_first_cap }}NewComponent },
11
+ { path: ':{{ keyPath }}', component: {{ entity_first_cap }}DetailComponent,
12
+ data: {
13
+ oPermission: {
14
+ permissionId: '{{ entity }}-detail-permissions'
15
+ }
16
+ }
17
+ }{{ additional_routes }}
18
+ ]}
19
+ ];
20
+
21
+ export const {{ entity_upper}}_MODULE_DECLARATIONS = [
22
+ {{ entity_first_cap }}HomeComponent,
23
+ {{ entity_first_cap }}NewComponent,
24
+ {{ entity_first_cap }}DetailComponent
25
+ ];
26
+
27
+
28
+ @NgModule({
29
+ imports: [RouterModule.forChild(routes)],
30
+ exports: [RouterModule]
31
+ })
32
+ export class {{ entity_first_cap }}RoutingModule { }
@@ -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
@@ -1179,7 +1180,8 @@ else:
1179
1180
  render_coltype = not dedicated_fks or any(fk.column is column for fk in dedicated_fks)
1180
1181
  if 'DataTypes.char_type DEBUG ONLY' == str(column):
1181
1182
  debug_stop = "Debug Stop: Column" # char_type = Column(CHAR(1, 'SQL_Latin1_General_CP1_CI_AS'))
1182
-
1183
+ if str(column) in ['Credit_limit', 'credit_limit']:
1184
+ debug_stop = "Debug Stop: Column"
1183
1185
  if column.key != column.name:
1184
1186
  kwarg.append('key')
1185
1187
  if column.primary_key:
@@ -1511,7 +1513,7 @@ else:
1511
1513
  child_accessor = f' {child_accessor_name} : Mapped[List["{reln.source_cls}"]] = '\
1512
1514
  f'relationship({multi_reln_fix}back_populates="{reln.parent_accessor_name}")\n'
1513
1515
 
1514
- if model.name in ["Employee", "CharacterClass"]: # Emp has Department and Department1
1516
+ if model.name in ["Item", "Employee", "CharacterClass"]: # Emp has Department and Department1
1515
1517
  debug_str = "nice breakpoint" # DND CharacterClass - check parent acceossor (class_ not class)
1516
1518
  model.rendered_parent_relationships += parent_accessor
1517
1519
  parent_model.rendered_child_relationships += child_accessor
@@ -9,7 +9,7 @@ from importlib import import_module
9
9
  from pathlib import Path
10
10
  from werkzeug.utils import secure_filename
11
11
  from database.models import *
12
- from logic_bank.logic_bank import DeclareRule, Rule, LogicBank
12
+ from logic_bank.logic_bank import Rule, LogicBank
13
13
  from colorama import Fore, Style, init
14
14
  from logic_bank.logic_bank import RuleBank
15
15
  from logic_bank.rule_bank.rule_bank_setup import find_referenced_attributes