Skip to content

Commit

Permalink
invoice basic working
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasHub committed Dec 31, 2024
1 parent 1155cee commit 9c5f22b
Show file tree
Hide file tree
Showing 14 changed files with 105 additions and 46 deletions.
4 changes: 2 additions & 2 deletions backend/src/controllers/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const saveClient = async (req: ConfacRequest, res: Response) => {

await saveAudit(req, 'client', originalClient, client);
const clientResponse = {_id, ...client};
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.CLIENTS, _id, clientResponse);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityUpdated, entityType: CollectionNames.CLIENTS, entityId: _id, entity: clientResponse });
return res.send(clientResponse);
}

Expand All @@ -42,6 +42,6 @@ export const saveClient = async (req: ConfacRequest, res: Response) => {
client.audit = createAudit(req.user);
const inserted = await req.db.collection(CollectionNames.CLIENTS).insertOne(client);
const [createdClient] = inserted.ops;
emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.CLIENTS, createdClient._id, createdClient);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityCreated, entityType: CollectionNames.CLIENTS, entityId: createdClient._id, entity: createdClient });
return res.send(createdClient);
};
4 changes: 2 additions & 2 deletions backend/src/controllers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ export const saveCompanyConfig = async (req: ConfacRequest, res: Response) => {

await saveAudit(req, 'config', originalConfig, config);
const responseConfig = {_id, ...config};
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.CONFIG, _id, responseConfig);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityUpdated, entityType: CollectionNames.CONFIG, entityId: _id, entity: responseConfig });
return res.send(responseConfig);
}

const inserted = await req.db.collection<ICompanyConfig>(CollectionNames.CONFIG).insertOne(config);
const responseConfig = inserted.ops[0];
emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.CONFIG, responseConfig._id, responseConfig);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityCreated, entityType: CollectionNames.CONFIG, entityId: responseConfig._id, entity: responseConfig });
return res.send(responseConfig);
};

Expand Down
4 changes: 2 additions & 2 deletions backend/src/controllers/consultants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const saveConsultant = async (req: ConfacRequest, res: Response) => {

await saveAudit(req, 'consultant', originalConsultant, consultant);
const responseConsultant = {_id, ...consultant};
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.CONSULTANTS, _id, responseConsultant);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityUpdated, entityType: CollectionNames.CONSULTANTS, entityId: _id, entity: responseConsultant });
return res.send(responseConsultant);
}

Expand All @@ -34,6 +34,6 @@ export const saveConsultant = async (req: ConfacRequest, res: Response) => {
audit: createAudit(req.user),
});
const [createdConsultant] = inserted.ops;
emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.CONSULTANTS, createdConsultant._id, createdConsultant);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityCreated, entityType: CollectionNames.CONSULTANTS, entityId: createdConsultant._id, entity: createdConsultant });
return res.send(createdConsultant);
};
37 changes: 26 additions & 11 deletions backend/src/controllers/invoices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import {ObjectID, Db} from 'mongodb';
import {IInvoice, INVOICE_EXCEL_HEADERS} from '../models/invoices';
import {IAttachmentCollection} from '../models/attachments';
import {createPdf, createXml} from './utils';
import {CollectionNames, IAttachment, createAudit, updateAudit} from '../models/common';
import {CollectionNames, IAttachment, SocketEventTypes, createAudit, updateAudit} from '../models/common';
import {IProjectMonth} from '../models/projectsMonth';
import {ConfacRequest, Jwt} from '../models/technical';
import {saveAudit} from './utils/audit-logs';
import {emitEntityEvent} from './utils/entity-events';


const createInvoice = async (invoice: IInvoice, db: Db, pdfBuffer: Buffer, user: Jwt) => {
Expand Down Expand Up @@ -49,14 +50,16 @@ const moveProjectMonthAttachmentsToInvoice = async (invoice: IInvoice, projectMo
const projectMonth = await db.collection<IProjectMonth>(CollectionNames.PROJECTS_MONTH).findOne({_id: projectMonthId});
const updatedAttachmentDetails = projectMonth ? [...invoice.attachments, ...projectMonth?.attachments] : invoice.attachments;

const inserted = await db.collection<IInvoice>(CollectionNames.INVOICES)
const updateInvoiceResult = await db.collection<IInvoice>(CollectionNames.INVOICES)
.findOneAndUpdate({_id: new ObjectID(invoice._id)}, {$set: {attachments: updatedAttachmentDetails}}, {returnOriginal: false});
const updatedInvoice = inserted.value;
const updatedInvoice = updateInvoiceResult.value;

const updateProjectMonthResult = await db.collection<IProjectMonth>(CollectionNames.PROJECTS_MONTH).findOneAndUpdate({_id: projectMonthId}, {$set: {attachments: []}});
const updatedProjectMonth = updateProjectMonthResult.value;

await db.collection<IProjectMonth>(CollectionNames.PROJECTS_MONTH).findOneAndUpdate({_id: projectMonthId}, {$set: {attachments: []}});
await db.collection(CollectionNames.ATTACHMENTS_PROJECT_MONTH).findOneAndDelete({_id: projectMonthId});

return updatedInvoice;
return {updatedInvoice, updatedProjectMonth};
};


Expand Down Expand Up @@ -114,11 +117,13 @@ export const createInvoiceController = async (req: ConfacRequest, res: Response)

if (invoice.projectMonth) {
const projectMonthId = new ObjectID(invoice.projectMonth.projectMonthId);
const updatedInvoice = await moveProjectMonthAttachmentsToInvoice(createdInvoice, projectMonthId, req.db);

const {updatedInvoice, updatedProjectMonth} = await moveProjectMonthAttachmentsToInvoice(createdInvoice, projectMonthId, req.db);
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.INVOICES, updatedInvoice!._id, updatedInvoice);
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.PROJECTS_MONTH, updatedProjectMonth!._id, updatedProjectMonth);
return res.send(updatedInvoice);
}

emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.INVOICES, createdInvoice._id, createdInvoice);
return res.send(createdInvoice);
};

Expand Down Expand Up @@ -172,15 +177,20 @@ export const updateInvoiceController = async (req: ConfacRequest, res: Response)
.findOneAndUpdate({_id: new ObjectID(invoice.projectMonth.projectMonthId)}, {$set: {verified: invoice.verified}});
}

const invoiceResponse = {_id, ...invoice};
const result: Array<any> = [{
type: 'invoice',
model: {_id, ...invoice},
model: invoiceResponse,
}];
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.INVOICES, invoiceResponse._id, invoiceResponse);

if (projectMonth && projectMonth.ok && projectMonth.value) {
const projectMonthResponse = projectMonth.value;
result.push({
type: 'projectMonth',
model: projectMonth.value,
model: projectMonthResponse,
});
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.PROJECTS_MONTH, projectMonthResponse._id, projectMonthResponse);
}

return res.send(result);
Expand All @@ -189,7 +199,7 @@ export const updateInvoiceController = async (req: ConfacRequest, res: Response)


/** Hard invoice delete: There is no coming back from this one */
export const deleteInvoiceController = async (req: Request, res: Response) => {
export const deleteInvoiceController = async (req: ConfacRequest, res: Response) => {
const { id: invoiceId }: { id: string; } = req.body;

const invoice = await req.db.collection<IInvoice>(CollectionNames.INVOICES).findOne({ _id: new ObjectID(invoiceId) });
Expand All @@ -213,12 +223,17 @@ export const deleteInvoiceController = async (req: Request, res: Response) => {

const projectMonthCollection = req.db.collection(CollectionNames.PROJECTS_MONTH);
const attachments = invoice.attachments.filter(a => a.type !== 'pdf');
await projectMonthCollection.findOneAndUpdate({ _id: new ObjectID(invoice.projectMonth.projectMonthId) }, { $set: { attachments } });
const projectMonthId = new ObjectID(invoice.projectMonth.projectMonthId);
const updateProjectMonthResult = await projectMonthCollection.findOneAndUpdate({ _id: projectMonthId }, { $set: { attachments } });
const updatedProjectMonth = updateProjectMonthResult.value;
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.PROJECTS_MONTH, updatedProjectMonth!._id, updatedProjectMonth);
}

await req.db.collection(CollectionNames.INVOICES).findOneAndDelete({ _id: new ObjectID(invoiceId) });
await req.db.collection(CollectionNames.ATTACHMENTS).findOneAndDelete({ _id: new ObjectID(invoiceId) });

emitEntityEvent(req, SocketEventTypes.EntityDeleted, CollectionNames.INVOICES, new ObjectID(invoiceId), null);

return res.send(invoiceId);
};

Expand Down
6 changes: 3 additions & 3 deletions backend/src/controllers/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const saveProject = async (req: ConfacRequest, res: Response) => {
const {value: originalProject} = await projectsColl.findOneAndUpdate({_id: new ObjectID(_id)}, {$set: project}, {returnOriginal: true});
await saveAudit(req, 'project', originalProject, project);
const responseProject = {_id, ...project};
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.PROJECTS, _id, responseProject);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityUpdated, entityType: CollectionNames.PROJECTS, entityId: _id, entity: responseProject });
return res.send(responseProject);
}

Expand All @@ -55,14 +55,14 @@ export const saveProject = async (req: ConfacRequest, res: Response) => {
audit: createAudit(req.user),
});
const [createdProject] = inserted.ops;
emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.PROJECTS, createdProject._id, createdProject);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityCreated, entityType: CollectionNames.PROJECTS, entityId: createdProject._id, entity: createdProject });
return res.send(createdProject);
};


export const deleteProject = async (req: ConfacRequest, res: Response) => {
const id = req.body.id;
await req.db.collection(CollectionNames.PROJECTS).findOneAndDelete({_id: new ObjectID(id)});
emitEntityEvent(req, SocketEventTypes.EntityDeleted, CollectionNames.PROJECTS, id, null);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityDeleted, entityType: CollectionNames.PROJECTS, entityId: id, entity: null });
return res.send(id);
};
8 changes: 4 additions & 4 deletions backend/src/controllers/projectsMonth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const createProjectsMonthController = async (req: ConfacRequest, res: Res
return createdProjectMonth;
}));

emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.PROJECTS_MONTH, null, createdProjectsMonth);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityCreated, entityType: CollectionNames.PROJECTS_MONTH, entityId: null, entity: createdProjectsMonth });

return res.send(createdProjectsMonth);
};
Expand All @@ -72,7 +72,7 @@ export const patchProjectsMonthController = async (req: ConfacRequest, res: Resp
const {value: originalProjectMonth} = await projMonthCollection.findOneAndUpdate({_id: new ObjectID(_id)}, {$set: projectMonth}, {returnOriginal: true});
await saveAudit(req, 'projectMonth', originalProjectMonth, projectMonth);
const projectMonthResponse = {_id, ...projectMonth};
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.PROJECTS_MONTH, projectMonthResponse._id, projectMonthResponse);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityUpdated, entityType: CollectionNames.PROJECTS_MONTH, entityId: projectMonthResponse._id, entity: projectMonthResponse });
return res.send(projectMonthResponse);
}

Expand All @@ -81,7 +81,7 @@ export const patchProjectsMonthController = async (req: ConfacRequest, res: Resp
audit: createAudit(req.user),
});
const [createdProjectMonth] = inserted.ops;
emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.PROJECTS_MONTH, createdProjectMonth._id, createdProjectMonth);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityCreated, entityType: CollectionNames.PROJECTS_MONTH, entityId: createdProjectMonth._id, entity: createdProjectMonth });
return res.send(createdProjectMonth);
};

Expand All @@ -91,6 +91,6 @@ export const deleteProjectsMonthController = async (req: ConfacRequest, res: Res
const id = req.body.id;
await req.db.collection(CollectionNames.PROJECTS_MONTH).findOneAndDelete({ _id: new ObjectID(id) });
await req.db.collection(CollectionNames.ATTACHMENTS_PROJECT_MONTH).findOneAndDelete({ _id: new ObjectID(id) });
emitEntityEvent(req, SocketEventTypes.EntityDeleted, CollectionNames.PROJECTS_MONTH, id, null);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityDeleted, entityType: CollectionNames.PROJECTS_MONTH, entityId: id, entity: null });
return res.send(id);
};
8 changes: 4 additions & 4 deletions backend/src/controllers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ export const saveUser = async (req: ConfacRequest, res: Response) => {
const {value: originalUser} = await collection.findOneAndUpdate({_id: new ObjectID(_id)}, {$set: user}, {returnOriginal: true});
await saveAudit(req, 'user', originalUser, user);
const responseUser = {_id, ...user};
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.USERS, _id, responseUser);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityUpdated, entityType: CollectionNames.USERS, entityId: _id, entity: responseUser });
return res.send(responseUser);
}

user.audit = createAudit(req.user);
const inserted = await collection.insertOne(user);
const [createdUser] = inserted.ops;
emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.USERS, createdUser._id, createdUser);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityCreated, entityType: CollectionNames.USERS, entityId: createdUser._id, entity: createdUser });
return res.send(createdUser);
};

Expand Down Expand Up @@ -148,13 +148,13 @@ export const saveRole = async (req: ConfacRequest, res: Response) => {
await saveAudit(req, 'role', originalRole, role);

const responseRole = {_id, ...role};
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.ROLES, _id, responseRole);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityUpdated, entityType: CollectionNames.ROLES, entityId: _id, entity: responseRole });
return res.send(responseRole);
}

role.audit = createAudit(req.user);
const inserted = await collection.insertOne(role);
const [createdRole] = inserted.ops;
emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.ROLES, createdRole._id, createdRole);
emitEntityEvent({ req, eventType: SocketEventTypes.EntityCreated, entityType: CollectionNames.ROLES, entityId: createdRole._id, entity: createdRole });
return res.send(createdRole);
};
2 changes: 1 addition & 1 deletion backend/src/controllers/utils/entity-events.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ObjectID } from 'bson';
import {ObjectID} from 'bson';
import {CollectionNames, SocketEventTypes} from '../../models/common';
import {ConfacRequest} from '../../models/technical';

Expand Down
23 changes: 23 additions & 0 deletions frontend/src/actions/invoiceActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import InvoiceModel from '../components/invoice/models/InvoiceModel';
import {ProjectMonthModel} from '../components/project/models/ProjectMonthModel';
import {authService} from '../components/users/authService';
import { socketService } from '../components/socketio/SocketService';
import { EntityEventPayload } from '../components/socketio/EntityEventPayload';
import { SocketEventTypes } from '../components/socketio/SocketEventTypes';
import { Dispatch } from 'redux';


function cleanViewModel(data: InvoiceModel): InvoiceModel {
Expand Down Expand Up @@ -119,3 +122,23 @@ export function deleteInvoice(invoice: InvoiceModel) {
.then(() => dispatch(busyToggle.off()));
};
}

export function handleInvoiceSocketEvents(eventType: string, eventPayload: EntityEventPayload){
return (dispatch: Dispatch) => {
dispatch(busyToggle());
switch(eventType){
case SocketEventTypes.EntityUpdated:
case SocketEventTypes.EntityCreated:
dispatch({
type: ACTION_TYPES.INVOICE_UPDATED,
invoice: eventPayload.entity}); break;
case SocketEventTypes.EntityDeleted:
dispatch({
type: ACTION_TYPES.INVOICE_DELETED,
id: eventPayload.entityId,
}); break;
default: throw new Error(`${eventType} not supported for project month.`);
}
dispatch(busyToggle.off());
}
}
2 changes: 1 addition & 1 deletion frontend/src/actions/projectActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,5 +291,5 @@ export function handleProjectMonthSocketEvents(eventType: string, eventPayload:
default: throw new Error(`${eventType} not supported for project month.`);
}
dispatch(busyToggle.off());
}
}
}
2 changes: 2 additions & 0 deletions frontend/src/components/invoice/invoice-edit/EditInvoice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {InvoiceDownloadIcon} from '../../controls/attachments/AttachmentDownload


import './EditInvoice.scss';
import useEntityChangedToast from '../../hooks/useEntityChangedToast';


const EditInvoice = () => {
Expand All @@ -45,6 +46,7 @@ const EditInvoice = () => {
const initInvoice = storeInvoice ? new InvoiceModel(config, storeInvoice) : getNewInvoice(config, invoices, clients, {isQuotation});
const fullProjectMonth = useProjectsMonth(storeInvoice?.projectMonth?.projectMonthId);
const [invoice, setInvoice] = useState<InvoiceModel>(initInvoice);
useEntityChangedToast(invoice._id);
const [, forceUpdate] = useReducer(x => x + 1, 0);
const dispatch = useDispatch();
// useEffect(() => window.scrollTo(0, 0)); // TODO: each keystroke made it scroll to top :(
Expand Down
19 changes: 10 additions & 9 deletions frontend/src/components/socketio/SocketService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import { Dispatch } from "redux";
import { io } from "socket.io-client";
import { handleClientSocketEvents, handleConfigSocketEvents, handleConsultantSocketEvents, handleProjectMonthSocketEvents, handleProjectSocketEvents } from "../../actions";
import { handleClientSocketEvents, handleConfigSocketEvents, handleConsultantSocketEvents, handleInvoiceSocketEvents, handleProjectMonthSocketEvents, handleProjectSocketEvents } from "../../actions";
import { SocketEventTypes } from "./SocketEventTypes";
import { EntityEventPayload } from "./EntityEventPayload";
import { t } from "../utils";
Expand Down Expand Up @@ -39,14 +39,15 @@ function createSocketService () {
}

switch(eventPayload.entityType){
case 'projects': dispatch(handleProjectSocketEvents(eventType, eventPayload)); break;
case 'consultants': dispatch(handleConsultantSocketEvents(eventType, eventPayload)); break;
case 'clients': dispatch(handleClientSocketEvents(eventType, eventPayload)); break;
case 'users': dispatch(handleUserSocketEvents(eventType, eventPayload)); break;
case 'roles': dispatch(handleRoleSocketEvents(eventType, eventPayload)); break;
case 'config': dispatch(handleConfigSocketEvents(eventType, eventPayload)); break;
case 'projects_month': dispatch(handleProjectMonthSocketEvents(eventType, eventPayload)); break;
default: throw new Error(`${eventPayload.entityType} event for entity type not supported.`);
case 'clients': dispatch(handleClientSocketEvents(eventType, eventPayload)); break;
case 'config': dispatch(handleConfigSocketEvents(eventType, eventPayload)); break;
case 'consultants': dispatch(handleConsultantSocketEvents(eventType, eventPayload)); break;
case 'invoices': dispatch(handleInvoiceSocketEvents(eventType, eventPayload)); break;
case 'projects': dispatch(handleProjectSocketEvents(eventType, eventPayload)); break;
case 'projects_month': dispatch(handleProjectMonthSocketEvents(eventType, eventPayload)); break;
case 'roles': dispatch(handleRoleSocketEvents(eventType, eventPayload)); break;
case 'users': dispatch(handleUserSocketEvents(eventType, eventPayload)); break;
default: throw new Error(`${eventPayload.entityType} event for entity type not supported.`);
};
});
}
Expand Down
Loading

0 comments on commit 9c5f22b

Please sign in to comment.