diff --git a/api/__pycache__/settings.cpython-313.pyc b/api/__pycache__/settings.cpython-313.pyc index 19c59008..6c33a0b0 100644 Binary files a/api/__pycache__/settings.cpython-313.pyc and b/api/__pycache__/settings.cpython-313.pyc differ diff --git a/app/__pycache__/consumers.cpython-313.pyc b/app/__pycache__/consumers.cpython-313.pyc index 62d1510e..3d2d9ac2 100644 Binary files a/app/__pycache__/consumers.cpython-313.pyc and b/app/__pycache__/consumers.cpython-313.pyc differ diff --git a/app/__pycache__/models.cpython-313.pyc b/app/__pycache__/models.cpython-313.pyc index 73ee1fba..539332c8 100644 Binary files a/app/__pycache__/models.cpython-313.pyc and b/app/__pycache__/models.cpython-313.pyc differ diff --git a/app/consumers.py b/app/consumers.py index b9dfdb87..82cfba8a 100644 --- a/app/consumers.py +++ b/app/consumers.py @@ -59,8 +59,10 @@ class DataConsumer(AsyncJsonWebsocketConsumer): from .views import get_serializer payload = event["payload"] + change_type = payload.get("change_type") record_id = payload["record"].get("id") - if not record_id: + + if not record_id or not change_type: return model_name_lower = payload["name"] @@ -71,7 +73,19 @@ class DataConsumer(AsyncJsonWebsocketConsumer): if not client_params: return # This client is not subscribed to this model. - # 2. Check if the updated record ID could possibly match the client's filter + # 2. Handle DELETION event + if change_type == 'deleted': + await self.send_json({ + "type": "realtime_update", + "payload": { + "name": model_name_lower, + "change_type": "deleted", + "record": {"id": record_id} + } + }) + return + + # 3. Handle CREATION and UPDATE events Model, _ = get_serializer(model_name_lower) if not Model: return @@ -80,36 +94,37 @@ class DataConsumer(AsyncJsonWebsocketConsumer): filter_q = Q() filter_dict = client_params.get('filter') if isinstance(filter_dict, dict): - for key, value in filter_dict.items(): - filter_q.add(Q(**{key: value}), Q.AND) + filter_q = Q(**filter_dict) - # Combine the client's filter with the specific record's ID - combined_filter = Q(pk=record_id) & filter_q - # Check if the object actually exists with the combined filter - record_exists = await database_sync_to_async(Model.objects.filter(combined_filter).exists)() - if not record_exists: - return # The record does not match the client's filter, so don't send. + record_exists = await database_sync_to_async( + Model.objects.filter(Q(pk=record_id) & filter_q).exists + )() - # 3. Re-run the original query for just this single object. - # This correctly applies 'values', 'distinct_values', 'summary', etc. - single_record_params = client_params.copy() - single_record_params['filter'] = {'pk': record_id} - - data = await database_sync_to_async(execute_data_query)(model_name_capitalized, single_record_params) + if record_exists: + # If record matches filter, re-run the query to get the correctly shaped data + single_record_params = client_params.copy() + single_record_params['filter'] = {'pk': record_id} + + data = await database_sync_to_async(execute_data_query)(model_name_capitalized, single_record_params) - # If the query returns no data (e.g., record was deleted or no longer matches), do nothing. - if not data or not data.get('rows'): - return - - # 4. Build the final payload with the correctly-shaped record - payload_for_client = { - "name": model_name_lower, - "record": data['rows'][0] - } - - # 5. Send the final, tailored payload to the client - await self.send_json({ - "type": "realtime_update", - "payload": payload_for_client - }) + if data and data.get('rows'): + payload_for_client = { + "name": model_name_lower, + "change_type": change_type, + "record": data['rows'][0] + } + await self.send_json({ + "type": "realtime_update", + "payload": payload_for_client + }) + else: + # If the record exists but no longer matches the filter, treat as a deletion for this client + await self.send_json({ + "type": "realtime_update", + "payload": { + "name": model_name_lower, + "change_type": "deleted", + "record": {"id": record_id} + } + }) diff --git a/app/migrations/0341_rename_facebook_people_taxcode_remove_people_zalo_and_more.py b/app/migrations/0341_rename_facebook_people_taxcode_remove_people_zalo_and_more.py new file mode 100644 index 00000000..f80bbcc1 --- /dev/null +++ b/app/migrations/0341_rename_facebook_people_taxcode_remove_people_zalo_and_more.py @@ -0,0 +1,32 @@ +# Generated by Django 5.1.7 on 2025-12-31 09:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0340_file_hashtag_co_ownership'), + ] + + operations = [ + migrations.RenameField( + model_name='people', + old_name='facebook', + new_name='taxcode', + ), + migrations.RemoveField( + model_name='people', + name='zalo', + ), + migrations.AddField( + model_name='transaction_detail', + name='amount_received', + field=models.DecimalField(decimal_places=2, max_digits=15, null=True), + ), + migrations.AddField( + model_name='transaction_detail', + name='amount_remaining', + field=models.DecimalField(decimal_places=2, max_digits=15, null=True), + ), + ] diff --git a/app/models.py b/app/models.py index 6831d794..28a0c21f 100644 --- a/app/models.py +++ b/app/models.py @@ -1200,8 +1200,7 @@ class People(models.Model): issued_date = models.DateField(null=True) address = models.CharField(max_length=200, null=True) contact_address = models.CharField(max_length=200, null=True) - zalo = models.CharField(max_length=20, null=True) - facebook = models.CharField(max_length=100, null=True) + taxcode = models.CharField(max_length=100, null=True) note = models.TextField(null=True) country = models.ForeignKey(Country, null=True, related_name='+', on_delete=models.PROTECT, default=1) company = models.ForeignKey(Company, null=True, related_name='+', on_delete=models.PROTECT) @@ -1371,6 +1370,8 @@ class Transaction_Detail(AutoCodeModel): code = models.CharField(max_length=30, null=True, unique=True) date = models.DateField() amount = models.DecimalField(max_digits=15, decimal_places=2, null=True) + amount_remaining = models.DecimalField(max_digits=15, decimal_places=2, null=True) + amount_received = models.DecimalField(max_digits=15, decimal_places=2, null=True) due_date = models.DateField(null=True) transaction = models.ForeignKey(Transaction, null=False, related_name='resvtxn', on_delete=models.PROTECT) phase = models.ForeignKey(Transaction_Phase, null=False, related_name='+', on_delete=models.PROTECT)