Repository: paperless-ngx/paperless-ngx

Issue:
[BUG] Wrong ASN on "+1" Button with multiuser
### Description

If another user will add a document and set an ASN on it, the "+1" Button near the ASN fild wont work for the other users, because the numbering is wrong.

![image](https://github.com/paperless-ngx/paperless-ngx/assets/6043382/ef8dec2a-4a67-46f7-8fa4-f5ba3bc7fb21)

If the document with the first given ASN is shared to me, the "+1" Button will add the correct number (2 in this case).
If i cant see the other document (not shared) the "+1" Button will add a one and then i can't save the document because the ASN is still used.

### Steps to reproduce

**User1:**

- One user add adds a document
- Set a ASN on this document with "+1" button (1 is added)
- Save the document

**User2:**

- Other user adds a document
- Set a ASN on this document with "+1" button (1 is added)
- Try to save the document (error: ASN still in use)

User1 will share the document with User2.
Retry the steps from User2 - now a push on "+1" will add the correct ASN (2)

### Webserver logs

```bash
no logs needed
```


### Browser logs

_No response_

### Paperless-ngx version

1.17.4

### Host OS

Debian on Proxmox (Intel NUC)

### Installation method

Docker - official image

### Browser

Chrome

### Configuration changes

_No response_

### Other

**Solution:**
A global counter for the ASN should be respected, also if documents are not shared. ASNs should uniqe over the whole paperless instance, not only by the user.

or

Prefixed ASNs to make it uniqe for each user.


Discussion:
The ASN-feature doesn't seems to have a multiuser functionality at the moment. 
See also discussion: #4169 and #1841

Resolving patch:
diff --git a/src/documents/views.py b/src/documents/views.py
--- a/src/documents/views.py
+++ b/src/documents/views.py
@@ -661,6 +661,19 @@ def list(self, request, *args, **kwargs):
         else:
             return super().list(request)
 
+    @action(detail=False, methods=["GET"], name="Get Next ASN")
+    def next_asn(self, request, *args, **kwargs):
+        return Response(
+            (
+                Document.objects.filter(archive_serial_number__gte=0)
+                .order_by("archive_serial_number")
+                .last()
+                .archive_serial_number
+                or 0
+            )
+            + 1,
+        )
+
 
 class LogViewSet(ViewSet):
     permission_classes = (IsAuthenticated, PaperlessAdminPermissions)


Test patch:
diff --git a/src/documents/tests/test_api.py b/src/documents/tests/test_api.py
--- a/src/documents/tests/test_api.py
+++ b/src/documents/tests/test_api.py
@@ -2689,6 +2689,50 @@ def test_share_links_permissions_aware(self):
         )
         self.assertEqual(resp.status_code, status.HTTP_200_OK)
 
+    def test_next_asn(self):
+        """
+        GIVEN:
+            - Existing documents with ASNs, highest owned by user2
+        WHEN:
+            - API request is made by user1 to get next ASN
+        THEN:
+            - ASN +1 from user2's doc is returned for user1
+        """
+        user1 = User.objects.create_user(username="test1")
+        user1.user_permissions.add(*Permission.objects.all())
+        user1.save()
+
+        user2 = User.objects.create_user(username="test2")
+        user2.save()
+
+        doc1 = Document.objects.create(
+            title="test",
+            mime_type="application/pdf",
+            content="this is a document 1",
+            checksum="1",
+            archive_serial_number=998,
+        )
+        doc1.owner = user1
+        doc1.save()
+
+        doc2 = Document.objects.create(
+            title="test2",
+            mime_type="application/pdf",
+            content="this is a document 2 with higher ASN",
+            checksum="2",
+            archive_serial_number=999,
+        )
+        doc2.owner = user2
+        doc2.save()
+
+        self.client.force_authenticate(user1)
+
+        resp = self.client.get(
+            "/api/documents/next_asn/",
+        )
+        self.assertEqual(resp.status_code, status.HTTP_200_OK)
+        self.assertEqual(resp.content, b"1000")
+
 
 class TestDocumentApiV2(DirectoriesMixin, APITestCase):
     def setUp(self):