Skip to content

Commit

Permalink
feat(journal): add transaction history flag
Browse files Browse the repository at this point in the history
This commit adds the transaction history to the edit transaction modal
so that a user viewing the transaction may get a glimpse of the last
time this transaction was edited.
  • Loading branch information
jniles committed Sep 26, 2017
1 parent df82035 commit ca4f7a8
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 85 deletions.
1 change: 1 addition & 0 deletions client/src/i18n/en/posting_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"ROWS" : "Row(s)",
"EDITING" : "Editing",
"NO_TRANSACTION_TYPE" : "No assigned transaction type",
"HAS_PREVIOUS_EDITS" : "Last edit by {{ user }} on {{ date }}",
"JUSTIFICATION" : "Justification",
"REFRESH" : "Refresh",
"SAVE_TRANSACTION" : "Save Transaction",
Expand Down
1 change: 1 addition & 0 deletions client/src/i18n/fr/posting_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"REMOVE_ROW" : "Supprimer Ligne(s)",
"ROWS" : "Ligne(s)",
"SAVE_TRANSACTION_SUCCESS" : "La transaction etait enregistré avec succés",
"HAS_PREVIOUS_EDITS" : "Dernière édition par {{ user }} le {{ date }}",
"JUSTIFICATION" : "Justification",
"REFRESH" : "Rafraichir",
"SAVE_TRANSACTION" : "Sauvegarder la transaction",
Expand Down
10 changes: 9 additions & 1 deletion client/src/modules/journal/journal.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ function JournalService(Api, AppCache, Filters, Periods, Modal) {
service.openTransactionEditModal = openTransactionEditModal;
service.mapTransactionIdsToRecordUuids = mapTransactionIdsToRecordUuids;
service.commentPostingJournal = commentPostingJournal;
service.getTransactionEditHistory = getTransactionEditHistory;

/**
* Standard API read method, as this will be used to drive the journal grids
Expand Down Expand Up @@ -204,7 +205,14 @@ function JournalService(Api, AppCache, Filters, Periods, Modal) {

// updating the posting journal by adding comments in transactions
function commentPostingJournal(params) {
return service.$http.put(URL.concat('comments'), { 'params' : params })
return service.$http.put(URL.concat('comments'), { params : params })
.then(service.util.unwrapHttpResponse);
}

// load the edit history of a particular transaction
function getTransactionEditHistory(uuid) {
var url = '/transactions/:uuid/history'.replace(':uuid', uuid);
return service.$http.get(url)
.then(service.util.unwrapHttpResponse);
}

Expand Down
167 changes: 87 additions & 80 deletions client/src/modules/journal/modals/editTransaction.modal.html
Original file line number Diff line number Diff line change
@@ -1,113 +1,120 @@
<div class="modal-header">
<ol class="headercrumb">
<ol class="headercrumb clearfix">
<li class="static" translate>POSTING_JOURNAL.TRANSACTION</li>
<li class="title" translate>{{ModalCtrl.shared.trans_id}}</li>
<span class="badge badge-warning" ng-if="ModalCtrl.readOnly"><i class="fa fa-eye"></i> <span translate>POSTING_JOURNAL.VIEWING</span></span>
<span class="badge badge-primary" ng-if="!ModalCtrl.readOnly"><i class="fa fa-pencil"></i> <span translate>POSTING_JOURNAL.EDITING</span></span>
</ol>
</div>

<div class="modal-body">
<!-- warn user that standard users cannot edit posted transactions -->
<div class="alert alert-warning pad-alert" ng-if="ModalCtrl.validation.blockedPostedTransactionEdit">
<i class="fa fa-warning"></i> <span translate>POSTING_JOURNAL.ERRORS.USER_CANNOT_EDIT_POSTED_TRANSACTION</span>
</div>

<!-- Record information -->
<div style="border : 1px solid #c4c4c4; padding : 5px; margin-bottom : 10px;">
<div style="border : 1px solid #c4c4c4; padding : 5px; margin-bottom : 10px;">

<div class="row" ng-if="ModalCtrl.loadingTransaction">
<div class="col-xs-12 text-center">
<span class="fa fa-circle-o-notch fa-spin"></span>
</div>
<div class="row" ng-if="ModalCtrl.loadingTransaction">
<div class="col-xs-12 text-center">
<span class="fa fa-circle-o-notch fa-spin"></span>
</div>
<div class="row" ng-if="ModalCtrl.setupComplete">
<form class="form-horizontal">
<div class="col-xs-6">
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.RECORD</label>
<div class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.hrRecord}}</p>
</div>
</div>
<div class="row" ng-if="ModalCtrl.setupComplete">
<form class="form-horizontal">
<div class="col-xs-6">
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.RECORD</label>
<div class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.hrRecord}}</p>
</div>
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.PROJECT</label>
<div class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.project_name}}</p>
</div>
</div>
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.PROJECT</label>
<div class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.project_name}}</p>
</div>
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.TRANSACTION_ID</label>
<div class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.trans_id}}</p>
</div>
</div>
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.TRANSACTION_ID</label>
<div class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.trans_id}}</p>
</div>
</div>
<div class="col-xs-6">
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.TYPE</label>
<div ng-if="ModalCtrl.readOnly" class="col-sm-9">
<p class="form-control-static" translate>{{ModalCtrl.transactionTypes.get(ModalCtrl.shared.origin_id).text || '-'}}</p>
</div>
<div ng-if="!ModalCtrl.readOnly" class="col-sm-9">
<select
ng-model="ModalCtrl.shared.origin_id"
ng-change="ModalCtrl.handleTransactionTypeChange(ModalCtrl.shared.origin_id)"
ng-options="types.id as (types.text | translate) for types in ModalCtrl.transactionTypes.data"
class="form-control">
<option disabled value="" translate>POSTING_JOURNAL.NO_TRANSACTION_TYPE</option>
</select>
</div>
</div>
<div class="col-xs-6">
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.TYPE</label>
<div ng-if="ModalCtrl.readOnly" class="col-sm-9">
<p class="form-control-static" translate>{{ModalCtrl.transactionTypes.get(ModalCtrl.shared.origin_id).text || '-'}}</p>
</div>
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.RESPONSIBLE</label>
<div class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.display_name}}</p>
</div>
<div ng-if="!ModalCtrl.readOnly" class="col-sm-9">
<select
ng-model="ModalCtrl.shared.origin_id"
ng-change="ModalCtrl.handleTransactionTypeChange(ModalCtrl.shared.origin_id)"
ng-options="types.id as (types.text | translate) for types in ModalCtrl.transactionTypes.data"
class="form-control">
<option disabled value="" translate>POSTING_JOURNAL.NO_TRANSACTION_TYPE</option>
</select>
</div>
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.DATE</label>
<div ng-if="ModalCtrl.readOnly" class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.trans_date | date}}</p>
</div>
<div ng-if="!ModalCtrl.readOnly" class="col-sm-9">
<div class="input-group">
<input
uib-datepicker-popup="dd/MM/yyyy"
ng-model="ModalCtrl.shared.trans_date"
ng-change="ModalCtrl.handleTransactionDateChange(ModalCtrl.shared.trans_date)"
is-open="ModalCtrl.dateEditorOpen"
type="text"
class="form-control"></input>
<span class="input-group-btn">
<button class="btn btn-default btn-sm" ng-click="ModalCtrl.openDateEditor()"><span class="fa fa-calendar"></span></button>
</span>
</div>
</div>
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.RESPONSIBLE</label>
<div class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.display_name}}</p>
</div>
</div>
<div class="form-group-sm">
<label class="col-sm-3 control-label" translate>TABLE.COLUMNS.DATE</label>
<div ng-if="ModalCtrl.readOnly" class="col-sm-9">
<p class="form-control-static">{{ModalCtrl.shared.trans_date | date}}</p>
</div>
<div ng-if="!ModalCtrl.readOnly" class="col-sm-9">
<div class="input-group">
<input
uib-datepicker-popup="dd/MM/yyyy"
ng-model="ModalCtrl.shared.trans_date"
ng-change="ModalCtrl.handleTransactionDateChange(ModalCtrl.shared.trans_date)"
is-open="ModalCtrl.dateEditorOpen"
type="text"
class="form-control"></input>
<span class="input-group-btn">
<button class="btn btn-default btn-sm" ng-click="ModalCtrl.openDateEditor()"><span class="fa fa-calendar"></span></button>
</span>
</div>
</div>
</div>
</form>
</div>
</div>
</form>
</div>
</div>

<div class="alert alert-danger pad-alert" id="validation-errored-alert" ng-if="ModalCtrl.validation.errored">
<i class="fa fa-exclamation-circle"></i> <span translate>{{ModalCtrl.validation.message}}</span>
</div>
<div class="alert alert-danger pad-alert" id="validation-errored-alert" ng-if="ModalCtrl.validation.errored">
<i class="fa fa-exclamation-circle"></i> <span translate>{{ModalCtrl.validation.message}}</span>
</div>

<!-- Transaction row edit utilities -->
<div ng-if="!ModalCtrl.readOnly" style="margin-bottom : 5px" class="text-right">
<button ng-disabled="!ModalCtrl.setupComplete" class="btn btn-default btn-sm" ng-click="ModalCtrl.addRow()" translate>POSTING_JOURNAL.ADD_ROW</button>
<button ng-disabled="!ModalCtrl.setupComplete" class="btn btn-default btn-sm" ng-click="ModalCtrl.removeRows()" translate data-method="delete">POSTING_JOURNAL.REMOVE_ROW</button>
</div>
<div style="height : 230px" id="transaction-edit-grid" ui-grid="ModalCtrl.gridOptions" ui-grid-cellNav ui-grid-selection ui-grid-edit ui-grid-resize-columns ui-grid-auto-resize>
<bh-grid-loading-indicator
loading-state="ModalCtrl.loadingTransaction"
empty-state="ModalCtrl.gridOptions.data.length === 0"
error-state="ModalCtrl.hasError">
</bh-grid-loading-indicator>
</div>
<!-- Transaction row edit utilities -->
<div ng-if="!ModalCtrl.readOnly" style="margin-bottom : 5px" class="text-right">
<button ng-disabled="!ModalCtrl.setupComplete" class="btn btn-default btn-sm" ng-click="ModalCtrl.addRow()" translate>POSTING_JOURNAL.ADD_ROW</button>
<button ng-disabled="!ModalCtrl.setupComplete" class="btn btn-default btn-sm" ng-click="ModalCtrl.removeRows()" translate data-method="delete">POSTING_JOURNAL.REMOVE_ROW</button>
</div>
<div style="height : 230px" id="transaction-edit-grid" ui-grid="ModalCtrl.gridOptions" ui-grid-cellNav ui-grid-selection ui-grid-edit ui-grid-resize-columns ui-grid-auto-resize>
<bh-grid-loading-indicator
loading-state="ModalCtrl.loadingTransaction"
empty-state="ModalCtrl.gridOptions.data.length === 0"
error-state="ModalCtrl.hasError">
</bh-grid-loading-indicator>
</div>
</div>

<div class="modal-footer">
<div class="modal-footer clearfix">
<!-- informational: this record has been edited x times -->
<span ng-if="ModalCtrl.hasPreviousEdits" class="text-muted pull-left" style="margin-top:5px;">
<i class="fa fa-info-circle"></i>
<span translate translate-values="ModalCtrl.lastEditValues">POSTING_JOURNAL.HAS_PREVIOUS_EDITS</span>
</span>

<button class="btn btn-default" data-method="cancel" ng-click="ModalCtrl.close()" translate>FORM.BUTTONS.CANCEL</button>
<bh-loading-button ng-if="!ModalCtrl.readOnly" disabled="!ModalCtrl.setupComplete" loading-state="ModalCtrl.saving" ng-click="ModalCtrl.saveTransaction()">
<span translate>POSTING_JOURNAL.SAVE_TRANSACTION</span>
Expand Down
24 changes: 21 additions & 3 deletions client/src/modules/journal/modals/editTransaction.modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ angular.module('bhima.controllers')

JournalEditTransactionController.$inject = [
'JournalService', 'Store', 'TransactionTypeService', '$uibModalInstance',
'transactionUuid', 'readOnly', 'uiGridConstants', 'uuid', 'util',
'transactionUuid', 'readOnly', 'uiGridConstants', 'uuid', 'util', 'moment',
];

function JournalEditTransactionController(
Journal, Store, TransactionType, Modal, transactionUuid, readOnly, uiGridConstants, uuid, util
Journal, Store, TransactionType, Modal, transactionUuid, readOnly, uiGridConstants,
uuid, util, moment
) {
var gridApi = {};
var vm = this;
Expand All @@ -23,7 +24,6 @@ function JournalEditTransactionController(
var ERROR_IMBALANCED_TRANSACTION = 'TRANSACTIONS.IMBALANCED_TRANSACTION';
var ERROR_SINGLE_ACCOUNT_TRANSACTION = 'TRANSACTIONS.SINGLE_ACCOUNT_TRANSACTION';
var ERROR_SINGLE_ROW_TRANSACTION = 'TRANSACTIONS.SINGLE_ROW_TRANSACTION';
var ERROR_NEGATIVE_VALUES = 'VOUCHERS.COMPLEX.ERRORS_NEGATIVE_VALUES'
var ERROR_INVALID_DEBITS_AND_CREDITS = 'VOUCHERS.COMPLEX.ERROR_AMOUNT';

var footerTemplate =
Expand Down Expand Up @@ -121,6 +121,24 @@ function JournalEditTransactionController(
vm.transactionTypes.setData(typeResults);
});

// this is completely optional - it is just for decoration and interest.
Journal.getTransactionEditHistory(transactionUuid)
.then(function (editHistory) {
var hasPreviousEdits = editHistory.length > 0;
var mostRecentEdit;
vm.hasPreviousEdits = hasPreviousEdits;

if (hasPreviousEdits) {
mostRecentEdit = editHistory.pop();

vm.lastEditValues = {
user : mostRecentEdit.display_name,
date : moment(mostRecentEdit.timestamp).format('DD/MM/YYYY'),
};
}
});


vm.loadingTransaction = true;
Journal.grid(transactionUuid)
.then(function (transaction) {
Expand Down
2 changes: 2 additions & 0 deletions server/config/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ exports.configure = function configure(app) {
app.get('/general_ledger/accounts', generalLedger.listAccounts);
app.put('/general_ledger/comments', generalLedger.commentAccountStatement);

app.get('/transactions/:uuid/history', journal.getTransactionEditHistory);

/* fiscal year controller */
app.get('/fiscal', fiscal.list);

Expand Down
23 changes: 22 additions & 1 deletion server/controllers/finance/journal/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ exports.reverse = reverse;
exports.find = find;
exports.buildTransactionQuery = buildTransactionQuery;

// exports.getTransactionEditHistory = getTransactionEditHistory;
exports.getTransactionEditHistory = getTransactionEditHistory;

exports.editTransaction = editTransaction;
exports.count = count;
Expand Down Expand Up @@ -543,6 +543,27 @@ function getTransactionDate(changedRows = {}, oldRows) {
.pop();
}

/**
* @function getTransactionEditHistory
*
* @description
* A lightweight function to scan the transaction_history and check if
* a transaction has previously been edited. If so, it pulls out the user
* that edited it and return that record to the client.
*/
function getTransactionEditHistory(req, res, next) {
const sql = `
SELECT u.display_name, timestamp FROM transaction_history
JOIN user AS u ON u.id = transaction_history.user_id
WHERE record_uuid = ?;
`;

db.exec(sql, [db.bid(req.params.uuid)])
.then(record => res.status(200).json(record))
.catch(next)
.done();
}


/**
* PUT /journal/comments
Expand Down

0 comments on commit ca4f7a8

Please sign in to comment.