fix issues.

This commit is contained in:
Ahmed Bouhuolia
2020-05-05 04:21:37 +02:00
parent 3b25056cbe
commit bd7eb0eb76
41 changed files with 364 additions and 216 deletions

View File

@@ -14,7 +14,6 @@ exports.up = function (knex) {
table.text('note').nullable();
table.integer('category_id').unsigned();
table.integer('user_id').unsigned();
table.string('attachment_file');
table.timestamps();
});
};

View File

@@ -9,7 +9,7 @@ exports.up = function (knex) {
table.integer('view_id').unsigned();
}).then(() => {
return knex.seed.run({
specific: 'seed_views_role.js',
specific: 'seed_views_roles.js',
});
});
};

View File

@@ -7,13 +7,13 @@ exports.seed = function(knex) {
return knex('resource_fields').insert([
{ id: 1, label_name: 'Name', key: 'name', data_type: '', active: 1, predefined: 1 },
{ id: 2, label_name: 'Code', key: 'code', data_type: '', active: 1, predefined: 1 },
{ id: 3, label_name: 'Account Type', key: 'account_type_id', data_type: '', active: 1, predefined: 1 },
{ id: 3, label_name: 'Account Type', key: 'type', data_type: '', active: 1, predefined: 1 },
{ id: 4, label_name: 'Description', key: 'description', data_type: '', active: 1, predefined: 1 },
{ id: 5, label_name: 'Account Normal', key: 'normal', data_type: 'string', active: 1, predefined: 1 },
{
id: 6,
label_name: 'Root Account Type',
key: 'root_account_type',
key: 'root_type',
data_type: 'string',
active: 1,
predefined: 1,

View File

@@ -5,11 +5,11 @@ exports.seed = (knex) => {
.then(() => {
// Inserts seed entries
return knex('view_roles').insert([
{ id: 1, field_id: 6, comparator: 'equals', value: 'asset', view_id: 1 },
{ id: 2, field_id: 6, comparator: 'equals', value: 'liability', view_id: 2 },
{ id: 3, field_id: 6, comparator: 'equals', value: 'equity', view_id: 3 },
{ id: 4, field_id: 6, comparator: 'equals', value: 'income', view_id: 4 },
{ id: 5, field_id: 6, comparator: 'equals', value: 'expense', view_id: 5 },
{ id: 1, field_id: 6, index: 1, comparator: 'equals', value: 'asset', view_id: 1 },
{ id: 2, field_id: 6, index: 1, comparator: 'equals', value: 'liability', view_id: 2 },
{ id: 3, field_id: 6, index: 1, comparator: 'equals', value: 'equity', view_id: 3 },
{ id: 4, field_id: 6, index: 1, comparator: 'equals', value: 'income', view_id: 4 },
{ id: 5, field_id: 6, index: 1, comparator: 'equals', value: 'expense', view_id: 5 },
]);
});
};

View File

@@ -82,6 +82,7 @@ export default {
}
const form = {
custom_fields: [],
media_ids: [],
...req.body,
};
const {
@@ -90,6 +91,7 @@ export default {
ResourceField,
ItemCategory,
Item,
MediaLink,
} = req.models;
const errorReasons = [];
@@ -146,6 +148,7 @@ export default {
return res.boom.badRequest(null, { errors: errorReasons });
}
const bulkSaveMediaLinks = [];
const item = await Item.query().insertAndFetch({
name: form.name,
type: form.type,
@@ -156,6 +159,20 @@ export default {
currency_code: form.currency_code,
note: form.note,
});
form.media_ids.forEach((mediaId) => {
const oper = MediaLink.query().insert({
model_name: 'Item',
media_id: mediaId,
model_id: item.id,
});
bulkSaveMediaLinks.push(oper);
});
// Save the media links.
await Promise.all([
...bulkSaveMediaLinks,
]);
return res.status(200).send({ id: item.id });
},
},
@@ -188,14 +205,14 @@ export default {
code: 'validation_error', ...validationErrors,
});
}
const { Account, Item, ItemCategory } = req.models;
const { Account, Item, ItemCategory, MediaLink } = req.models;
const { id } = req.params;
const form = {
custom_fields: [],
...req.body,
};
const item = await Item.query().findById(id);
const item = await Item.query().findById(id).withGraphFetched('media');
if (!item) {
return res.boom.notFound(null, {
@@ -235,12 +252,12 @@ export default {
if (attachment) {
const publicPath = 'storage/app/public/';
const tenantPath = `${publicPath}${req.organizationId}`;
try {
await fsPromises.unlink(`${tenantPath}/${item.attachmentFile}`);
} catch (error) {
Logger.log('error', 'Delete item attachment file delete failed.', { error });
}
try {
await attachment.mv(`${tenantPath}/${attachment.md5}.png`);
} catch (error) {
@@ -262,6 +279,22 @@ export default {
note: form.note,
attachment_file: (attachment) ? item.attachmentFile : null,
});
// Save links of new inserted media that associated to the item model.
const itemMediaIds = item.media.map((m) => m.id);
const newInsertedMedia = difference(form.media_ids, itemMediaIds);
const bulkSaveMediaLink = [];
newInsertedMedia.forEach((mediaId) => {
const oper = MediaLink.query().insert({
model_name: 'Journal',
model_id: manualJournal.id,
media_id: mediaId,
});
bulkSaveMediaLink.push(oper);
});
await Promise.all([ ...newInsertedMedia ]);
return res.status(200).send({ id: updatedItem.id });
},
},

View File

@@ -6,6 +6,7 @@ import {
validationResult,
} from 'express-validator';
import fs from 'fs';
import { difference } from 'lodash';
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
import Logger from '@/services/Logger';
@@ -22,7 +23,7 @@ export default {
this.upload.validation,
asyncMiddleware(this.upload.handler));
router.delete('/delete/:id',
router.delete('/',
this.delete.validation,
asyncMiddleware(this.delete.handler));
@@ -109,7 +110,8 @@ export default {
*/
delete: {
validation: [
param('id').exists().isNumeric().toInt(),
query('ids').exists().isArray(),
query('ids.*').exists().isNumeric().toInt(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
@@ -120,26 +122,37 @@ export default {
});
}
const { Media, MediaLink } = req.models;
const { id } = req.params;
const media = await Media.query().where('id', id).first();
const ids = Array.isArray(req.query.ids) ? req.query.ids : [req.query.ids];
const media = await Media.query().whereIn('id', ids);
const mediaIds = media.map((m) => m.id);
const notFoundMedia = difference(ids, mediaIds);
if (!media) {
if (notFoundMedia.length) {
return res.status(400).send({
errors: [{ type: 'MEDIA.ID.NOT.FOUND', code: 200 }],
errors: [{ type: 'MEDIA.IDS.NOT.FOUND', code: 200, ids: notFoundMedia }],
});
}
const publicPath = 'storage/app/public/';
const tenantPath = `${publicPath}${req.organizationId}`;
const unlinkOpers = [];
try {
await fsPromises.unlink(`${tenantPath}/${media.attachmentFile}`);
Logger.log('error', 'Attachment file has been deleted.');
} catch (error) {
Logger.log('error', 'Delete item attachment file delete failed.', { error });
}
media.forEach((mediaModel) => {
const oper = fsPromises.unlink(`${tenantPath}/${mediaModel.attachmentFile}`);
unlinkOpers.push(oper);
});
await Promise.all(unlinkOpers).then((resolved) => {
resolved.forEach(() => {
Logger.log('error', 'Attachment file has been deleted.');
});
})
.catch((errors) => {
errors.forEach((error) => {
Logger.log('error', 'Delete item attachment file delete failed.', { error });
})
});
await MediaLink.query().where('media_id', media.id).delete();
await Media.query().where('id', media.id).delete();
await MediaLink.query().whereIn('media_id', mediaIds).delete();
await Media.query().whereIn('id', mediaIds).delete();
return res.status(200).send();
},

View File

@@ -12,6 +12,9 @@ export default class Item extends TenantModel {
return 'items';
}
/**
* Model modifiers.
*/
static get modifiers() {
const TABLE_NAME = Item.tableName;
@@ -29,6 +32,7 @@ export default class Item extends TenantModel {
* Relationship mapping.
*/
static get relationMappings() {
const Media = require('@/models/Media');
const Account = require('@/models/Account');
const ItemCategory = require('@/models/ItemCategory');
@@ -71,6 +75,19 @@ export default class Item extends TenantModel {
to: 'accounts.id',
},
},
media: {
relation: Model.ManyToManyRelation,
modelClass: this.relationBindKnex(Media.default),
join: {
from: 'items.id',
through: {
from: 'media_links.model_id',
to: 'media_links.media_id',
},
to: 'media.id',
}
},
};
}
}