diff --git a/client/src/js/components/bhCurrencySelect.js b/client/src/js/components/bhCurrencySelect.js index b997bcb9fa..99c201a03e 100644 --- a/client/src/js/components/bhCurrencySelect.js +++ b/client/src/js/components/bhCurrencySelect.js @@ -87,7 +87,7 @@ function bhCurrencySelect($scope, Currencies) { $scope.$watchCollection(function () { return $ctrl.disableIds; }, function (array) { - array = array || []; + if (!array) { return; } // loop through the currencies, disabling the currencies with ids in the // disabledIds array. @@ -97,8 +97,6 @@ function bhCurrencySelect($scope, Currencies) { // if the two array lengths are equal, it means every currency is disabled $ctrl.allDisabled = ($ctrl.currencies.length === array.length); - if ($ctrl.allDisabled) { - $ctrl.form.$setValidity('currencies', false); - } + $ctrl.form.$setValidity('currencies', $ctrl.allDisabled); }); } diff --git a/client/src/js/services/CashService.js b/client/src/js/services/CashService.js index eae9e444b6..d15a07be04 100644 --- a/client/src/js/services/CashService.js +++ b/client/src/js/services/CashService.js @@ -1,49 +1,30 @@ -/** - * CashService - * - * This service interacts with the server-side /cash API. - * - * @module services/CashService - */ - angular.module('bhima.services') .service('CashService', CashService); -CashService.$inject = [ '$http', 'util', 'ExchangeRateService', 'uuid', 'SessionService' ]; +CashService.$inject = [ + 'PrototypeApiService', 'ExchangeRateService', 'SessionService' +]; /** - * A service to interact with the server-side /cash API. + * @class CashService * - * @constructor CashService + * @description + * A service to interact with the server-side /cash API. */ -function CashService($http, util, Exchange, uuid, sessionService ) { +function CashService(PrototypeApiService, Exchange, Session) { var service = this; - var baseUrl = '/cash/'; - service.read = read; + // inherit prototype API methods + angular.extend(service, PrototypeApiService); + + // bind the base url + service.url = '/cash/'; + + // custom methods service.create = create; - service.update = update; - service.delete = remove; service.reference = reference; service.getTransferRecord = getTransferRecord; - /** - * Fetchs cash payments from the server. If an uuid is specified, will read a - * single JSON out of the service, otherwise, fetches every cash payment in the - * database. - * - * @method read - * @param {string} uuid (optional) - a cash payment UUID - * @param {object} options - parameters to be passed as HTTP query strings - * @returns {object|array} payments One or more cash payments. - */ - function read(uuid, options) { - var target = baseUrl.concat(uuid || ''); - - return $http.get(target, options) - .then(util.unwrapHttpResponse); - } - /** * Cash Payments can be made to multiple invoices. This function loops * though the invoices in selected order, allocating the global amount to each @@ -83,9 +64,11 @@ function CashService($http, util, Exchange, uuid, sessionService ) { } /** + * @method create + * + * @description * Creates a cash payment from a JSON passed from a form. * - * @method create * @param {object} data A JSON object containing the cash payment record defn * @returns {object} payment A promise resolved with the database uuid. */ @@ -109,101 +92,59 @@ function CashService($http, util, Exchange, uuid, sessionService ) { // remove data.invoices property before submission to the server delete data.invoices; - return $http.post(baseUrl, { payment : data }) - .then(util.unwrapHttpResponse); - } - - /** - * Fetchs cash payments from the server. If an id is specified, will read a single - * JSON out of the service, otherwise, fetches every cash payment in the database. - * - * @method update - * @param {string} uuid A cash payment UUID - * @returns {object} payments A promise containing the entire cash payment record - */ - function update(uuid, data) { - var target = baseUrl.concat(uuid); - return $http.put(target, data) - .then(util.unwrapHttpResponse); - } - - /** - * Deletes cash payments from the database based on the id passed in. - * - * @method delete - * @param {string} uuid A cash payment UUID - * @returns {promise} promise - a resolved or rejected empty promise - */ - function remove(uuid) { - var target = baseUrl.concat(uuid); - - // Technically, we are not returning any body, so unwrappHttpResponse does - // not do anything. However, to keep uniformity with the API, I've included - // it. - return $http.delete(target) - .then(util.unwrapHttpResponse); + // call the prototype create method with the formatted data + return PrototypeApiService.create.call(service, { payment : data }); } /** * Searches for a cash payment by its reference. * * @method reference - * @param {string} reference - * @returns {promise} promise - a resolved or rejected promise with the + * @param {String} reference + * @returns {Promise} promise - a resolved or rejected promise with the * result sent from the server. */ function reference(ref) { - var target = baseUrl + 'references/' + ref; - - return $http.get(target) - .then(util.unwrapHttpResponse); + var target = service.url.concat('references/', ref); + return this.$http.get(target) + .then(this.util.unwrapHttpResponse); } /** - * This methode is responsible to create a voucher object and it back - **/ - function getTransferRecord (cashAccountCurrency, amount, currency_id){ + * This method is responsible to create a voucher object and it back + */ + function getTransferRecord(cashAccountCurrency, amount, currencyId) { /** * The date field is set at the server side * @todo the date in timestamp type in the database */ var voucher = { - uuid : uuid(), - project_id : sessionService.project.id, - currency_id : currency_id, + project_id : Session.project.id, + currency_id : currencyId, amount : amount, description : generateTransferDescription(), - user_id : sessionService.user.id, - items : [] - }; - - var cashVoucherLine = { - uuid : uuid (), - account_id : cashAccountCurrency.account_id, - debit : 0, - credit : amount, - voucher_uuid : voucher.uuid + user_id : Session.user.id, + + // two lines (debit and credit) to be recorded in the database + items : [{ + account_id : cashAccountCurrency.account_id, + debit : 0, + credit : amount, + }, { + account_id : cashAccountCurrency.transfer_account_id, + debit : amount, + credit : 0, + }] }; - var transferVoucherLine = { - uuid : uuid (), - account_id : cashAccountCurrency.transfer_account_id, - debit : amount, - credit : 0, - voucher_uuid : voucher.uuid - }; - - voucher.items.push(cashVoucherLine); - voucher.items.push(transferVoucherLine); - return { voucher : voucher }; } /** - * This methode is responsible to generate a description for the transfer operation - * @private - **/ + * This method is responsible to generate a description for the transfer operation. + * @private + */ function generateTransferDescription (){ - return ['Transfer voucher', new Date().toISOString().slice(0, 10), sessionService.user.id].join('/'); + return 'Transfer Voucher/'.concat(new Date().toISOString().slice(0, 10), '/', Session.user.id); } } diff --git a/client/src/js/services/FiscalYearService.js b/client/src/js/services/FiscalYearService.js new file mode 100644 index 0000000000..96b138230b --- /dev/null +++ b/client/src/js/services/FiscalYearService.js @@ -0,0 +1,22 @@ +angular.module('bhima.services') +.service('FiscalService', FiscalService); + +FiscalService.$inject = ['PrototypeApiService']; + +/** + * Fiscal Service + * + * This service is responsible for loading the Fiscal Years and Periods, as well + * as providing metadata like period totals, opening balances and such. + */ +function FiscalService(PrototypeApiService) { + var service = this; + + // inherit from the PrototypeApiService + angular.extend(service, PrototypeApiService); + + // the service URL + service.url = '/fiscal/'; + + return service; +} diff --git a/client/src/js/services/PeriodService.js b/client/src/js/services/PeriodService.js new file mode 100644 index 0000000000..bcde448c60 --- /dev/null +++ b/client/src/js/services/PeriodService.js @@ -0,0 +1,14 @@ +angular.module('bhima.services') +.service('PeriodService', PeriodService); + +PeriodService.$inject = ['PrototypeApiService']; + +function PeriodService(PrototypeApiService) { + var service = this; + + // inherit methods from the + angular.extend(service, PrototypeApiService); + + + return service; +} diff --git a/client/src/js/services/PrototypeApiService.js b/client/src/js/services/PrototypeApiService.js new file mode 100644 index 0000000000..461d67b5da --- /dev/null +++ b/client/src/js/services/PrototypeApiService.js @@ -0,0 +1,164 @@ +angular.module('bhima.services') +.service('PrototypeApiService', PrototypeApiService); + +PrototypeApiService.$inject = ['$http', 'util']; + +/** + * @class PrototypeApiService + * + * @description + * This service is the parent/prototype of all API services throughout the + * application. It defines the basic methods to be implemented and parameters + * that are required for each. Full CRUD is implemented in this service, + * extending from a base url. + * + * Child services are expected to use angular.extend() to inherit the basic + * methods and properties from this service. + * + * @requires $http + * @requires util + */ +function PrototypeApiService($http, util) { + + /** bind the required $http and util services */ + this.$http = $http; + this.$util = util; + + // basic API methods + this.create = create; + this.read = read; + this.update = update; + this.delete = remove; + + /** + * @method read + * + * @description + * Sends an HTTP GET request to the url "/route" or "route/:id". If an id is + * provided, the id is appended to the base url before sending the request. + * Otherwise, the request is made against the base url. + * + * Optional parameters may be provided as the second parameter to be passed as + * query string parameters to $http. + * + * @param {Number|String|Null} id - the optional identifier of the URL route. + * @param {Object|Null} params - optional parameters to be passed to $http + * @returns {Promise} - the promise with the requested data + * + * @example + * // GETting data from the base /route/ + * service.read().then(function (data) { + * // data is an array of values + * }) + * + * // GETting data from the /route/:id + * service.read(id).then(function (data) { + * // data is typically an object here + * }); + * + * // GETting data with query string params + * // /route?limit=10&detailed=1 + * service.read(null, { limit : 10, detailed : 1 }) + * .then(function (data) { + * // data is typically an array here + * }); + */ + function read(id, parameters) { + + // default to empty object for paramters + parameters = parameters || {}; + + // append the id to the target + var target = this.url.concat(id || ''); + + // send the GET request + return this.$http.get(target, { params : parameters }) + .then(util.unwrapHttpResponse); + } + + /** + * @method update + * + * @description + * Sends an HTTP PUT request to the url `/route/:id` with properties to update in + * the database. The method removes any identifiers (id, uuid) if they exist + * on the object to avoid changing references in the database. + * + * @param {Number|String|Null} id - the optional identifier of the URL route. + * @param {Object|Null} data - the changed data to be updated in the database + * @returns {Promise} - the promise with the full changed object + * + * @example + * // PUT data to the url "/route/1" + * service.update(1, { name : "Hope" }).then(function (data) { + * // data is a JSON with the full record's properties + * }); + */ + function update(id, data) { + + // remove identifers before update command + delete data.id; + delete data.uuid; + + // append the id to the base url + var target = this.url.concat(id); + + // send the PUT request + return this.$http.put(target, data) + .then(util.unwrapHttpResponse); + } + + /** + * @method create + * + * @description + * Sends an HTTP POST request to the url `/route` with the record properties + * in the HTTP body. + * + * @param {Object|Null} data - the record data to be create in the database + * @returns {Promise} - the promise with the identifier from the database + * resolving to the created record identifier + * + * @example + * // POST data to the url "/route" + * service.create({ text : "Hello World!" }).then(function (data) { + * // data an object containing the identifier. Usually "id" or "uuid" + * }); + */ + function create(data) { + + // the target is the base URL + var target = this.url; + + // send the POST request + return this.$http.post(target, data) + .then(util.unwrapHttpResponse); + } + + /** + * @method delete + * + * @description + * Sends an HTTP DELETE request to the url "/route/:id" to delete an object + * from the database. The expected response is a `204 No Content` HTTP status + * code. + * + * @param {Number|String|Null} id - the identifier of the URL route. + * @returns {Promise} - the promise with the identifier from the database + * + * @example + * // POST data to the url "/route" + * service.create({ text : "Hello World!" }).then(function (data) { + * // data an object containing the identifier. Usually "id" or "uuid" + * }); + */ + function remove(id) { + + // append the id to the base url + var target = this.url.concat(id); + + // send the DELETE request + return this.$http.delete(target) + .then(util.unwrapHttpResponse); + } +} diff --git a/client/src/partials/cash/cash.html b/client/src/partials/cash/cash.html index 04468f867f..995e555bed 100644 --- a/client/src/partials/cash/cash.html +++ b/client/src/partials/cash/cash.html @@ -74,7 +74,6 @@ -