u
This commit is contained in:
@@ -32,10 +32,21 @@ function parseCompanyId(id) {
|
||||
return { companyId };
|
||||
}
|
||||
|
||||
function requireSelectedCompany(req) {
|
||||
const id = req.user?.selectedCompanyId;
|
||||
if (id == null) {
|
||||
const err = new Error('No company selected');
|
||||
err.statusCode = 400;
|
||||
throw err;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
function companyErrorStatus(error) {
|
||||
if (error.message === 'Company not found') return 404;
|
||||
if (error.message === 'Company name not available') return 409;
|
||||
if (error.message === 'Invalid tax rate') return 400;
|
||||
if (error.message === 'Invalid tax rate' || error.message === 'Text required' || error.message === 'No company selected') return 400;
|
||||
if (error.message === 'Not authorized') return 403;
|
||||
return 500;
|
||||
}
|
||||
|
||||
@@ -167,6 +178,170 @@ export function register(app, basePath = '') {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /company/history:
|
||||
* get:
|
||||
* tags: [Company]
|
||||
* summary: Get company history
|
||||
* description: |
|
||||
* Returns `companyhistory` rows for the selected company, newest first (`date` DESC, `id` DESC).
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* x-markdown: company/history.md
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: limit
|
||||
* required: false
|
||||
* schema:
|
||||
* type: integer
|
||||
* minimum: 1
|
||||
* maximum: 1000
|
||||
* description: Maximum number of entries to return (newest first). Omit for all entries.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Company history (newest first)
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [history, truncated]
|
||||
* properties:
|
||||
* history:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/CompanyHistoryEntry'
|
||||
* truncated:
|
||||
* type: boolean
|
||||
* description: True when a limit was applied and the result set was exactly that size (more entries may exist).
|
||||
* 400:
|
||||
* description: Invalid limit 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: Forbidden
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 500:
|
||||
* description: Server error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* post:
|
||||
* tags: [Company]
|
||||
* summary: Add company history entry
|
||||
* description: |
|
||||
* Appends an entry to `companyhistory` for the selected company.
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* x-markdown: company/addHistory.md
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [text]
|
||||
* properties:
|
||||
* text:
|
||||
* type: string
|
||||
* description: History entry text or note
|
||||
* responses:
|
||||
* 201:
|
||||
* description: History entry created
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required: [history]
|
||||
* properties:
|
||||
* history:
|
||||
* $ref: '#/components/schemas/CompanyHistoryEntry'
|
||||
* 400:
|
||||
* description: Text required 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: Forbidden
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
* 500:
|
||||
* description: Server error
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Error'
|
||||
*/
|
||||
app.get(`${basePath}/company/history`, async (req, res) => {
|
||||
try {
|
||||
requireSelectedCompany(req);
|
||||
} catch (error) {
|
||||
return res.status(error.statusCode || 400).json({ error: error.message });
|
||||
}
|
||||
|
||||
const rawLimit = req.query.limit;
|
||||
let limit = null;
|
||||
if (rawLimit !== undefined) {
|
||||
limit = parseInt(rawLimit, 10);
|
||||
if (!Number.isInteger(limit) || limit < 1 || limit > 1000) {
|
||||
return res.status(400).json({ error: 'limit must be an integer between 1 and 1000' });
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const history = await db.getCompanyHistory(req.user.id, limit != null ? { limit } : undefined);
|
||||
const truncated = limit != null && history.length === limit;
|
||||
res.status(200).json({ history, truncated });
|
||||
} catch (error) {
|
||||
const status = companyErrorStatus(error);
|
||||
if (status === 500) console.error('Get company history failed:', error);
|
||||
res.status(status).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.post(`${basePath}/company/history`, async (req, res) => {
|
||||
try {
|
||||
requireSelectedCompany(req);
|
||||
} catch (error) {
|
||||
return res.status(error.statusCode || 400).json({ error: error.message });
|
||||
}
|
||||
|
||||
const text = typeof req.body?.text === 'string' ? req.body.text.trim() : '';
|
||||
if (!text) {
|
||||
return res.status(400).json({ error: 'text is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
const entry = await db.addCompanyHistory(req.user.id, { text });
|
||||
res.status(201).json({ history: entry });
|
||||
} catch (error) {
|
||||
const status = companyErrorStatus(error);
|
||||
if (status === 500) console.error('Add company history failed:', error);
|
||||
res.status(status).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @openapi
|
||||
* /company/{id}:
|
||||
|
||||
Reference in New Issue
Block a user