mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
Merge branch 'develop' into print-resources
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
|
||||
export class AttachmentTransformer extends Transformer {
|
||||
/**
|
||||
* Exclude attributes.
|
||||
* @returns {string[]}
|
||||
*/
|
||||
public excludeAttributes = (): string[] => {
|
||||
return ['id', 'createdAt'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Includeded attributes.
|
||||
* @returns {string[]}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return [];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { UploadDocument } from './UploadDocument';
|
||||
import { DeleteAttachment } from './DeleteAttachment';
|
||||
import { GetAttachment } from './GetAttachment';
|
||||
import { AttachmentUploadPipeline } from './S3UploadPipeline';
|
||||
import { LinkAttachment } from './LinkAttachment';
|
||||
import { UnlinkAttachment } from './UnlinkAttachment';
|
||||
import { getAttachmentPresignedUrl } from './GetAttachmentPresignedUrl';
|
||||
import type { Multer } from 'multer';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsApplication {
|
||||
@Inject()
|
||||
private uploadDocumentService: UploadDocument;
|
||||
|
||||
@Inject()
|
||||
private deleteDocumentService: DeleteAttachment;
|
||||
|
||||
@Inject()
|
||||
private getDocumentService: GetAttachment;
|
||||
|
||||
@Inject()
|
||||
private uploadPipelineService: AttachmentUploadPipeline;
|
||||
|
||||
@Inject()
|
||||
private linkDocumentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkDocumentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private getPresignedUrlService: getAttachmentPresignedUrl;
|
||||
|
||||
/**
|
||||
* Express middleware for uploading attachments to an S3 bucket.
|
||||
* @returns {Multer}
|
||||
*/
|
||||
get uploadPipeline(): Multer {
|
||||
return this.uploadPipelineService.uploadPipeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the metadata of uploaded document to S3 on database.
|
||||
* @param {number} tenantId
|
||||
* @param {} file
|
||||
* @returns {Promise<Document>}
|
||||
*/
|
||||
public upload(tenantId: number, file: any) {
|
||||
return this.uploadDocumentService.upload(tenantId, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the give file attachment file key.
|
||||
* @param {number} tenantId
|
||||
* @param {string} documentKey
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public delete(tenantId: number, documentKey: string) {
|
||||
return this.deleteDocumentService.delete(tenantId, documentKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the document data.
|
||||
* @param {number} tenantId
|
||||
* @param {string} documentKey
|
||||
*/
|
||||
public get(tenantId: number, documentKey: string) {
|
||||
return this.getDocumentService.getAttachment(tenantId, documentKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Links the given document to resource model.
|
||||
* @param {number} tenantId
|
||||
* @param {string} filekey
|
||||
* @param {string} modelRef
|
||||
* @param {number} modelId
|
||||
* @returns
|
||||
*/
|
||||
public link(
|
||||
tenantId: number,
|
||||
filekey: string,
|
||||
modelRef: string,
|
||||
modelId: number
|
||||
) {
|
||||
return this.linkDocumentService.link(tenantId, filekey, modelRef, modelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlinks the given document from resource model.
|
||||
* @param {number} tenantId
|
||||
* @param {string} filekey
|
||||
* @param {string} modelRef
|
||||
* @param {number} modelId
|
||||
* @returns
|
||||
*/
|
||||
public unlink(
|
||||
tenantId: number,
|
||||
filekey: string,
|
||||
modelRef: string,
|
||||
modelId: number
|
||||
) {
|
||||
return this.unlinkDocumentService.unlink(
|
||||
tenantId,
|
||||
filekey,
|
||||
modelRef,
|
||||
modelId
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the presigned url of the given attachment key.
|
||||
* @param {string} key
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
public getPresignedUrl(key: string): Promise<string> {
|
||||
return this.getPresignedUrlService.getPresignedUrl(key);
|
||||
}
|
||||
}
|
||||
45
packages/server/src/services/Attachments/DeleteAttachment.ts
Normal file
45
packages/server/src/services/Attachments/DeleteAttachment.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { DeleteObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { s3 } from '@/lib/S3/S3';
|
||||
import HasTenancyService from '../Tenancy/TenancyService';
|
||||
import config from '@/config';
|
||||
import UnitOfWork from '../UnitOfWork';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
@Service()
|
||||
export class DeleteAttachment {
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
@Inject()
|
||||
private uow: UnitOfWork;
|
||||
|
||||
/**
|
||||
* Deletes the give file attachment file key.
|
||||
* @param {number} tenantId
|
||||
* @param {string} filekey
|
||||
*/
|
||||
async delete(tenantId: number, filekey: string): Promise<void> {
|
||||
const { Document, DocumentLink } = this.tenancy.models(tenantId);
|
||||
|
||||
const params = {
|
||||
Bucket: config.s3.bucket,
|
||||
Key: filekey,
|
||||
};
|
||||
await s3.send(new DeleteObjectCommand(params));
|
||||
|
||||
const foundDocument = await Document.query()
|
||||
.findOne('key', filekey)
|
||||
.throwIfNotFound();
|
||||
|
||||
await this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||
// Delete all document links
|
||||
await DocumentLink.query(trx)
|
||||
.where('documentId', foundDocument.id)
|
||||
.delete();
|
||||
|
||||
// Delete thedocument.
|
||||
await Document.query(trx).findById(foundDocument.id).delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
22
packages/server/src/services/Attachments/GetAttachment.ts
Normal file
22
packages/server/src/services/Attachments/GetAttachment.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Service } from 'typedi';
|
||||
import { GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { s3 } from '@/lib/S3/S3';
|
||||
import config from '@/config';
|
||||
|
||||
@Service()
|
||||
export class GetAttachment {
|
||||
/**
|
||||
* Retrieves data of the given document key.
|
||||
* @param {number} tenantId
|
||||
* @param {string} filekey
|
||||
*/
|
||||
async getAttachment(tenantId: number, filekey: string) {
|
||||
const params = {
|
||||
Bucket: config.s3.bucket,
|
||||
Key: filekey,
|
||||
};
|
||||
const data = await s3.send(new GetObjectCommand(params));
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Service } from 'typedi';
|
||||
import { GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
import { s3 } from '@/lib/S3/S3';
|
||||
import config from '@/config';
|
||||
|
||||
@Service()
|
||||
export class getAttachmentPresignedUrl {
|
||||
/**
|
||||
* Retrieves the presigned url of the given attachment key.
|
||||
* @param {string} key
|
||||
* @returns {Promise<string?>}
|
||||
*/
|
||||
async getPresignedUrl(key: string) {
|
||||
const command = new GetObjectCommand({
|
||||
Bucket: config.s3.bucket,
|
||||
Key: key,
|
||||
});
|
||||
const signedUrl = await getSignedUrl(s3, command, { expiresIn: 300 });
|
||||
|
||||
return signedUrl;
|
||||
}
|
||||
}
|
||||
82
packages/server/src/services/Attachments/LinkAttachment.ts
Normal file
82
packages/server/src/services/Attachments/LinkAttachment.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import bluebird from 'bluebird';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
validateLinkModelEntryExists,
|
||||
validateLinkModelExists,
|
||||
} from './_utils';
|
||||
import HasTenancyService from '../Tenancy/TenancyService';
|
||||
import { ServiceError } from '@/exceptions';
|
||||
import { ERRORS } from './constants';
|
||||
|
||||
@Service()
|
||||
export class LinkAttachment {
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
/**
|
||||
* Links the given file key to the given model type and id.
|
||||
* @param {number} tenantId
|
||||
* @param {string} filekey
|
||||
* @param {string} modelRef
|
||||
* @param {number} modelId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async link(
|
||||
tenantId: number,
|
||||
filekey: string,
|
||||
modelRef: string,
|
||||
modelId: number,
|
||||
trx?: Knex.Transaction
|
||||
) {
|
||||
const { DocumentLink, Document, ...models } = this.tenancy.models(tenantId);
|
||||
const LinkModel = models[modelRef];
|
||||
validateLinkModelExists(LinkModel);
|
||||
|
||||
const foundFile = await Document.query(trx)
|
||||
.findOne('key', filekey)
|
||||
.throwIfNotFound();
|
||||
|
||||
const foundLinkModel = await LinkModel.query(trx).findById(modelId);
|
||||
validateLinkModelEntryExists(foundLinkModel);
|
||||
|
||||
const foundLinks = await DocumentLink.query(trx)
|
||||
.where('modelRef', modelRef)
|
||||
.where('modelId', modelId)
|
||||
.where('documentId', foundFile.id);
|
||||
|
||||
if (foundLinks.length > 0) {
|
||||
throw new ServiceError(ERRORS.DOCUMENT_LINK_ALREADY_LINKED);
|
||||
}
|
||||
await DocumentLink.query(trx).insert({
|
||||
modelRef,
|
||||
modelId,
|
||||
documentId: foundFile.id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Links the given file keys to the given model type and id.
|
||||
* @param {number} tenantId
|
||||
* @param {string[]} filekeys
|
||||
* @param {string} modelRef
|
||||
* @param {number} modelId
|
||||
* @param {Knex.Transaction} trx
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async bulkLink(
|
||||
tenantId: number,
|
||||
filekeys: string[],
|
||||
modelRef: string,
|
||||
modelId: number,
|
||||
trx?: Knex.Transaction
|
||||
) {
|
||||
return bluebird.each(filekeys, async (fieldKey: string) => {
|
||||
try {
|
||||
await this.link(tenantId, fieldKey, modelRef, modelId, trx);
|
||||
} catch {
|
||||
// Ignore catching exceptions in bulk action.
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
29
packages/server/src/services/Attachments/S3UploadPipeline.ts
Normal file
29
packages/server/src/services/Attachments/S3UploadPipeline.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import multer from 'multer';
|
||||
import type { Multer } from 'multer'
|
||||
import multerS3 from 'multer-s3';
|
||||
import { s3 } from '@/lib/S3/S3';
|
||||
import { Service } from 'typedi';
|
||||
import config from '@/config';
|
||||
|
||||
@Service()
|
||||
export class AttachmentUploadPipeline {
|
||||
/**
|
||||
* Express middleware for uploading attachments to an S3 bucket.
|
||||
* It utilizes the multer middleware for handling multipart/form-data, specifically for file uploads.
|
||||
*/
|
||||
public uploadPipeline(): Multer {
|
||||
return multer({
|
||||
storage: multerS3({
|
||||
s3,
|
||||
bucket: config.s3.bucket,
|
||||
contentType: multerS3.AUTO_CONTENT_TYPE,
|
||||
metadata: function (req, file, cb) {
|
||||
cb(null, { fieldName: file.fieldname });
|
||||
},
|
||||
key: function (req, file, cb) {
|
||||
cb(null, Date.now().toString());
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
125
packages/server/src/services/Attachments/UnlinkAttachment.ts
Normal file
125
packages/server/src/services/Attachments/UnlinkAttachment.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import bluebird from 'bluebird';
|
||||
import HasTenancyService from '../Tenancy/TenancyService';
|
||||
import {
|
||||
validateLinkModelEntryExists,
|
||||
validateLinkModelExists,
|
||||
} from './_utils';
|
||||
import { Knex } from 'knex';
|
||||
import { difference } from 'lodash';
|
||||
|
||||
@Service()
|
||||
export class UnlinkAttachment {
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
/**
|
||||
* Unlink the attachments from the model entry.
|
||||
* @param {number} tenantId
|
||||
* @param {string} filekey
|
||||
* @param {string} modelRef
|
||||
* @param {number} modelId
|
||||
*/
|
||||
async unlink(
|
||||
tenantId: number,
|
||||
filekey: string,
|
||||
modelRef: string,
|
||||
modelId: number,
|
||||
trx?: Knex.Transaction
|
||||
): Promise<void> {
|
||||
const { DocumentLink, Document, ...models } = this.tenancy.models(tenantId);
|
||||
const LinkModel = models[modelRef];
|
||||
validateLinkModelExists(LinkModel);
|
||||
|
||||
const foundLinkModel = await LinkModel.query(trx).findById(modelId);
|
||||
validateLinkModelEntryExists(foundLinkModel);
|
||||
|
||||
const document = await Document.query(trx).findOne('key', filekey);
|
||||
|
||||
// Delete the document link.
|
||||
await DocumentLink.query(trx)
|
||||
.where('modelRef', modelRef)
|
||||
.where('modelId', modelId)
|
||||
.where('documentId', document.id)
|
||||
.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk unlink the attachments from the model entry.
|
||||
* @param {number} tenantId
|
||||
* @param {string} fieldkey
|
||||
* @param {string} modelRef
|
||||
* @param {number} modelId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async bulkUnlink(
|
||||
tenantId: number,
|
||||
filekeys: string[],
|
||||
modelRef: string,
|
||||
modelId: number,
|
||||
trx?: Knex.Transaction
|
||||
): Promise<void> {
|
||||
await bluebird.each(filekeys, (fieldKey: string) => {
|
||||
try {
|
||||
this.unlink(tenantId, fieldKey, modelRef, modelId, trx);
|
||||
} catch {
|
||||
// Ignore catching exceptions on bulk action.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all the unpresented keys of the given model type and id.
|
||||
* @param {number} tenantId
|
||||
* @param {string[]} presentedKeys
|
||||
* @param {string} modelRef
|
||||
* @param {number} modelId
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
async unlinkUnpresentedKeys(
|
||||
tenantId: number,
|
||||
presentedKeys: string[],
|
||||
modelRef: string,
|
||||
modelId: number,
|
||||
trx?: Knex.Transaction
|
||||
): Promise<void> {
|
||||
const { DocumentLink } = this.tenancy.models(tenantId);
|
||||
|
||||
const modelLinks = await DocumentLink.query(trx)
|
||||
.where('modelRef', modelRef)
|
||||
.where('modelId', modelId)
|
||||
.withGraphFetched('document');
|
||||
|
||||
const modelLinkKeys = modelLinks.map((link) => link.document.key);
|
||||
const unpresentedKeys = difference(modelLinkKeys, presentedKeys);
|
||||
|
||||
await this.bulkUnlink(tenantId, unpresentedKeys, modelRef, modelId, trx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments of the given model type and id.
|
||||
* @param {number} tenantId
|
||||
* @param {string} modelRef
|
||||
* @param {number} modelId
|
||||
* @param {Knex.Transaction} trx
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async unlinkAllModelKeys(
|
||||
tenantId: number,
|
||||
modelRef: string,
|
||||
modelId: number,
|
||||
trx?: Knex.Transaction
|
||||
): Promise<void> {
|
||||
const { DocumentLink } = this.tenancy.models(tenantId);
|
||||
|
||||
// Get all the keys of the modelRef and modelId.
|
||||
const modelLinks = await DocumentLink.query(trx)
|
||||
.where('modelRef', modelRef)
|
||||
.where('modelId', modelId)
|
||||
.withGraphFetched('document');
|
||||
|
||||
const modelLinkKeys = modelLinks.map((link) => link.document.key);
|
||||
|
||||
await this.bulkUnlink(tenantId, modelLinkKeys, modelRef, modelId, trx);
|
||||
}
|
||||
}
|
||||
26
packages/server/src/services/Attachments/UploadDocument.ts
Normal file
26
packages/server/src/services/Attachments/UploadDocument.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import HasTenancyService from '../Tenancy/TenancyService';
|
||||
|
||||
@Service()
|
||||
export class UploadDocument {
|
||||
@Inject()
|
||||
private tenancy: HasTenancyService;
|
||||
|
||||
/**
|
||||
* Inserts the document metadata.
|
||||
* @param {number} tenantId
|
||||
* @param {} file
|
||||
* @returns {}
|
||||
*/
|
||||
async upload(tenantId: number, file: any) {
|
||||
const { Document } = this.tenancy.models(tenantId);
|
||||
|
||||
const insertedDocument = await Document.query().insert({
|
||||
key: file.key,
|
||||
mimeType: file.mimetype,
|
||||
size: file.size,
|
||||
originName: file.originalname,
|
||||
});
|
||||
return insertedDocument;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { castArray, difference } from 'lodash';
|
||||
import HasTenancyService from '../Tenancy/TenancyService';
|
||||
import { ServiceError } from '@/exceptions';
|
||||
import { Inject, Service } from 'typedi';
|
||||
|
||||
@Service()
|
||||
export class ValidateAttachments {
|
||||
@Inject()
|
||||
tenancy: HasTenancyService;
|
||||
|
||||
/**
|
||||
* Validates the given file keys existance.
|
||||
* @param {number} tenantId
|
||||
* @param {string|string[]} key
|
||||
*/
|
||||
async validate(tenantId: number, key: string | string[]) {
|
||||
const { Document } = this.tenancy.models(tenantId);
|
||||
|
||||
const keys = castArray(key);
|
||||
const documents = await Document.query().whereIn('key', key);
|
||||
const documentKeys = documents.map((document) => document.key);
|
||||
|
||||
const notFoundKeys = difference(keys, documentKeys);
|
||||
|
||||
if (notFoundKeys.length > 0) {
|
||||
throw new ServiceError('DOCUMENT_KEYS_INVALID');
|
||||
}
|
||||
}
|
||||
}
|
||||
14
packages/server/src/services/Attachments/_utils.ts
Normal file
14
packages/server/src/services/Attachments/_utils.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ServiceError } from '@/exceptions';
|
||||
import { ERRORS } from './constants';
|
||||
|
||||
export const validateLinkModelExists = (LinkModel) => {
|
||||
if (!LinkModel) {
|
||||
throw new ServiceError(ERRORS.DOCUMENT_LINK_REF_INVALID);
|
||||
}
|
||||
};
|
||||
|
||||
export const validateLinkModelEntryExists = (foundLinkModel) => {
|
||||
if (!foundLinkModel) {
|
||||
throw new ServiceError(ERRORS.DOCUMENT_LINK_ID_INVALID);
|
||||
}
|
||||
};
|
||||
5
packages/server/src/services/Attachments/constants.ts
Normal file
5
packages/server/src/services/Attachments/constants.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export enum ERRORS {
|
||||
DOCUMENT_LINK_REF_INVALID = 'DOCUMENT_LINK_REF_INVALID',
|
||||
DOCUMENT_LINK_ID_INVALID = 'DOCUMENT_LINK_ID_INVALID',
|
||||
DOCUMENT_LINK_ALREADY_LINKED = 'DOCUMENT_LINK_ALREADY_LINKED'
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
IBIllEventDeletedPayload,
|
||||
IBillCreatedPayload,
|
||||
IBillCreatingPayload,
|
||||
IBillEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnBills {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.bill.onCreating,
|
||||
this.validateAttachmentsOnBillCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.bill.onCreated,
|
||||
this.handleAttachmentsOnBillCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.bill.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnBillEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.bill.onEdited,
|
||||
this.handleLinkPresentedKeysOnBillEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.bill.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnBillDeleted.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating bill.
|
||||
* @param {ISaleInvoiceCreatingPaylaod}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnBillCreate({
|
||||
billDTO,
|
||||
tenantId,
|
||||
}: IBillCreatingPayload): Promise<void> {
|
||||
if (isEmpty(billDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = billDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created bill.
|
||||
* @param {ISaleInvoiceCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnBillCreated({
|
||||
tenantId,
|
||||
bill,
|
||||
billDTO,
|
||||
trx,
|
||||
}: IBillCreatedPayload): Promise<void> {
|
||||
if (isEmpty(billDTO.attachments)) return;
|
||||
|
||||
const keys = billDTO.attachments?.map((attachment) => attachment.key);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'Bill',
|
||||
bill.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited bill.
|
||||
* @param {IBillEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnBillEdited({
|
||||
tenantId,
|
||||
billDTO,
|
||||
bill,
|
||||
trx
|
||||
}: IBillEditedPayload) {
|
||||
const keys = billDTO.attachments?.map((attachment) => attachment.key);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'Bill',
|
||||
bill.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited bill.
|
||||
* @param {ISaleInvoiceEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnBillEdited({
|
||||
tenantId,
|
||||
billDTO,
|
||||
oldBill,
|
||||
trx,
|
||||
}: IBillEditedPayload) {
|
||||
if (isEmpty(billDTO.attachments)) return;
|
||||
|
||||
const keys = billDTO.attachments?.map((attachment) => attachment.key);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'Bill',
|
||||
oldBill.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the bill deleted.
|
||||
* @param {ISaleInvoiceDeletedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnBillDeleted({
|
||||
tenantId,
|
||||
oldBill,
|
||||
trx,
|
||||
}: IBIllEventDeletedPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'Bill',
|
||||
oldBill.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
ICreditNoteCreatedPayload,
|
||||
ICreditNoteCreatingPayload,
|
||||
ICreditNoteDeletingPayload,
|
||||
ICreditNoteEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnCreditNote {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.creditNote.onCreating,
|
||||
this.validateAttachmentsOnCreditNoteCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.creditNote.onCreated,
|
||||
this.handleAttachmentsOnCreditNoteCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.creditNote.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnCreditNoteEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.creditNote.onEdited,
|
||||
this.handleLinkPresentedKeysOnCreditNoteEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.creditNote.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnCreditNoteDeleted.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating credit note.
|
||||
* @param {ICreditNoteCreatingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnCreditNoteCreate({
|
||||
creditNoteDTO,
|
||||
tenantId,
|
||||
}: ICreditNoteCreatingPayload): Promise<void> {
|
||||
if (isEmpty(creditNoteDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = creditNoteDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created credit note.
|
||||
* @param {ICreditNoteCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnCreditNoteCreated({
|
||||
tenantId,
|
||||
creditNote,
|
||||
creditNoteDTO,
|
||||
trx,
|
||||
}: ICreditNoteCreatedPayload): Promise<void> {
|
||||
if (isEmpty(creditNoteDTO.attachments)) return;
|
||||
|
||||
const keys = creditNoteDTO.attachments?.map((attachment) => attachment.key);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'CreditNote',
|
||||
creditNote.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited credit note.
|
||||
* @param {ICreditNoteEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnCreditNoteEdited({
|
||||
tenantId,
|
||||
creditNoteEditDTO,
|
||||
oldCreditNote,
|
||||
trx,
|
||||
}: ICreditNoteEditedPayload) {
|
||||
const keys = creditNoteEditDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'CreditNote',
|
||||
oldCreditNote.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited credit note.
|
||||
* @param {ICreditNoteEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnCreditNoteEdited({
|
||||
tenantId,
|
||||
creditNoteEditDTO,
|
||||
oldCreditNote,
|
||||
trx,
|
||||
}: ICreditNoteEditedPayload) {
|
||||
if (isEmpty(creditNoteEditDTO.attachments)) return;
|
||||
|
||||
const keys = creditNoteEditDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'CreditNote',
|
||||
oldCreditNote.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the credit note deleted.
|
||||
* @param {ICreditNoteDeletingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnCreditNoteDeleted({
|
||||
tenantId,
|
||||
oldCreditNote,
|
||||
trx,
|
||||
}: ICreditNoteDeletingPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'CreditNote',
|
||||
oldCreditNote.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
IExpenseCreatedPayload,
|
||||
IExpenseCreatingPayload,
|
||||
IExpenseDeletingPayload,
|
||||
IExpenseEventEditPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnExpenses {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.expenses.onCreating,
|
||||
this.validateAttachmentsOnExpenseCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.expenses.onCreated,
|
||||
this.handleAttachmentsOnExpenseCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.expenses.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnExpenseEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.expenses.onEdited,
|
||||
this.handleLinkPresentedKeysOnExpenseEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.expenses.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnExpenseDeleted.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating expense.
|
||||
* @param {ISaleInvoiceCreatingPaylaod}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnExpenseCreate({
|
||||
expenseDTO,
|
||||
tenantId,
|
||||
}: IExpenseCreatingPayload): Promise<void> {
|
||||
if (isEmpty(expenseDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = expenseDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created expense.
|
||||
* @param {ISaleInvoiceCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnExpenseCreated({
|
||||
tenantId,
|
||||
expenseDTO,
|
||||
expense,
|
||||
trx,
|
||||
}: IExpenseCreatedPayload): Promise<void> {
|
||||
if (isEmpty(expenseDTO.attachments)) return;
|
||||
|
||||
const keys = expenseDTO.attachments?.map((attachment) => attachment.key);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'Expense',
|
||||
expense.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited expense.
|
||||
* @param {ISaleInvoiceEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnExpenseEdited({
|
||||
tenantId,
|
||||
expenseDTO,
|
||||
expense,
|
||||
trx,
|
||||
}: IExpenseEventEditPayload) {
|
||||
const keys = expenseDTO.attachments?.map((attachment) => attachment.key);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'Expense',
|
||||
expense.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited expense.
|
||||
* @param {ISaleInvoiceEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnExpenseEdited({
|
||||
tenantId,
|
||||
expenseDTO,
|
||||
oldExpense,
|
||||
trx,
|
||||
}: IExpenseEventEditPayload) {
|
||||
if (isEmpty(expenseDTO.attachments)) return;
|
||||
|
||||
const keys = expenseDTO.attachments?.map((attachment) => attachment.key);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'Expense',
|
||||
oldExpense.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the expense deleted.
|
||||
* @param {ISaleInvoiceDeletedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnExpenseDeleted({
|
||||
tenantId,
|
||||
oldExpense,
|
||||
trx,
|
||||
}: IExpenseDeletingPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'Expense',
|
||||
oldExpense.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
IManualJournalCreatingPayload,
|
||||
IManualJournalEventCreatedPayload,
|
||||
IManualJournalEventDeletedPayload,
|
||||
IManualJournalEventEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnManualJournals {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.manualJournals.onCreating,
|
||||
this.validateAttachmentsOnManualJournalCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.manualJournals.onCreated,
|
||||
this.handleAttachmentsOnManualJournalCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.manualJournals.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnManualJournalEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.manualJournals.onEdited,
|
||||
this.handleLinkPresentedKeysOnManualJournalEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.manualJournals.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnManualJournalDeleted.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating manual journal.
|
||||
* @param {IManualJournalCreatingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnManualJournalCreate({
|
||||
manualJournalDTO,
|
||||
tenantId,
|
||||
}: IManualJournalCreatingPayload): Promise<void> {
|
||||
if (isEmpty(manualJournalDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = manualJournalDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created manual journal.
|
||||
* @param {IManualJournalEventCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnManualJournalCreated({
|
||||
tenantId,
|
||||
manualJournalDTO,
|
||||
manualJournal,
|
||||
trx,
|
||||
}: IManualJournalEventCreatedPayload): Promise<void> {
|
||||
if (isEmpty(manualJournalDTO.attachments)) return;
|
||||
|
||||
const keys = manualJournalDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'ManualJournal',
|
||||
manualJournal.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited manual journal.
|
||||
* @param {ISaleInvoiceEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnManualJournalEdited({
|
||||
tenantId,
|
||||
manualJournalDTO,
|
||||
manualJournal,
|
||||
trx
|
||||
}: IManualJournalEventEditedPayload) {
|
||||
const keys = manualJournalDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleInvoice',
|
||||
manualJournal.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited manual journal.
|
||||
* @param {ISaleInvoiceEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnManualJournalEdited({
|
||||
tenantId,
|
||||
manualJournalDTO,
|
||||
oldManualJournal,
|
||||
trx,
|
||||
}: IManualJournalEventEditedPayload) {
|
||||
if (isEmpty(manualJournalDTO.attachments)) return;
|
||||
|
||||
const keys = manualJournalDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'ManualJournal',
|
||||
oldManualJournal.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the manual journal deleted.
|
||||
* @param {ISaleInvoiceDeletedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnManualJournalDeleted({
|
||||
tenantId,
|
||||
oldManualJournal,
|
||||
trx,
|
||||
}: IManualJournalEventDeletedPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'SaleInvoice',
|
||||
oldManualJournal.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
IBillPaymentCreatingPayload,
|
||||
IBillPaymentDeletingPayload,
|
||||
IBillPaymentEventCreatedPayload,
|
||||
IBillPaymentEventEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnBillPayments {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.billPayment.onCreating,
|
||||
this.validateAttachmentsOnBillPaymentCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.billPayment.onCreated,
|
||||
this.handleAttachmentsOnBillPaymentCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.billPayment.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnBillPaymentEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.billPayment.onEdited,
|
||||
this.handleLinkPresentedKeysOnBillPaymentEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.billPayment.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnBillPaymentDeleted.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating bill payment.
|
||||
* @param {IBillPaymentCreatingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnBillPaymentCreate({
|
||||
billPaymentDTO,
|
||||
tenantId,
|
||||
}: IBillPaymentCreatingPayload): Promise<void> {
|
||||
if (isEmpty(billPaymentDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = billPaymentDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created bill payment.
|
||||
* @param {IBillPaymentEventCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnBillPaymentCreated({
|
||||
tenantId,
|
||||
billPaymentDTO,
|
||||
billPayment,
|
||||
trx,
|
||||
}: IBillPaymentEventCreatedPayload): Promise<void> {
|
||||
if (isEmpty(billPaymentDTO.attachments)) return;
|
||||
|
||||
const keys = billPaymentDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'BillPayment',
|
||||
billPayment.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited bill payment.
|
||||
* @param {IBillPaymentEventEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnBillPaymentEdited({
|
||||
tenantId,
|
||||
billPaymentDTO,
|
||||
oldBillPayment,
|
||||
trx,
|
||||
}: IBillPaymentEventEditedPayload) {
|
||||
const keys = billPaymentDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'BillPayment',
|
||||
oldBillPayment.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited bill payment.
|
||||
* @param {IBillPaymentEventEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnBillPaymentEdited({
|
||||
tenantId,
|
||||
billPaymentDTO,
|
||||
oldBillPayment,
|
||||
trx,
|
||||
}: IBillPaymentEventEditedPayload) {
|
||||
if (isEmpty(billPaymentDTO.attachments)) return;
|
||||
|
||||
const keys = billPaymentDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'BillPayment',
|
||||
oldBillPayment.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the bill payment deleted.
|
||||
* @param {IBillPaymentDeletingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnBillPaymentDeleted({
|
||||
tenantId,
|
||||
oldBillPayment,
|
||||
trx,
|
||||
}: IBillPaymentDeletingPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'BillPayment',
|
||||
oldBillPayment.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
IPaymentReceiveCreatedPayload,
|
||||
IPaymentReceiveCreatingPayload,
|
||||
IPaymentReceiveDeletingPayload,
|
||||
IPaymentReceiveEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnPaymentsReceived {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.paymentReceive.onCreating,
|
||||
this.validateAttachmentsOnPaymentCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.paymentReceive.onCreated,
|
||||
this.handleAttachmentsOnPaymentCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.paymentReceive.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnPaymentEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.paymentReceive.onEdited,
|
||||
this.handleLinkPresentedKeysOnPaymentEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.paymentReceive.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnPaymentDelete.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating payment.
|
||||
* @param {IPaymentReceiveCreatingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnPaymentCreate({
|
||||
paymentReceiveDTO,
|
||||
tenantId,
|
||||
}: IPaymentReceiveCreatingPayload): Promise<void> {
|
||||
if (isEmpty(paymentReceiveDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = paymentReceiveDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created payment.
|
||||
* @param {IPaymentReceiveCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnPaymentCreated({
|
||||
tenantId,
|
||||
paymentReceiveDTO,
|
||||
paymentReceive,
|
||||
trx,
|
||||
}: IPaymentReceiveCreatedPayload): Promise<void> {
|
||||
if (isEmpty(paymentReceiveDTO.attachments)) return;
|
||||
|
||||
const keys = paymentReceiveDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'PaymentReceive',
|
||||
paymentReceive.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited payment.
|
||||
* @param {IPaymentReceiveEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnPaymentEdited({
|
||||
tenantId,
|
||||
paymentReceiveDTO,
|
||||
oldPaymentReceive,
|
||||
trx,
|
||||
}: IPaymentReceiveEditedPayload) {
|
||||
const keys = paymentReceiveDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'PaymentReceive',
|
||||
oldPaymentReceive.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited payment.
|
||||
* @param {IPaymentReceiveEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnPaymentEdited({
|
||||
tenantId,
|
||||
paymentReceiveDTO,
|
||||
oldPaymentReceive,
|
||||
trx,
|
||||
}: IPaymentReceiveEditedPayload) {
|
||||
if (isEmpty(paymentReceiveDTO.attachments)) return;
|
||||
|
||||
const keys = paymentReceiveDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'PaymentReceive',
|
||||
oldPaymentReceive.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the payment deleted.
|
||||
* @param {ISaleInvoiceDeletedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnPaymentDelete({
|
||||
tenantId,
|
||||
oldPaymentReceive,
|
||||
trx,
|
||||
}: IPaymentReceiveDeletingPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'PaymentReceive',
|
||||
oldPaymentReceive.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
ISaleEstimateCreatedPayload,
|
||||
ISaleEstimateCreatingPayload,
|
||||
ISaleEstimateDeletingPayload,
|
||||
ISaleEstimateEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnSaleEstimates {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.saleEstimate.onCreating,
|
||||
this.validateAttachmentsOnSaleEstimateCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleEstimate.onCreated,
|
||||
this.handleAttachmentsOnSaleEstimateCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleEstimate.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnSaleEstimateEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleEstimate.onEdited,
|
||||
this.handleLinkPresentedKeysOnSaleEstimateEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleEstimate.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnSaleEstimateDelete.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating sale estimate.
|
||||
* @param {ISaleEstimateCreatingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnSaleEstimateCreated({
|
||||
estimateDTO,
|
||||
tenantId,
|
||||
}: ISaleEstimateCreatingPayload): Promise<void> {
|
||||
if (isEmpty(estimateDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = estimateDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created sale estimate.
|
||||
* @param {ISaleEstimateCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnSaleEstimateCreated({
|
||||
tenantId,
|
||||
saleEstimateDTO,
|
||||
saleEstimate,
|
||||
trx,
|
||||
}: ISaleEstimateCreatedPayload): Promise<void> {
|
||||
if (isEmpty(saleEstimateDTO.attachments)) return;
|
||||
|
||||
const keys = saleEstimateDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleEstimate',
|
||||
saleEstimate.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited sale estimate.
|
||||
* @param {ISaleEstimateEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnSaleEstimateEdited({
|
||||
tenantId,
|
||||
estimateDTO,
|
||||
oldSaleEstimate,
|
||||
trx
|
||||
}: ISaleEstimateEditedPayload) {
|
||||
const keys = estimateDTO.attachments?.map((attachment) => attachment.key);
|
||||
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleEstimate',
|
||||
oldSaleEstimate.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited sale estimate.
|
||||
* @param {ISaleEstimateEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnSaleEstimateEdited({
|
||||
tenantId,
|
||||
estimateDTO,
|
||||
oldSaleEstimate,
|
||||
trx,
|
||||
}: ISaleEstimateEditedPayload) {
|
||||
if (isEmpty(estimateDTO.attachments)) return;
|
||||
|
||||
const keys = estimateDTO.attachments?.map((attachment) => attachment.key);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleEstimate',
|
||||
oldSaleEstimate.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the estimate deleted.
|
||||
* @param {ISaleEstimateDeletingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnSaleEstimateDelete({
|
||||
tenantId,
|
||||
oldSaleEstimate,
|
||||
trx,
|
||||
}: ISaleEstimateDeletingPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'SaleEstimate',
|
||||
oldSaleEstimate.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
ISaleInvoiceCreatedPayload,
|
||||
ISaleInvoiceCreatingPaylaod,
|
||||
ISaleInvoiceDeletePayload,
|
||||
ISaleInvoiceEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnSaleInvoiceCreated {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.saleInvoice.onCreating,
|
||||
this.validateAttachmentsOnSaleInvoiceCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleInvoice.onCreated,
|
||||
this.handleAttachmentsOnSaleInvoiceCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleInvoice.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnInvoiceEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleInvoice.onEdited,
|
||||
this.handleLinkPresentedKeysOnInvoiceEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleInvoice.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnInvoiceDeleted.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating sale invoice.
|
||||
* @param {ISaleInvoiceCreatingPaylaod}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnSaleInvoiceCreate({
|
||||
saleInvoiceDTO,
|
||||
tenantId,
|
||||
}: ISaleInvoiceCreatingPaylaod): Promise<void> {
|
||||
if (isEmpty(saleInvoiceDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = saleInvoiceDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created sale invoice.
|
||||
* @param {ISaleInvoiceCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnSaleInvoiceCreated({
|
||||
tenantId,
|
||||
saleInvoiceDTO,
|
||||
saleInvoice,
|
||||
trx,
|
||||
}: ISaleInvoiceCreatedPayload): Promise<void> {
|
||||
if (isEmpty(saleInvoiceDTO.attachments)) return;
|
||||
|
||||
const keys = saleInvoiceDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleInvoice',
|
||||
saleInvoice.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited sale invoice.
|
||||
* @param {ISaleInvoiceEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnInvoiceEdited({
|
||||
tenantId,
|
||||
saleInvoiceDTO,
|
||||
saleInvoice,
|
||||
trx,
|
||||
}: ISaleInvoiceEditedPayload) {
|
||||
// if (isEmpty(saleInvoiceDTO.attachments)) return;
|
||||
|
||||
const keys = saleInvoiceDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleInvoice',
|
||||
saleInvoice.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited sale invoice.
|
||||
* @param {ISaleInvoiceEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnInvoiceEdited({
|
||||
tenantId,
|
||||
saleInvoiceDTO,
|
||||
oldSaleInvoice,
|
||||
trx,
|
||||
}: ISaleInvoiceEditedPayload) {
|
||||
if (isEmpty(saleInvoiceDTO.attachments)) return;
|
||||
|
||||
const keys = saleInvoiceDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleInvoice',
|
||||
oldSaleInvoice.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the invoice deleted.
|
||||
* @param {ISaleInvoiceDeletedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnInvoiceDeleted({
|
||||
tenantId,
|
||||
saleInvoice,
|
||||
trx,
|
||||
}: ISaleInvoiceDeletePayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'SaleInvoice',
|
||||
saleInvoice.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
ISaleReceiptCreatedPayload,
|
||||
ISaleReceiptCreatingPayload,
|
||||
ISaleReceiptDeletingPayload,
|
||||
ISaleReceiptEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnSaleReceipt {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.saleReceipt.onCreating,
|
||||
this.validateAttachmentsOnSaleInvoiceCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleReceipt.onCreated,
|
||||
this.handleAttachmentsOnSaleInvoiceCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleReceipt.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnInvoiceEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleReceipt.onEdited,
|
||||
this.handleLinkPresentedKeysOnInvoiceEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleReceipt.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnReceiptDeleted.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating sale receipt.
|
||||
* @param {ISaleReceiptCreatingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnSaleInvoiceCreate({
|
||||
saleReceiptDTO,
|
||||
tenantId,
|
||||
}: ISaleReceiptCreatingPayload): Promise<void> {
|
||||
if (isEmpty(saleReceiptDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = saleReceiptDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created sale receipt.
|
||||
* @param {ISaleReceiptCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnSaleInvoiceCreated({
|
||||
tenantId,
|
||||
saleReceiptDTO,
|
||||
saleReceipt,
|
||||
trx,
|
||||
}: ISaleReceiptCreatedPayload): Promise<void> {
|
||||
if (isEmpty(saleReceiptDTO.attachments)) return;
|
||||
|
||||
const keys = saleReceiptDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleReceipt',
|
||||
saleReceipt.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited sale receipt.
|
||||
* @param {ISaleReceiptEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnInvoiceEdited({
|
||||
tenantId,
|
||||
saleReceiptDTO,
|
||||
saleReceipt,
|
||||
trx,
|
||||
}: ISaleReceiptEditedPayload) {
|
||||
const keys = saleReceiptDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleReceipt',
|
||||
saleReceipt.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited sale receipt.
|
||||
* @param {ISaleReceiptEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnInvoiceEdited({
|
||||
tenantId,
|
||||
saleReceiptDTO,
|
||||
oldSaleReceipt,
|
||||
trx,
|
||||
}: ISaleReceiptEditedPayload) {
|
||||
if (isEmpty(saleReceiptDTO.attachments)) return;
|
||||
|
||||
const keys = saleReceiptDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'SaleReceipt',
|
||||
oldSaleReceipt.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the receipt deleted.
|
||||
* @param {ISaleReceiptDeletingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnReceiptDeleted({
|
||||
tenantId,
|
||||
oldSaleReceipt,
|
||||
trx,
|
||||
}: ISaleReceiptDeletingPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'SaleReceipt',
|
||||
oldSaleReceipt.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { isEmpty } from 'lodash';
|
||||
import {
|
||||
IVendorCreditCreatedPayload,
|
||||
IVendorCreditCreatingPayload,
|
||||
IVendorCreditDeletingPayload,
|
||||
IVendorCreditEditedPayload,
|
||||
} from '@/interfaces';
|
||||
import events from '@/subscribers/events';
|
||||
import { LinkAttachment } from '../LinkAttachment';
|
||||
import { ValidateAttachments } from '../ValidateAttachments';
|
||||
import { UnlinkAttachment } from '../UnlinkAttachment';
|
||||
|
||||
@Service()
|
||||
export class AttachmentsOnVendorCredits {
|
||||
@Inject()
|
||||
private linkAttachmentService: LinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private unlinkAttachmentService: UnlinkAttachment;
|
||||
|
||||
@Inject()
|
||||
private validateDocuments: ValidateAttachments;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public attach(bus) {
|
||||
bus.subscribe(
|
||||
events.vendorCredit.onCreating,
|
||||
this.validateAttachmentsOnVendorCreditCreate.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.vendorCredit.onCreated,
|
||||
this.handleAttachmentsOnVendorCreditCreated.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.vendorCredit.onEdited,
|
||||
this.handleUnlinkUnpresentedKeysOnVendorCreditEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.vendorCredit.onEdited,
|
||||
this.handleLinkPresentedKeysOnVendorCreditEdited.bind(this)
|
||||
);
|
||||
bus.subscribe(
|
||||
events.vendorCredit.onDeleting,
|
||||
this.handleUnlinkAttachmentsOnVendorCreditDeleted.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the attachment keys on creating vendor credit.
|
||||
* @param {IVendorCreditCreatingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateAttachmentsOnVendorCreditCreate({
|
||||
vendorCreditCreateDTO,
|
||||
tenantId,
|
||||
}: IVendorCreditCreatingPayload): Promise<void> {
|
||||
if (isEmpty(vendorCreditCreateDTO.attachments)) {
|
||||
return;
|
||||
}
|
||||
const documentKeys = vendorCreditCreateDTO?.attachments?.map((a) => a.key);
|
||||
|
||||
await this.validateDocuments.validate(tenantId, documentKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking the attachments of the created vendor credit.
|
||||
* @param {IVendorCreditCreatedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleAttachmentsOnVendorCreditCreated({
|
||||
tenantId,
|
||||
vendorCreditCreateDTO,
|
||||
vendorCredit,
|
||||
trx,
|
||||
}: IVendorCreditCreatedPayload): Promise<void> {
|
||||
if (isEmpty(vendorCreditCreateDTO.attachments)) return;
|
||||
|
||||
const keys = vendorCreditCreateDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'VendorCredit',
|
||||
vendorCredit.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unlinking all the unpresented keys of the edited vendor credit.
|
||||
* @param {IVendorCreditEditedPayload}
|
||||
*/
|
||||
private async handleUnlinkUnpresentedKeysOnVendorCreditEdited({
|
||||
tenantId,
|
||||
vendorCreditDTO,
|
||||
oldVendorCredit,
|
||||
trx,
|
||||
}: IVendorCreditEditedPayload) {
|
||||
const keys = vendorCreditDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.unlinkAttachmentService.unlinkUnpresentedKeys(
|
||||
tenantId,
|
||||
keys,
|
||||
'VendorCredit',
|
||||
oldVendorCredit.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles linking all the presented keys of the edited vendor credit.
|
||||
* @param {IVendorCreditEditedPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleLinkPresentedKeysOnVendorCreditEdited({
|
||||
tenantId,
|
||||
vendorCreditDTO,
|
||||
oldVendorCredit,
|
||||
trx,
|
||||
}: IVendorCreditEditedPayload) {
|
||||
if (isEmpty(vendorCreditDTO.attachments)) return;
|
||||
|
||||
const keys = vendorCreditDTO.attachments?.map(
|
||||
(attachment) => attachment.key
|
||||
);
|
||||
await this.linkAttachmentService.bulkLink(
|
||||
tenantId,
|
||||
keys,
|
||||
'VendorCredit',
|
||||
oldVendorCredit.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlink all attachments once the vendor credit deleted.
|
||||
* @param {IVendorCreditDeletingPayload}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async handleUnlinkAttachmentsOnVendorCreditDeleted({
|
||||
tenantId,
|
||||
oldVendorCredit,
|
||||
trx,
|
||||
}: IVendorCreditDeletingPayload) {
|
||||
await this.unlinkAttachmentService.unlinkAllModelKeys(
|
||||
tenantId,
|
||||
'VendorCredit',
|
||||
oldVendorCredit.id,
|
||||
trx
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,10 @@ export class SendVerfiyMailOnSignUp {
|
||||
private handleSendVerifyMailOnSignup = async ({
|
||||
user,
|
||||
}: IAuthSignedUpEventPayload) => {
|
||||
// Can't continue if the user is verified.
|
||||
if (user.verified) {
|
||||
return;
|
||||
}
|
||||
const payload = {
|
||||
email: user.email,
|
||||
token: user.verifyToken,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { formatNumber } from 'utils';
|
||||
import { ItemEntryTransformer } from '../Sales/Invoices/ItemEntryTransformer';
|
||||
import { ICreditNote } from '@/interfaces';
|
||||
import { AttachmentTransformer } from '../Attachments/AttachmentTransformer';
|
||||
|
||||
export class CreditNoteTransformer extends Transformer {
|
||||
/**
|
||||
@@ -16,6 +17,7 @@ export class CreditNoteTransformer extends Transformer {
|
||||
'formattedCreditsUsed',
|
||||
'formattedSubtotal',
|
||||
'entries',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
@@ -80,4 +82,13 @@ export class CreditNoteTransformer extends Transformer {
|
||||
currencyCode: credit.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the credit note attachments.
|
||||
* @param {ISaleInvoice} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (creditNote) => {
|
||||
return this.item(creditNote.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export default class BaseCreditNotes {
|
||||
autoNextNumber;
|
||||
|
||||
const initialDTO = {
|
||||
...omit(creditNoteDTO, ['open']),
|
||||
...omit(creditNoteDTO, ['open', 'attachments']),
|
||||
creditNoteNumber,
|
||||
amount,
|
||||
currencyCode: customerCurrencyCode,
|
||||
|
||||
@@ -28,7 +28,8 @@ export default class GetCreditNote extends BaseCreditNotes {
|
||||
.findById(creditNoteId)
|
||||
.withGraphFetched('entries.item')
|
||||
.withGraphFetched('customer')
|
||||
.withGraphFetched('branch');
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
if (!creditNote) {
|
||||
throw new ServiceError(ERRORS.CREDIT_NOTE_NOT_FOUND);
|
||||
|
||||
@@ -123,6 +123,7 @@ export class CreateExpense {
|
||||
tenantId,
|
||||
expenseId: expense.id,
|
||||
authorizedUser,
|
||||
expenseDTO,
|
||||
expense,
|
||||
trx,
|
||||
} as IExpenseCreatedPayload);
|
||||
|
||||
@@ -54,7 +54,7 @@ export class ExpenseDTOTransformer {
|
||||
|
||||
const initialDTO = {
|
||||
categories: [],
|
||||
...omit(expenseDTO, ['publish']),
|
||||
...omit(expenseDTO, ['publish', 'attachments']),
|
||||
totalAmount,
|
||||
landedCostAmount,
|
||||
paymentDate: moment(expenseDTO.paymentDate).toMySqlDateTime(),
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { formatNumber } from 'utils';
|
||||
import { IExpense } from '@/interfaces';
|
||||
import { ExpenseCategoryTransformer } from './ExpenseCategoryTransformer';
|
||||
import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer';
|
||||
|
||||
export class ExpenseTransfromer extends Transformer {
|
||||
/**
|
||||
@@ -15,6 +16,7 @@ export class ExpenseTransfromer extends Transformer {
|
||||
'formattedAllocatedCostAmount',
|
||||
'formattedDate',
|
||||
'categories',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
@@ -70,4 +72,13 @@ export class ExpenseTransfromer extends Transformer {
|
||||
currencyCode: expense.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the sale invoice attachments.
|
||||
* @param {ISaleInvoice} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (expense: IExpense) => {
|
||||
return this.item(expense.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ export class GetExpense {
|
||||
.withGraphFetched('categories.expenseAccount')
|
||||
.withGraphFetched('paymentAccount')
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('attachments')
|
||||
.throwIfNotFound();
|
||||
|
||||
// Transformes expense model to POJO.
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from '@/interfaces';
|
||||
import TenancyService from '@/services/Tenancy/TenancyService';
|
||||
import events from '@/subscribers/events';
|
||||
import { Tenant, TenantMetadata } from '@/system/models';
|
||||
import { TenantMetadata } from '@/system/models';
|
||||
import UnitOfWork from '@/services/UnitOfWork';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import { CommandManualJournalValidators } from './CommandManualJournalValidators';
|
||||
@@ -59,7 +59,7 @@ export class CreateManualJournalService {
|
||||
const journalNumber = manualJournalDTO.journalNumber || autoNextNumber;
|
||||
|
||||
const initialDTO = {
|
||||
...omit(manualJournalDTO, ['publish']),
|
||||
...omit(manualJournalDTO, ['publish', 'attachments']),
|
||||
...(manualJournalDTO.publish
|
||||
? { publishedAt: moment().toMySqlDateTime() }
|
||||
: {}),
|
||||
@@ -173,6 +173,7 @@ export class CreateManualJournalService {
|
||||
tenantId,
|
||||
manualJournal,
|
||||
manualJournalId: manualJournal.id,
|
||||
manualJournalDTO,
|
||||
trx,
|
||||
} as IManualJournalEventCreatedPayload);
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ export class EditManualJournal {
|
||||
|
||||
return {
|
||||
id: oldManualJournal.id,
|
||||
...omit(manualJournalDTO, ['publish']),
|
||||
...omit(manualJournalDTO, ['publish', 'attachments']),
|
||||
...(manualJournalDTO.publish && !oldManualJournal.publishedAt
|
||||
? { publishedAt: moment().toMySqlDateTime() }
|
||||
: {}),
|
||||
@@ -143,6 +143,7 @@ export class EditManualJournal {
|
||||
tenantId,
|
||||
manualJournal,
|
||||
oldManualJournal,
|
||||
manualJournalDTO,
|
||||
trx,
|
||||
} as IManualJournalEventEditedPayload);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ export class GetManualJournal {
|
||||
.withGraphFetched('entries.contact')
|
||||
.withGraphFetched('entries.branch')
|
||||
.withGraphFetched('transactions')
|
||||
.withGraphFetched('media')
|
||||
.withGraphFetched('attachments')
|
||||
.throwIfNotFound();
|
||||
|
||||
return this.transformer.transform(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { IManualJournal } from '@/interfaces';
|
||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { formatNumber } from 'utils';
|
||||
import { AttachmentTransformer } from '../Attachments/AttachmentTransformer';
|
||||
|
||||
export class ManualJournalTransfromer extends Transformer {
|
||||
/**
|
||||
@@ -8,7 +9,12 @@ export class ManualJournalTransfromer extends Transformer {
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return ['formattedAmount', 'formattedDate', 'formattedPublishedAt'];
|
||||
return [
|
||||
'formattedAmount',
|
||||
'formattedDate',
|
||||
'formattedPublishedAt',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,4 +45,13 @@ export class ManualJournalTransfromer extends Transformer {
|
||||
protected formattedPublishedAt = (manualJorunal: IManualJournal): string => {
|
||||
return this.formatDate(manualJorunal.publishedAt);
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the manual journal attachments.
|
||||
* @param {ISaleInvoice} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (manualJorunal: IManualJournal) => {
|
||||
return this.item(manualJorunal.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { IBillPayment } from '@/interfaces';
|
||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { formatNumber } from 'utils';
|
||||
import { BillPaymentEntryTransformer } from './BillPaymentEntryTransformer';
|
||||
import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer';
|
||||
|
||||
export class BillPaymentTransformer extends Transformer {
|
||||
/**
|
||||
@@ -9,7 +10,12 @@ export class BillPaymentTransformer extends Transformer {
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return ['formattedPaymentDate', 'formattedAmount', 'entries'];
|
||||
return [
|
||||
'formattedPaymentDate',
|
||||
'formattedAmount',
|
||||
'entries',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -38,4 +44,13 @@ export class BillPaymentTransformer extends Transformer {
|
||||
protected entries = (billPayment) => {
|
||||
return this.item(billPayment.entries, new BillPaymentEntryTransformer());
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the bill attachments.
|
||||
* @param {ISaleInvoice} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (billPayment) => {
|
||||
return this.item(billPayment.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ export default class BillPaymentsPages {
|
||||
const { BillPayment, Bill } = this.tenancy.models(tenantId);
|
||||
const billPayment = await BillPayment.query()
|
||||
.findById(billPaymentId)
|
||||
.withGraphFetched('entries.bill');
|
||||
.withGraphFetched('entries.bill')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
// Throw not found the bill payment.
|
||||
if (!billPayment) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import * as R from 'ramda';
|
||||
import { sumBy } from 'lodash';
|
||||
import { omit, sumBy } from 'lodash';
|
||||
import { IBillPayment, IBillPaymentDTO, IVendor } from '@/interfaces';
|
||||
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
|
||||
import { formatDateFields } from '@/utils';
|
||||
@@ -24,7 +24,9 @@ export class CommandBillPaymentDTOTransformer {
|
||||
oldBillPayment?: IBillPayment
|
||||
): Promise<IBillPayment> {
|
||||
const initialDTO = {
|
||||
...formatDateFields(billPaymentDTO, ['paymentDate']),
|
||||
...formatDateFields(omit(billPaymentDTO, ['attachments']), [
|
||||
'paymentDate',
|
||||
]),
|
||||
amount: sumBy(billPaymentDTO.entries, 'paymentAmount'),
|
||||
currencyCode: vendor.currencyCode,
|
||||
exchangeRate: billPaymentDTO.exchangeRate || 1,
|
||||
|
||||
@@ -112,12 +112,12 @@ export class CreateBillPayment {
|
||||
const billPayment = await BillPayment.query(trx).insertGraphAndFetch({
|
||||
...billPaymentObj,
|
||||
});
|
||||
|
||||
// Triggers `onBillPaymentCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.billPayment.onCreated, {
|
||||
tenantId,
|
||||
billPayment,
|
||||
billPaymentId: billPayment.id,
|
||||
billPaymentDTO,
|
||||
trx,
|
||||
} as IBillPaymentEventCreatedPayload);
|
||||
|
||||
|
||||
@@ -137,6 +137,7 @@ export class EditBillPayment {
|
||||
billPaymentId,
|
||||
billPayment,
|
||||
oldBillPayment,
|
||||
billPaymentDTO,
|
||||
trx,
|
||||
} as IBillPaymentEventEditedPayload);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export class GetBillPayment {
|
||||
private transformer: TransformerInjectable;
|
||||
|
||||
/**
|
||||
* Retrieve bill payment.
|
||||
* Retrieves bill payment.
|
||||
* @param {number} tenantId
|
||||
* @param {number} billPyamentId
|
||||
* @return {Promise<IBillPayment>}
|
||||
@@ -30,6 +30,7 @@ export class GetBillPayment {
|
||||
.withGraphFetched('paymentAccount')
|
||||
.withGraphFetched('transactions')
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('attachments')
|
||||
.findById(billPyamentId)
|
||||
.throwIfNotFound();
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ export class BillDTOTransformer {
|
||||
)(asyncEntries);
|
||||
|
||||
const initialDTO = {
|
||||
...formatDateFields(omit(billDTO, ['open', 'entries']), [
|
||||
...formatDateFields(omit(billDTO, ['open', 'entries', 'attachments']), [
|
||||
'billDate',
|
||||
'dueDate',
|
||||
]),
|
||||
|
||||
@@ -110,6 +110,7 @@ export class CreateBill {
|
||||
tenantId,
|
||||
bill,
|
||||
billId: bill.id,
|
||||
billDTO,
|
||||
trx,
|
||||
} as IBillCreatedPayload);
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ export class EditBill {
|
||||
billId,
|
||||
oldBill,
|
||||
bill,
|
||||
billDTO,
|
||||
trx,
|
||||
} as IBillEditedPayload);
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ export class GetBill {
|
||||
.withGraphFetched('vendor')
|
||||
.withGraphFetched('entries.item')
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('taxes.taxRate');
|
||||
.withGraphFetched('taxes.taxRate')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
// Validates the bill existance.
|
||||
this.validators.validateBillExistance(bill);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IBill } from '@/interfaces';
|
||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer';
|
||||
import { ItemEntryTransformer } from '@/services/Sales/Invoices/ItemEntryTransformer';
|
||||
import { SaleInvoiceTaxEntryTransformer } from '@/services/Sales/Invoices/SaleInvoiceTaxEntryTransformer';
|
||||
import { formatNumber } from 'utils';
|
||||
@@ -26,6 +27,7 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
||||
'totalLocalFormatted',
|
||||
'taxes',
|
||||
'entries',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
@@ -192,4 +194,13 @@ export class PurchaseInvoiceTransformer extends Transformer {
|
||||
currencyCode: bill.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the bill attachments.
|
||||
* @param {ISaleInvoice} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (bill) => {
|
||||
return this.item(bill.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export default class BaseVendorCredit {
|
||||
autoNextNumber;
|
||||
|
||||
const initialDTO = {
|
||||
...omit(vendorCreditDTO, ['open']),
|
||||
...omit(vendorCreditDTO, ['open', 'attachments']),
|
||||
amount,
|
||||
currencyCode: vendorCurrencyCode,
|
||||
exchangeRate: vendorCreditDTO.exchangeRate || 1,
|
||||
|
||||
@@ -93,6 +93,7 @@ export default class EditVendorCredit extends BaseVendorCredit {
|
||||
oldVendorCredit,
|
||||
vendorCredit,
|
||||
vendorCreditId,
|
||||
vendorCreditDTO,
|
||||
trx,
|
||||
} as IVendorCreditEditedPayload);
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ export default class GetVendorCredit {
|
||||
.findById(vendorCreditId)
|
||||
.withGraphFetched('entries.item')
|
||||
.withGraphFetched('vendor')
|
||||
.withGraphFetched('branch');
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
if (!vendorCredit) {
|
||||
throw new ServiceError(ERRORS.VENDOR_CREDIT_NOT_FOUND);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IVendorCredit } from '@/interfaces';
|
||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer';
|
||||
import { ItemEntryTransformer } from '@/services/Sales/Invoices/ItemEntryTransformer';
|
||||
import { formatNumber } from 'utils';
|
||||
|
||||
@@ -16,6 +17,7 @@ export class VendorCreditTransformer extends Transformer {
|
||||
'formattedCreditsRemaining',
|
||||
'formattedInvoicedAmount',
|
||||
'entries',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
@@ -80,4 +82,13 @@ export class VendorCreditTransformer extends Transformer {
|
||||
currencyCode: vendorCredit.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the vendor credit attachments.
|
||||
* @param {IVendorCredit} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (vendorCredit) => {
|
||||
return this.item(vendorCredit.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ export class EditSaleEstimate {
|
||||
estimateId,
|
||||
saleEstimate,
|
||||
oldSaleEstimate,
|
||||
estimateDTO,
|
||||
trx,
|
||||
} as ISaleEstimateEditedPayload);
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ export class GetSaleEstimate {
|
||||
.findById(estimateId)
|
||||
.withGraphFetched('entries.item')
|
||||
.withGraphFetched('customer')
|
||||
.withGraphFetched('branch');
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
// Validates the estimate existance.
|
||||
this.validators.validateEstimateExistance(estimate);
|
||||
|
||||
@@ -58,10 +58,10 @@ export class SaleEstimateDTOTransformer {
|
||||
|
||||
const initialDTO = {
|
||||
amount,
|
||||
...formatDateFields(omit(estimateDTO, ['delivered', 'entries']), [
|
||||
'estimateDate',
|
||||
'expirationDate',
|
||||
]),
|
||||
...formatDateFields(
|
||||
omit(estimateDTO, ['delivered', 'entries', 'attachments']),
|
||||
['estimateDate', 'expirationDate']
|
||||
),
|
||||
currencyCode: paymentCustomer.currencyCode,
|
||||
exchangeRate: estimateDTO.exchangeRate || 1,
|
||||
...(estimateNumber ? { estimateNumber } : {}),
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ISaleEstimate } from '@/interfaces';
|
||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { formatNumber } from 'utils';
|
||||
import { ItemEntryTransformer } from '../Invoices/ItemEntryTransformer';
|
||||
import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer';
|
||||
|
||||
export class SaleEstimateTransfromer extends Transformer {
|
||||
/**
|
||||
@@ -18,6 +19,7 @@ export class SaleEstimateTransfromer extends Transformer {
|
||||
'formattedApprovedAtDate',
|
||||
'formattedRejectedAtDate',
|
||||
'entries',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
@@ -91,9 +93,18 @@ export class SaleEstimateTransfromer extends Transformer {
|
||||
* @param {ISaleEstimate} estimate
|
||||
* @returns {}
|
||||
*/
|
||||
protected entries = (estimate) => {
|
||||
protected entries = (estimate: ISaleEstimate) => {
|
||||
return this.item(estimate.entries, new ItemEntryTransformer(), {
|
||||
currencyCode: estimate.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the sale estimate attachments.
|
||||
* @param {ISaleInvoice} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (estimate: ISaleEstimate) => {
|
||||
return this.item(estimate.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -86,7 +86,12 @@ export class CommandSaleInvoiceDTOTransformer {
|
||||
|
||||
const initialDTO = {
|
||||
...formatDateFields(
|
||||
omit(saleInvoiceDTO, ['delivered', 'entries', 'fromEstimateId']),
|
||||
omit(saleInvoiceDTO, [
|
||||
'delivered',
|
||||
'entries',
|
||||
'fromEstimateId',
|
||||
'attachments',
|
||||
]),
|
||||
['invoiceDate', 'dueDate']
|
||||
),
|
||||
// Avoid rewrite the deliver date in edit mode when already published.
|
||||
|
||||
@@ -34,7 +34,8 @@ export class GetSaleInvoice {
|
||||
.withGraphFetched('entries.tax')
|
||||
.withGraphFetched('customer')
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('taxes.taxRate');
|
||||
.withGraphFetched('taxes.taxRate')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
// Validates the given sale invoice existance.
|
||||
this.validators.validateInvoiceExistance(saleInvoice);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { formatNumber } from 'utils';
|
||||
import { SaleInvoiceTaxEntryTransformer } from './SaleInvoiceTaxEntryTransformer';
|
||||
import { ItemEntryTransformer } from './ItemEntryTransformer';
|
||||
import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer';
|
||||
|
||||
export class SaleInvoiceTransformer extends Transformer {
|
||||
/**
|
||||
@@ -25,6 +26,7 @@ export class SaleInvoiceTransformer extends Transformer {
|
||||
'totalLocalFormatted',
|
||||
'taxes',
|
||||
'entries',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
@@ -190,4 +192,13 @@ export class SaleInvoiceTransformer extends Transformer {
|
||||
currencyCode: invoice.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the sale invoice attachments.
|
||||
* @param {ISaleInvoice} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (invoice) => {
|
||||
return this.item(invoice.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ export class CreatePaymentReceive {
|
||||
tenantId,
|
||||
paymentReceive,
|
||||
paymentReceiveId: paymentReceive.id,
|
||||
paymentReceiveDTO,
|
||||
authorizedUser,
|
||||
trx,
|
||||
} as IPaymentReceiveCreatedPayload);
|
||||
|
||||
@@ -51,7 +51,7 @@ export class PaymentReceiveDTOTransformer {
|
||||
this.validators.validatePaymentNoRequire(paymentReceiveNo);
|
||||
|
||||
const initialDTO = {
|
||||
...formatDateFields(omit(paymentReceiveDTO, ['entries']), [
|
||||
...formatDateFields(omit(paymentReceiveDTO, ['entries', 'attachments']), [
|
||||
'paymentDate',
|
||||
]),
|
||||
amount: paymentAmount,
|
||||
|
||||
@@ -66,7 +66,7 @@ export default class PaymentReceivesPages {
|
||||
*/
|
||||
public async getPaymentReceiveEditPage(
|
||||
tenantId: number,
|
||||
paymentReceiveId: number,
|
||||
paymentReceiveId: number
|
||||
): Promise<{
|
||||
paymentReceive: Omit<IPaymentReceive, 'entries'>;
|
||||
entries: IPaymentReceivePageEntry[];
|
||||
@@ -76,7 +76,8 @@ export default class PaymentReceivesPages {
|
||||
// Retrieve payment receive.
|
||||
const paymentReceive = await PaymentReceive.query()
|
||||
.findById(paymentReceiveId)
|
||||
.withGraphFetched('entries.invoice');
|
||||
.withGraphFetched('entries.invoice')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
// Throw not found the payment receive.
|
||||
if (!paymentReceive) {
|
||||
|
||||
@@ -101,6 +101,7 @@ export class CreateSaleReceipt {
|
||||
tenantId,
|
||||
saleReceipt,
|
||||
saleReceiptId: saleReceipt.id,
|
||||
saleReceiptDTO,
|
||||
trx,
|
||||
} as ISaleReceiptCreatedPayload);
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@ export class EditSaleReceipt {
|
||||
oldSaleReceipt,
|
||||
saleReceipt,
|
||||
saleReceiptId,
|
||||
saleReceiptDTO,
|
||||
trx,
|
||||
} as ISaleReceiptEditedPayload);
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ export class GetSaleReceipt {
|
||||
.withGraphFetched('entries.item')
|
||||
.withGraphFetched('customer')
|
||||
.withGraphFetched('depositAccount')
|
||||
.withGraphFetched('branch');
|
||||
.withGraphFetched('branch')
|
||||
.withGraphFetched('attachments');
|
||||
|
||||
// Valdiates the sale receipt existance.
|
||||
this.validators.validateReceiptExistance(saleReceipt);
|
||||
|
||||
@@ -68,9 +68,10 @@ export class SaleReceiptDTOTransformer {
|
||||
|
||||
const initialDTO = {
|
||||
amount,
|
||||
...formatDateFields(omit(saleReceiptDTO, ['closed', 'entries']), [
|
||||
'receiptDate',
|
||||
]),
|
||||
...formatDateFields(
|
||||
omit(saleReceiptDTO, ['closed', 'entries', 'attachments']),
|
||||
['receiptDate']
|
||||
),
|
||||
currencyCode: paymentCustomer.currencyCode,
|
||||
exchangeRate: saleReceiptDTO.exchangeRate || 1,
|
||||
receiptNumber,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ISaleReceipt } from '@/interfaces';
|
||||
import { Transformer } from '@/lib/Transformer/Transformer';
|
||||
import { formatNumber } from 'utils';
|
||||
import { ItemEntryTransformer } from '../Invoices/ItemEntryTransformer';
|
||||
import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer';
|
||||
|
||||
@Service()
|
||||
export class SaleReceiptTransformer extends Transformer {
|
||||
@@ -17,6 +18,7 @@ export class SaleReceiptTransformer extends Transformer {
|
||||
'formattedReceiptDate',
|
||||
'formattedClosedAtDate',
|
||||
'entries',
|
||||
'attachments',
|
||||
];
|
||||
};
|
||||
|
||||
@@ -68,4 +70,13 @@ export class SaleReceiptTransformer extends Transformer {
|
||||
currencyCode: receipt.currencyCode,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the sale receipt attachments.
|
||||
* @param {ISaleReceipt} invoice
|
||||
* @returns
|
||||
*/
|
||||
protected attachments = (receipt) => {
|
||||
return this.item(receipt.attachments, new AttachmentTransformer());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from './utils';
|
||||
import { Plan } from '@/system/models';
|
||||
import { Subscription } from './Subscription';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
@Service()
|
||||
export class LemonSqueezyWebhooks {
|
||||
@@ -32,6 +33,9 @@ export class LemonSqueezyWebhooks {
|
||||
if (!config.lemonSqueezy.webhookSecret) {
|
||||
throw new Error('Lemon Squeezy Webhook Secret not set in .env');
|
||||
}
|
||||
if (!signature) {
|
||||
throw new Error('Request signature is required.');
|
||||
}
|
||||
const secret = config.lemonSqueezy.webhookSecret;
|
||||
const hmacSignature = createHmacSignature(secret, rawData);
|
||||
|
||||
@@ -49,7 +53,7 @@ export class LemonSqueezyWebhooks {
|
||||
|
||||
/**
|
||||
* This action will process a webhook event in the database.
|
||||
* @param {unknown} eventBody -
|
||||
* @param {unknown} eventBody -
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async processWebhookEvent(eventBody): Promise<void> {
|
||||
@@ -96,7 +100,7 @@ export class LemonSqueezyWebhooks {
|
||||
if (webhookEvent === 'subscription_created') {
|
||||
await this.subscriptionService.newSubscribtion(
|
||||
tenantId,
|
||||
'early-adaptor',
|
||||
'early-adaptor'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user