u
This commit is contained in:
@@ -134,6 +134,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/delivery/delete.md`](routes/delivery/delete.md) | `DELETE /delivery/{id}` |
|
||||
| [`routes/delivery/get.md`](routes/delivery/get.md) | `GET /delivery/{id}` |
|
||||
| [`routes/delivery/update.md`](routes/delivery/update.md) | `PATCH /delivery/{id}` |
|
||||
| [`routes/delivery/_id/file/_fileId.delete.md`](routes/delivery/_id/file/_fileId.delete.md) | `DELETE /delivery/{id}/file/{fileId}` |
|
||||
| [`routes/delivery/file.md`](routes/delivery/file.md) | `GET /delivery/{id}/file/{fileId}` |
|
||||
| [`routes/delivery/_id/pdf.md`](routes/delivery/_id/pdf.md) | `POST /delivery/{id}/pdf` |
|
||||
| [`routes/entity/list.md`](routes/entity/list.md) | `GET /entity` |
|
||||
@@ -188,7 +189,8 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/order/delete.md`](routes/order/delete.md) | `DELETE /order/{id}` |
|
||||
| [`routes/order/get.md`](routes/order/get.md) | `GET /order/{id}` |
|
||||
| [`routes/order/update.md`](routes/order/update.md) | `PATCH /order/{id}` |
|
||||
| [`routes/order/_id/file/_fileId.md`](routes/order/_id/file/_fileId.md) | `GET /order/{id}/file/{fileId}` |
|
||||
| [`routes/order/_id/file/_fileId.delete.md`](routes/order/_id/file/_fileId.delete.md) | `DELETE /order/{id}/file/{fileId}` |
|
||||
| [`routes/order/_id/file/_fileId.get.md`](routes/order/_id/file/_fileId.get.md) | `GET /order/{id}/file/{fileId}` |
|
||||
| [`routes/order/_id/payment.get.md`](routes/order/_id/payment.get.md) | `GET /order/{id}/payment` |
|
||||
| [`routes/order/_id/payment.post.md`](routes/order/_id/payment.post.md) | `POST /order/{id}/payment` |
|
||||
| [`routes/order/_id/pdf.md`](routes/order/_id/pdf.md) | `POST /order/{id}/pdf` |
|
||||
@@ -227,13 +229,15 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route
|
||||
| [`routes/quote/delete.md`](routes/quote/delete.md) | `DELETE /quote/{id}` |
|
||||
| [`routes/quote/get.md`](routes/quote/get.md) | `GET /quote/{id}` |
|
||||
| [`routes/quote/update.md`](routes/quote/update.md) | `PATCH /quote/{id}` |
|
||||
| [`routes/quote/_id/file/_fileId.md`](routes/quote/_id/file/_fileId.md) | `GET /quote/{id}/file/{fileId}` |
|
||||
| [`routes/quote/_id/file/_fileId.delete.md`](routes/quote/_id/file/_fileId.delete.md) | `DELETE /quote/{id}/file/{fileId}` |
|
||||
| [`routes/quote/_id/file/_fileId.get.md`](routes/quote/_id/file/_fileId.get.md) | `GET /quote/{id}/file/{fileId}` |
|
||||
| [`routes/quote/_id/pdf.md`](routes/quote/_id/pdf.md) | `POST /quote/{id}/pdf` |
|
||||
| [`routes/serper/image.md`](routes/serper/image.md) | `POST /serper/image` |
|
||||
| [`routes/serper/images.md`](routes/serper/images.md) | `POST /serper/images` |
|
||||
| [`routes/shipment/_id.delete.md`](routes/shipment/_id.delete.md) | `DELETE /shipment/{id}` |
|
||||
| [`routes/shipment/_id.get.md`](routes/shipment/_id.get.md) | `GET /shipment/{id}` |
|
||||
| [`routes/shipment/_id/file/_fileId.md`](routes/shipment/_id/file/_fileId.md) | `GET /shipment/{id}/file/{fileId}` |
|
||||
| [`routes/shipment/_id/file/_fileId.delete.md`](routes/shipment/_id/file/_fileId.delete.md) | `DELETE /shipment/{id}/file/{fileId}` |
|
||||
| [`routes/shipment/_id/file/_fileId.get.md`](routes/shipment/_id/file/_fileId.get.md) | `GET /shipment/{id}/file/{fileId}` |
|
||||
| [`routes/shipment/_id/pdf.md`](routes/shipment/_id/pdf.md) | `POST /shipment/{id}/pdf` |
|
||||
| [`routes/shipment/_id/shipping.get.md`](routes/shipment/_id/shipping.get.md) | `GET /shipment/{id}/shipping` |
|
||||
| [`routes/shipment/_id/shipping.post.md`](routes/shipment/_id/shipping.post.md) | `POST /shipment/{id}/shipping` |
|
||||
@@ -288,16 +292,16 @@ Clients subscribe via [`GET /events`](routes/events.md) (`text/event-stream`). A
|
||||
| `attributename` | `POST /attributename`, `PUT /attributename/order`, `DELETE /attributename/{id}`, `PATCH /attributename/{id}`, `DELETE /attributevalue/{id}/image`, `POST /attributevalue/{id}/image` |
|
||||
| `brand` | `POST /brand`, `DELETE /brand/{id}`, `PATCH /brand/{id}`, `DELETE /brand/{id}/image`, `POST /brand/{id}/image` |
|
||||
| `category` | `POST /category`, `PUT /category/order`, `DELETE /category/{id}`, `PATCH /category/{id}`, `DELETE /category/{id}/image`, `POST /category/{id}/image` |
|
||||
| `delivery` | `POST /delivery/{id}/pdf` |
|
||||
| `delivery` | `DELETE /delivery/{id}/file/{fileId}`, `POST /delivery/{id}/pdf` |
|
||||
| `labeltemplate` | `POST /labeltemplate`, `DELETE /labeltemplate/{id}`, `PATCH /labeltemplate/{id}`, `PUT /labeltemplate/{id}` |
|
||||
| `ledger` | `POST /stock/adjust` |
|
||||
| `modelconversation` | `POST /modelconversation`, `DELETE /modelconversation/{id}` |
|
||||
| `modelconversation-<id>` | `POST /modelconversation/{id}/message` |
|
||||
| `order` | `POST /order/{id}/pdf` |
|
||||
| `order` | `DELETE /order/{id}/file/{fileId}`, `POST /order/{id}/pdf`, `DELETE /shipment/{id}/file/{fileId}` |
|
||||
| `printer` | `POST /printer`, `PUT /printer/order`, `DELETE /printer/{id}`, `PATCH /printer/{id}`, `PUT /printer/{id}` |
|
||||
| `propertyname` | `POST /propertyname`, `PUT /propertyname/order`, `DELETE /propertyname/{id}`, `PATCH /propertyname/{id}` |
|
||||
| `quote` | `POST /quote/{id}/pdf` |
|
||||
| `shipment` | `POST /shipment/{id}/pdf` |
|
||||
| `quote` | `DELETE /quote/{id}/file/{fileId}`, `POST /quote/{id}/pdf` |
|
||||
| `shipment` | `DELETE /shipment/{id}/file/{fileId}`, `POST /shipment/{id}/pdf` |
|
||||
| `stock` | `POST /stock/adjust` |
|
||||
| `vfs` | `POST /vfs/mkdir`, `POST /vfs/rename`, `POST /vfs/upload`, `DELETE /vfs/{*path}`, `POST /vfs/{*path}`, `PUT /vfs/{*path}` |
|
||||
| `warehouse` | `POST /warehouse`, `PUT /warehouse/order`, `DELETE /warehouse/{id}`, `PUT /warehouse/{id}` |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dash API Routes Overview (All)
|
||||
|
||||
Overview of all 242 API endpoints across all modules.
|
||||
Overview of all 246 API endpoints across all modules.
|
||||
|
||||
### Notation
|
||||
|
||||
@@ -419,6 +419,9 @@ _none_
|
||||
#### Update delivery — `PATCH /delivery/{id}`
|
||||
- Params: `id: int, body: { externalNumber?: str|null, date?: str, supplierId?: int|null, lines?: T34[], files?: { mimetype: str, name: str, content: str, sort?: int, size?: int, hash?: str, created?: str, modified?: str, meta?: { [k]: str } }[] }`
|
||||
- Returns: `200 T6`
|
||||
#### Delete delivery file attachment — `DELETE /delivery/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Get delivery attachment file content — `GET /delivery/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int, query: download?: bool`
|
||||
- Returns: `200 str`
|
||||
@@ -632,6 +635,9 @@ _none_
|
||||
#### Update order — `PATCH /order/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, lines?: T34[] }`
|
||||
- Returns: `200 T1`
|
||||
#### Delete order file attachment — `DELETE /order/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Get order attachment file content — `GET /order/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int, query: download?: bool`
|
||||
- Returns: `200 str`
|
||||
@@ -770,6 +776,9 @@ _none_
|
||||
#### Update quote — `PATCH /quote/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, lines?: T34[] }`
|
||||
- Returns: `200 T8`
|
||||
#### Delete quote file attachment — `DELETE /quote/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Get quote attachment file content — `GET /quote/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int, query: download?: bool`
|
||||
- Returns: `200 str`
|
||||
@@ -800,6 +809,9 @@ _none_
|
||||
#### Get shipment by ID — `GET /shipment/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shipment: T5 }`
|
||||
#### Delete shipment file attachment — `DELETE /shipment/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Get shipment attachment file content — `GET /shipment/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int, query: download?: bool`
|
||||
- Returns: `200 str`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Dash API Routes Overview
|
||||
|
||||
Overview of all 167 API endpoints across all modules.
|
||||
Overview of all 171 API endpoints across all modules.
|
||||
|
||||
### Notation
|
||||
|
||||
@@ -325,6 +325,9 @@ _none_
|
||||
#### Update delivery — `PATCH /delivery/{id}`
|
||||
- Params: `id: int, body: { externalNumber?: str|null, date?: str, supplierId?: int|null, lines?: T28[], files?: { mimetype: str, name: str, content: str, sort?: int, size?: int, hash?: str, created?: str, modified?: str, meta?: { [k]: str } }[] }`
|
||||
- Returns: `200 T6`
|
||||
#### Delete delivery file attachment — `DELETE /delivery/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Generate and attach delivery note PDF (goods receipt) — `POST /delivery/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 T11`
|
||||
@@ -436,6 +439,9 @@ _none_
|
||||
#### Update order — `PATCH /order/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, lines?: T28[] }`
|
||||
- Returns: `200 T1`
|
||||
#### Delete order file attachment — `DELETE /order/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### List payments of an order — `GET /order/{id}/payment`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { payments: T37[] }`
|
||||
@@ -529,6 +535,9 @@ _none_
|
||||
#### Update quote — `PATCH /quote/{id}`
|
||||
- Params: `id: int, body: { number?: str, date?: str, entityId?: int|null, lines?: T28[] }`
|
||||
- Returns: `200 T8`
|
||||
#### Delete quote file attachment — `DELETE /quote/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Generate and attach quote PDF — `POST /quote/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 T11`
|
||||
@@ -541,6 +550,9 @@ _none_
|
||||
#### Get shipment by ID — `GET /shipment/{id}`
|
||||
- Params: `id: int`
|
||||
- Returns: `200 { shipment: T5 }`
|
||||
#### Delete shipment file attachment — `DELETE /shipment/{id}/file/{fileId}`
|
||||
- Params: `id: int, fileId: int`
|
||||
- Returns: `204 void`
|
||||
#### Generate and attach shipment PDF (delivery note) — `POST /shipment/{id}/pdf`
|
||||
- Params: `id: int`
|
||||
- Returns: `201 T11`
|
||||
|
||||
38
docs/api/routes/delivery/_id/file/_fileId.delete.md
Normal file
38
docs/api/routes/delivery/_id/file/_fileId.delete.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# `DELETE /delivery/{id}/file/{fileId}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete delivery file attachment
|
||||
|
||||
Removes a file attachment from the delivery and deletes the underlying file.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Delivery ID |
|
||||
| `fileId` | yes | integer | File ID or attachment ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `delivery` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Attachment deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid parameters or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Delivery or attachment not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
38
docs/api/routes/order/_id/file/_fileId.delete.md
Normal file
38
docs/api/routes/order/_id/file/_fileId.delete.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# `DELETE /order/{id}/file/{fileId}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete order file attachment
|
||||
|
||||
Removes a file attachment from the order and deletes the underlying file.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Order ID |
|
||||
| `fileId` | yes | integer | File ID or attachment ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `order` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Attachment deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid parameters or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Order or attachment not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
38
docs/api/routes/quote/_id/file/_fileId.delete.md
Normal file
38
docs/api/routes/quote/_id/file/_fileId.delete.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# `DELETE /quote/{id}/file/{fileId}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete quote file attachment
|
||||
|
||||
Removes a file attachment from the quote and deletes the underlying file.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Quote ID |
|
||||
| `fileId` | yes | integer | File ID or attachment ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signal: `quote` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Attachment deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid parameters or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Quote or attachment not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
38
docs/api/routes/shipment/_id/file/_fileId.delete.md
Normal file
38
docs/api/routes/shipment/_id/file/_fileId.delete.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# `DELETE /shipment/{id}/file/{fileId}`
|
||||
|
||||
Protected. Requires a valid session cookie (`credentials: 'include'`).
|
||||
|
||||
Delete shipment file attachment
|
||||
|
||||
Removes a file attachment from the shipment and deletes the underlying file.
|
||||
|
||||
|
||||
## Path parameters
|
||||
|
||||
| Param | Required | Type | Description |
|
||||
|-------|----------|------|-------------|
|
||||
| `id` | yes | integer | Shipment ID |
|
||||
| `fileId` | yes | integer | File ID or attachment ID |
|
||||
|
||||
## Signals
|
||||
|
||||
On success, emits SSE signals: `shipment`, `order` (see [`GET /events`](../events.md)).
|
||||
|
||||
## Response `204`
|
||||
|
||||
Attachment deleted
|
||||
|
||||
_No content_
|
||||
|
||||
## Errors
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| 400 | Invalid parameters or no company selected — `{"error":"…"}` |
|
||||
| 401 | Unauthorized — `{"error":"…"}` |
|
||||
| 403 | Not authorized — `{"error":"…"}` |
|
||||
| 404 | Shipment or attachment not found — `{"error":"…"}` |
|
||||
|
||||
---
|
||||
|
||||
_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._
|
||||
@@ -2,6 +2,7 @@ import multer from 'multer';
|
||||
import * as db from '../../db/delivery.js';
|
||||
import { createAndAttachManifestPdf } from '../../services/manifestPdf.js';
|
||||
import { writeErrorLog } from '../../util/errorLog.js';
|
||||
import { emit } from '../sse.js';
|
||||
|
||||
// #region Helpers
|
||||
|
||||
@@ -995,5 +996,89 @@ export function register(app, basePath = '') {
|
||||
});
|
||||
|
||||
// #endregion
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /delivery/{id}/file/{fileId}:
|
||||
* delete:
|
||||
* tags: [Delivery]
|
||||
* summary: Delete delivery file attachment
|
||||
* description: |
|
||||
* Removes a file attachment from the delivery and deletes the underlying file.
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* x-signals: [delivery]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Delivery ID
|
||||
* - in: path
|
||||
* name: fileId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: File ID or attachment ID
|
||||
* responses:
|
||||
* 204:
|
||||
* description: Attachment deleted
|
||||
* 400:
|
||||
* description: Invalid parameters or no company selected
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 403:
|
||||
* description: Not authorized
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 404:
|
||||
* description: Delivery or attachment not found
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
// #region DELETE /delivery/:id/file/:fileId
|
||||
|
||||
app.delete(`${basePath}/delivery/:id/file/:fileId`, async (req, res) => {
|
||||
const selected = requireSelectedCompany(req);
|
||||
if (selected.error) {
|
||||
return res.status(400).json({ error: selected.error });
|
||||
}
|
||||
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id) || id <= 0) {
|
||||
return res.status(400).json({ error: 'id is required' });
|
||||
}
|
||||
|
||||
const fileId = Number(req.params.fileId);
|
||||
if (!Number.isInteger(fileId) || fileId <= 0) {
|
||||
return res.status(400).json({ error: 'fileId is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
await db.removeAttachment(req.user.id, id, fileId);
|
||||
emit('delivery', { companyId: selected.companyId });
|
||||
res.sendStatus(204);
|
||||
} catch (error) {
|
||||
const status = deliveryErrorStatus(error);
|
||||
if (status === 500) console.error('Delete delivery attachment failed:', error);
|
||||
res.status(status).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// #endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as db from '../../db/order.js';
|
||||
import { createAndAttachManifestPdf } from '../../services/manifestPdf.js';
|
||||
import { emit } from '../sse.js';
|
||||
|
||||
// #region Helpers
|
||||
|
||||
@@ -779,4 +780,88 @@ export function register(app, basePath = '') {
|
||||
});
|
||||
|
||||
// #endregion
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /order/{id}/file/{fileId}:
|
||||
* delete:
|
||||
* tags: [Order]
|
||||
* summary: Delete order file attachment
|
||||
* description: |
|
||||
* Removes a file attachment from the order and deletes the underlying file.
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* x-signals: [order]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Order ID
|
||||
* - in: path
|
||||
* name: fileId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: File ID or attachment ID
|
||||
* responses:
|
||||
* 204:
|
||||
* description: Attachment deleted
|
||||
* 400:
|
||||
* description: Invalid parameters or no company selected
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 403:
|
||||
* description: Not authorized
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 404:
|
||||
* description: Order or attachment not found
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
// #region DELETE /order/:id/file/:fileId
|
||||
|
||||
app.delete(`${basePath}/order/:id/file/:fileId`, async (req, res) => {
|
||||
const selected = requireSelectedCompany(req);
|
||||
if (selected.error) {
|
||||
return res.status(400).json({ error: selected.error });
|
||||
}
|
||||
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id) || id <= 0) {
|
||||
return res.status(400).json({ error: 'id is required' });
|
||||
}
|
||||
|
||||
const fileId = Number(req.params.fileId);
|
||||
if (!Number.isInteger(fileId) || fileId <= 0) {
|
||||
return res.status(400).json({ error: 'fileId is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
await db.removeAttachment(req.user.id, id, fileId);
|
||||
emit('order', { companyId: selected.companyId });
|
||||
res.sendStatus(204);
|
||||
} catch (error) {
|
||||
const status = orderErrorStatus(error);
|
||||
if (status === 500) console.error('Delete order attachment failed:', error);
|
||||
res.status(status).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// #endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as db from '../../db/quote.js';
|
||||
import { createAndAttachManifestPdf } from '../../services/manifestPdf.js';
|
||||
import { emit } from '../sse.js';
|
||||
|
||||
// #region Helpers
|
||||
|
||||
@@ -758,4 +759,88 @@ export function register(app, basePath = '') {
|
||||
});
|
||||
|
||||
// #endregion
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /quote/{id}/file/{fileId}:
|
||||
* delete:
|
||||
* tags: [Quote]
|
||||
* summary: Delete quote file attachment
|
||||
* description: |
|
||||
* Removes a file attachment from the quote and deletes the underlying file.
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* x-signals: [quote]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Quote ID
|
||||
* - in: path
|
||||
* name: fileId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: File ID or attachment ID
|
||||
* responses:
|
||||
* 204:
|
||||
* description: Attachment deleted
|
||||
* 400:
|
||||
* description: Invalid parameters or no company selected
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 403:
|
||||
* description: Not authorized
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 404:
|
||||
* description: Quote or attachment not found
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
// #region DELETE /quote/:id/file/:fileId
|
||||
|
||||
app.delete(`${basePath}/quote/:id/file/:fileId`, async (req, res) => {
|
||||
const selected = requireSelectedCompany(req);
|
||||
if (selected.error) {
|
||||
return res.status(400).json({ error: selected.error });
|
||||
}
|
||||
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id) || id <= 0) {
|
||||
return res.status(400).json({ error: 'id is required' });
|
||||
}
|
||||
|
||||
const fileId = Number(req.params.fileId);
|
||||
if (!Number.isInteger(fileId) || fileId <= 0) {
|
||||
return res.status(400).json({ error: 'fileId is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
await db.removeAttachment(req.user.id, id, fileId);
|
||||
emit('quote', { companyId: selected.companyId });
|
||||
res.sendStatus(204);
|
||||
} catch (error) {
|
||||
const status = quoteErrorStatus(error);
|
||||
if (status === 500) console.error('Delete quote attachment failed:', error);
|
||||
res.status(status).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// #endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -591,5 +591,89 @@ export function register(app, basePath = '') {
|
||||
});
|
||||
|
||||
// #endregion
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /shipment/{id}/file/{fileId}:
|
||||
* delete:
|
||||
* tags: [Shipment]
|
||||
* summary: Delete shipment file attachment
|
||||
* description: |
|
||||
* Removes a file attachment from the shipment and deletes the underlying file.
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* x-signals: [shipment, order]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Shipment ID
|
||||
* - in: path
|
||||
* name: fileId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: File ID or attachment ID
|
||||
* responses:
|
||||
* 204:
|
||||
* description: Attachment deleted
|
||||
* 400:
|
||||
* description: Invalid parameters or no company selected
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 401:
|
||||
* description: Unauthorized
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 403:
|
||||
* description: Not authorized
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 404:
|
||||
* description: Shipment or attachment not found
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
// #region DELETE /shipment/:id/file/:fileId
|
||||
|
||||
app.delete(`${basePath}/shipment/:id/file/:fileId`, async (req, res) => {
|
||||
const selected = requireSelectedCompany(req);
|
||||
if (selected.error) {
|
||||
return res.status(400).json({ error: selected.error });
|
||||
}
|
||||
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id) || id <= 0) {
|
||||
return res.status(400).json({ error: 'id is required' });
|
||||
}
|
||||
|
||||
const fileId = Number(req.params.fileId);
|
||||
if (!Number.isInteger(fileId) || fileId <= 0) {
|
||||
return res.status(400).json({ error: 'fileId is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
await db.removeAttachment(req.user.id, id, fileId);
|
||||
emitShipmentEvents(selected.companyId);
|
||||
res.sendStatus(204);
|
||||
} catch (error) {
|
||||
const status = shipmentErrorStatus(error);
|
||||
if (status === 500) console.error('Delete shipment attachment failed:', error);
|
||||
res.status(status).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// #endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,3 +40,9 @@ export async function listAttachments(googleAuthId, deliveryId) {
|
||||
return store.manifestattachment.listByManifestId(googleAuthId, deliveryId);
|
||||
}
|
||||
|
||||
export async function removeAttachment(googleAuthId, deliveryId, fileId) {
|
||||
const store = await getStore();
|
||||
return store.manifestattachment.remove(googleAuthId, deliveryId, fileId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -173,4 +173,10 @@ export async function listAttachments(googleAuthId, orderId) {
|
||||
return store.manifestattachment.listByManifestId(googleAuthId, orderId);
|
||||
}
|
||||
|
||||
export async function removeAttachment(googleAuthId, orderId, fileId) {
|
||||
const store = await getStore();
|
||||
return store.manifestattachment.remove(googleAuthId, orderId, fileId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -103,3 +103,9 @@ export async function listAttachments(googleAuthId, quoteId) {
|
||||
return store.manifestattachment.listByManifestId(googleAuthId, quoteId);
|
||||
}
|
||||
|
||||
export async function removeAttachment(googleAuthId, quoteId, fileId) {
|
||||
const store = await getStore();
|
||||
return store.manifestattachment.remove(googleAuthId, quoteId, fileId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,3 +43,9 @@ export async function listAttachments(googleAuthId, shipmentId) {
|
||||
return store.manifestattachment.listByManifestId(googleAuthId, shipmentId);
|
||||
}
|
||||
|
||||
export async function removeAttachment(googleAuthId, shipmentId, fileId) {
|
||||
const store = await getStore();
|
||||
return store.manifestattachment.remove(googleAuthId, shipmentId, fileId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user