diff --git a/api/__pycache__/settings.cpython-313.pyc b/api/__pycache__/settings.cpython-313.pyc index 8ec4b12e..21a981e1 100644 Binary files a/api/__pycache__/settings.cpython-313.pyc and b/api/__pycache__/settings.cpython-313.pyc differ diff --git a/app/__pycache__/document_generator.cpython-313.pyc b/app/__pycache__/document_generator.cpython-313.pyc index 0d8051ca..289dab9e 100644 Binary files a/app/__pycache__/document_generator.cpython-313.pyc and b/app/__pycache__/document_generator.cpython-313.pyc differ diff --git a/app/__pycache__/models.cpython-313.pyc b/app/__pycache__/models.cpython-313.pyc index 62667e9a..b37f372a 100644 Binary files a/app/__pycache__/models.cpython-313.pyc and b/app/__pycache__/models.cpython-313.pyc differ diff --git a/app/__pycache__/workflow_engine.cpython-313.pyc b/app/__pycache__/workflow_engine.cpython-313.pyc index d7d7ca06..a0d34703 100644 Binary files a/app/__pycache__/workflow_engine.cpython-313.pyc and b/app/__pycache__/workflow_engine.cpython-313.pyc differ diff --git a/app/__pycache__/workflow_utils.cpython-313.pyc b/app/__pycache__/workflow_utils.cpython-313.pyc index 1e073c35..3d2a4646 100644 Binary files a/app/__pycache__/workflow_utils.cpython-313.pyc and b/app/__pycache__/workflow_utils.cpython-313.pyc differ diff --git a/app/document_generator.py b/app/document_generator.py index d17f6886..d8f80dd0 100644 --- a/app/document_generator.py +++ b/app/document_generator.py @@ -209,20 +209,44 @@ class DocumentGenerator: if not obj: return None + import re parts = field_path.split('.') value = obj for part in parts: if value is None: break - # Lấy thuộc tính từ object - value = getattr(value, part, None) + # 1. Kiểm tra nếu part chứa index mảng, ví dụ: "payment_plan[0]" + array_match = re.match(r"(\w+)\[(\d+)\]", part) - # KIỂM TRA NẾU LÀ QUAN HỆ NGƯỢC (ForeignKey ngược hoặc ManyToMany) - # Trong Django, các quan hệ này trả về một Manager (có method 'all') - if hasattr(value, 'all') and not isinstance(value, models.Model): - value = value.first() # Tự động lấy bản ghi đầu tiên + if array_match: + attr_name = array_match.group(1) # Lấy "payment_plan" + index = int(array_match.group(2)) # Lấy 0 + # Lấy list từ object + value = getattr(value, attr_name, None) + + # Truy cập phần tử theo index + try: + if isinstance(value, (list, tuple)): + value = value[index] + elif hasattr(value, 'all'): # QuerySet + value = value[index] + except (IndexError, TypeError): + return None + else: + # 2. Xử lý truy cập thuộc tính hoặc key của Dict (JSON) + if isinstance(value, dict): + # Nếu là dict (phần tử trong JSONField), dùng .get() + value = value.get(part) + else: + # Nếu là object, dùng getattr() + value = getattr(value, part, None) + + # 3. Hỗ trợ lấy bản ghi đầu tiên nếu gặp Quan hệ ngược (Manager) + if hasattr(value, 'all') and not isinstance(value, models.Model): + value = value.first() + return value def fetch_data(self): diff --git a/app/migrations/0346_remove_co_ownership_code.py b/app/migrations/0346_remove_co_ownership_code.py new file mode 100644 index 00000000..3f62beef --- /dev/null +++ b/app/migrations/0346_remove_co_ownership_code.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.7 on 2026-01-04 17:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0345_alter_co_ownership_transaction'), + ] + + operations = [ + migrations.RemoveField( + model_name='co_ownership', + name='code', + ), + ] diff --git a/app/models.py b/app/models.py index 51c211c4..619b2e9e 100644 --- a/app/models.py +++ b/app/models.py @@ -1964,7 +1964,6 @@ class Transaction_Discount(models.Model): class Co_Ownership(models.Model): - code = models.CharField(max_length=30, null=False, unique=True) transaction = models.ForeignKey(Transaction, null=False, related_name='co_op', on_delete=models.PROTECT) people = models.ForeignKey(People, null=False, related_name='+', on_delete=models.PROTECT) create_time = models.DateTimeField(null=True, auto_now_add=True) diff --git a/app/workflow_engine.py b/app/workflow_engine.py index 45b91896..0c579355 100644 --- a/app/workflow_engine.py +++ b/app/workflow_engine.py @@ -54,6 +54,7 @@ def evaluate_rule(rule: Rule, context: dict): print(f" Evaluating Rule: {left} {op} {right}") + if op == "IN" and left not in right: return False if op == "==" and left != right: return False if op == "!=" and left == right: return False if op == ">" and not (left > right): return False diff --git a/app/workflow_utils.py b/app/workflow_utils.py index 6be13466..ad4a2ff8 100644 --- a/app/workflow_utils.py +++ b/app/workflow_utils.py @@ -1,6 +1,6 @@ import re from datetime import datetime - +from django.db import models def resolve_value(expr, context): """ @@ -64,10 +64,36 @@ def resolve_value(expr, context): root, *rest = key_path.split(".") val = context.get(root) + for r in rest: if val is None: return None - val = getattr(val, r, None) if not isinstance(val, dict) else val.get(r) + + # 1. Xử lý truy cập index mảng, ví dụ: payment_plan[0] + array_match = re.match(r"(\w+)\[(\d+)\]", r) + if array_match: + attr_name = array_match.group(1) + index = int(array_match.group(2)) + # Lấy list/queryset + val = getattr(val, attr_name, None) if not isinstance(val, dict) else val.get(attr_name) + try: + if hasattr(val, 'all'): # Django QuerySet/Manager + val = val[index] + else: # List thông thường + val = val[index] + except (IndexError, TypeError, KeyError): + return None + else: + # 2. Xử lý truy cập thuộc tính hoặc dict key + if isinstance(val, dict): + val = val.get(r) + else: + val = getattr(val, r, None) + + # 3. Hỗ trợ tự động lấy bản ghi đầu tiên nếu là Manager (1-n) + if hasattr(val, 'all') and not isinstance(val, models.Model): + val = val.first() + return val # ============================================= diff --git a/static/contract/.~lock.1. Phiếu xác lập thỏa thuận ưu tiên tổ chức.docx# b/static/contract/.~lock.1. Phiếu xác lập thỏa thuận ưu tiên tổ chức.docx# deleted file mode 100644 index 58a88818..00000000 --- a/static/contract/.~lock.1. Phiếu xác lập thỏa thuận ưu tiên tổ chức.docx# +++ /dev/null @@ -1 +0,0 @@ -,kumduy,duy-pc,04.01.2026 23:48,file:///home/kumduy/.config/libreoffice/4; \ No newline at end of file diff --git a/static/contract/1. Phiếu xác lập thỏa thuận ưu tiên đồng sở hữu.docx b/static/contract/1. Phiếu xác lập thỏa thuận ưu tiên đồng sở hữu.docx new file mode 100644 index 00000000..dfe6f9e2 Binary files /dev/null and b/static/contract/1. Phiếu xác lập thỏa thuận ưu tiên đồng sở hữu.docx differ diff --git a/static/contract/2. Đơn Đăng kí nguyện vọng một người.docx b/static/contract/2. Đơn Đăng kí nguyện vọng một người.docx new file mode 100644 index 00000000..9ed7b71c Binary files /dev/null and b/static/contract/2. Đơn Đăng kí nguyện vọng một người.docx differ diff --git a/static/contract/2. Đơn Đăng kí nguyện vọng tổ chức.docx b/static/contract/2. Đơn Đăng kí nguyện vọng tổ chức.docx new file mode 100644 index 00000000..b02584fa Binary files /dev/null and b/static/contract/2. Đơn Đăng kí nguyện vọng tổ chức.docx differ diff --git a/static/contract/2. Đơn Đăng kí nguyện vọng đồng sở hữu.docx b/static/contract/2. Đơn Đăng kí nguyện vọng đồng sở hữu.docx new file mode 100644 index 00000000..22ec3749 Binary files /dev/null and b/static/contract/2. Đơn Đăng kí nguyện vọng đồng sở hữu.docx differ diff --git a/static/contract/3. Thoả thuận thực hiện nguyện vọng cá nhân.docx b/static/contract/3. Thoả thuận thực hiện nguyện vọng cá nhân.docx new file mode 100644 index 00000000..c215c589 Binary files /dev/null and b/static/contract/3. Thoả thuận thực hiện nguyện vọng cá nhân.docx differ diff --git a/static/contract/3. Thoả thuận thực hiện nguyện vọng tổ chức.docx b/static/contract/3. Thoả thuận thực hiện nguyện vọng tổ chức.docx new file mode 100644 index 00000000..497b0463 Binary files /dev/null and b/static/contract/3. Thoả thuận thực hiện nguyện vọng tổ chức.docx differ diff --git a/static/contract/3. Thoả thuận thực hiện nguyện vọng đồng sở hữu.docx b/static/contract/3. Thoả thuận thực hiện nguyện vọng đồng sở hữu.docx new file mode 100644 index 00000000..c52227a7 Binary files /dev/null and b/static/contract/3. Thoả thuận thực hiện nguyện vọng đồng sở hữu.docx differ diff --git a/static/contract/6. Biên bản thanh lý TTTHNV cá nhân.docx b/static/contract/6. Biên bản thanh lý TTTHNV cá nhân.docx new file mode 100644 index 00000000..2e510394 Binary files /dev/null and b/static/contract/6. Biên bản thanh lý TTTHNV cá nhân.docx differ diff --git a/static/contract/6. Biên bản thanh lý TTTHNV tổ chức.docx b/static/contract/6. Biên bản thanh lý TTTHNV tổ chức.docx new file mode 100644 index 00000000..b6645ee2 Binary files /dev/null and b/static/contract/6. Biên bản thanh lý TTTHNV tổ chức.docx differ diff --git a/static/contract/6. Biên bản thanh lý TTTHNV đồng sở hữu.docx b/static/contract/6. Biên bản thanh lý TTTHNV đồng sở hữu.docx new file mode 100644 index 00000000..5bd496f3 Binary files /dev/null and b/static/contract/6. Biên bản thanh lý TTTHNV đồng sở hữu.docx differ