diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..2b0041b --- /dev/null +++ b/.babelrc @@ -0,0 +1,17 @@ +{ + "sourceMap": true, + "sourceRoot": "src", + "moduleIds": false, + "comments": false, + "compact": false, + "code": true, + "presets": [ + ["es2015", {"loose": true}], + "stage-1" + ], + "plugins": [ + "syntax-flow", + "transform-decorators-legacy", + "transform-flow-strip-types" + ] +} diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..aebb25e --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +content/dist +content/js +aurelia_project \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index e727666..92c9947 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,10 +5,272 @@ "es6": true }, "extends": "eslint:recommended", + "parser": "babel-eslint", "parserOptions": { + "sourceType": "module", "ecmaVersion": 2017 }, "rules": { + "accessor-pairs": "off", + "array-bracket-newline": "off", + "array-bracket-spacing": "off", + "array-callback-return": "off", + "array-element-newline": "off", + "arrow-body-style": "off", + "arrow-parens": "off", + "arrow-spacing": "off", + "block-scoped-var": "off", + "block-spacing": "off", + "brace-style": "off", + "callback-return": "off", + "camelcase": "off", + "capitalized-comments": "off", + "class-methods-use-this": "off", + "comma-dangle": "off", + "comma-spacing": "off", + "comma-style": "off", + "complexity": "off", + "computed-property-spacing": "off", + "consistent-return": "off", + "consistent-this": "off", + "constructor-super": "error", + "curly": "off", + "default-case": "off", + "dot-location": "off", + "dot-notation": "off", + "eol-last": "off", + "eqeqeq": "off", + "for-direction": "error", + "func-call-spacing": "off", + "func-name-matching": "off", + "func-names": "off", + "func-style": "off", + "function-paren-newline": "off", + "generator-star-spacing": "off", + "getter-return": "error", + "global-require": "off", + "guard-for-in": "off", + "handle-callback-err": "off", + "id-blacklist": "off", + "id-length": "off", + "id-match": "off", + "implicit-arrow-linebreak": "off", + "indent-legacy": "off", + "init-declarations": "off", + "jsx-quotes": "off", + "key-spacing": "off", + "keyword-spacing": "off", + "line-comment-position": "off", + "lines-around-comment": "off", + "lines-around-directive": "off", + "lines-between-class-members": "off", + "max-classes-per-file": "off", + "max-depth": "off", + "max-len": "off", + "max-lines": "off", + "max-lines-per-function": "off", + "max-nested-callbacks": "off", + "max-params": "off", + "max-statements": "off", + "max-statements-per-line": "off", + "multiline-comment-style": "off", + "multiline-ternary": "off", + "new-cap": "off", + "new-parens": "off", + "newline-after-var": "off", + "newline-before-return": "off", + "newline-per-chained-call": "off", + "no-alert": "off", + "no-array-constructor": "off", + "no-async-promise-executor": "off", + "no-await-in-loop": "off", + "no-bitwise": "off", + "no-buffer-constructor": "off", + "no-caller": "off", + "no-case-declarations": "error", + "no-catch-shadow": "off", + "no-class-assign": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-confusing-arrow": "off", + "no-console": "error", + "no-const-assign": "error", + "no-constant-condition": "error", + "no-continue": "off", + "no-control-regex": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-div-regex": "off", + "no-dupe-args": "error", + "no-dupe-class-members": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-duplicate-imports": "off", + "no-else-return": "off", + "no-empty": "error", + "no-empty-character-class": "error", + "no-empty-function": "off", + "no-empty-pattern": "error", + "no-eq-null": "off", + "no-eval": "off", + "no-ex-assign": "error", + "no-extend-native": "off", + "no-extra-bind": "off", + "no-extra-boolean-cast": "error", + "no-extra-label": "off", + "no-extra-parens": "off", + "no-extra-semi": "error", + "no-fallthrough": "error", + "no-floating-decimal": "off", + "no-func-assign": "error", + "no-global-assign": "error", + "no-implicit-coercion": "off", + "no-implicit-globals": "off", + "no-implied-eval": "off", + "no-inline-comments": "off", + "no-inner-declarations": "error", + "no-invalid-regexp": "error", + "no-invalid-this": "off", + "no-irregular-whitespace": "error", + "no-iterator": "off", + "no-label-var": "off", + "no-labels": "off", + "no-lone-blocks": "off", + "no-lonely-if": "off", + "no-loop-func": "off", + "no-magic-numbers": "off", + "no-misleading-character-class": "off", + "no-mixed-operators": "off", + "no-mixed-requires": "off", + "no-mixed-spaces-and-tabs": "error", + "no-multi-assign": "off", + "no-multi-spaces": "off", + "no-multi-str": "off", + "no-multiple-empty-lines": "off", + "no-native-reassign": "off", + "no-negated-condition": "off", + "no-negated-in-lhs": "off", + "no-nested-ternary": "off", + "no-new": "off", + "no-new-func": "off", + "no-new-object": "off", + "no-new-require": "off", + "no-new-symbol": "error", + "no-new-wrappers": "off", + "no-obj-calls": "error", + "no-octal": "error", + "no-octal-escape": "off", + "no-param-reassign": "off", + "no-path-concat": "off", + "no-plusplus": "off", + "no-process-env": "off", + "no-process-exit": "off", + "no-proto": "off", + "no-prototype-builtins": "off", + "no-redeclare": "error", + "no-regex-spaces": "error", + "no-restricted-globals": "off", + "no-restricted-imports": "off", + "no-restricted-modules": "off", + "no-restricted-properties": "off", + "no-restricted-syntax": "off", + "no-return-assign": "off", + "no-return-await": "off", + "no-script-url": "off", + "no-self-assign": "error", + "no-self-compare": "off", + "no-sequences": "off", + "no-shadow": "off", + "no-shadow-restricted-names": "off", + "no-spaced-func": "off", + "no-sparse-arrays": "error", + "no-sync": "off", + "no-tabs": "off", + "no-template-curly-in-string": "off", + "no-ternary": "off", + "no-this-before-super": "error", + "no-throw-literal": "off", + "no-trailing-spaces": "off", + "no-undef": "error", + "no-undef-init": "off", + "no-undefined": "off", + "no-underscore-dangle": "off", + "no-unexpected-multiline": "error", + "no-unmodified-loop-condition": "off", + "no-unneeded-ternary": "off", + "no-unreachable": "error", + "no-unsafe-finally": "error", + "no-unsafe-negation": "error", + "no-unused-expressions": "off", + "no-unused-labels": "error", + "no-unused-vars": "error", + "no-use-before-define": "off", + "no-useless-call": "off", + "no-useless-computed-key": "off", + "no-useless-concat": "off", + "no-useless-constructor": "off", + "no-useless-escape": "error", + "no-useless-rename": "off", + "no-useless-return": "off", + "no-var": "off", + "no-void": "off", + "no-warning-comments": "off", + "no-whitespace-before-property": "off", + "no-with": "off", + "nonblock-statement-body-position": "off", + "object-curly-newline": "off", + "object-curly-spacing": "off", + "object-property-newline": "off", + "object-shorthand": "off", + "one-var": "off", + "one-var-declaration-per-line": "off", + "operator-assignment": "off", + "operator-linebreak": "off", + "padded-blocks": "off", + "padding-line-between-statements": "off", + "prefer-arrow-callback": "off", + "prefer-const": "off", + "prefer-destructuring": "off", + "prefer-numeric-literals": "off", + "prefer-object-spread": "off", + "prefer-promise-reject-errors": "off", + "prefer-reflect": "off", + "prefer-rest-params": "off", + "prefer-spread": "off", + "prefer-template": "off", + "quote-props": "off", + "radix": "off", + "require-atomic-updates": "off", + "require-await": "off", + "require-jsdoc": "off", + "require-unicode-regexp": "off", + "require-yield": "error", + "rest-spread-spacing": "off", + "semi-spacing": "off", + "semi-style": "off", + "sort-imports": "off", + "sort-keys": "off", + "sort-vars": "off", + "space-before-blocks": "off", + "space-before-function-paren": "off", + "space-in-parens": "off", + "space-infix-ops": "off", + "space-unary-ops": "off", + "spaced-comment": "off", + "strict": "off", + "switch-colon-spacing": "off", + "symbol-description": "off", + "template-curly-spacing": "off", + "template-tag-spacing": "off", + "unicode-bom": "off", + "use-isnan": "error", + "valid-jsdoc": "off", + "valid-typeof": "error", + "vars-on-top": "off", + "wrap-iife": "off", + "wrap-regex": "off", + "yield-star-spacing": "off", + "yoda": "off", "indent": [ "error", 4 diff --git a/.gitignore b/.gitignore index e2a155f..66526a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules package-lock.json .DS_Store -content/dist/ \ No newline at end of file +content/dist \ No newline at end of file diff --git a/README.md b/README.md index 0333262..aa42888 100644 --- a/README.md +++ b/README.md @@ -6,31 +6,41 @@ To get started/setup: 1. Run `node -v` and ensure you have at least node v9.6.0 installed. 2. Run `npm install --dev` to install all the npm package dependencies. When installing in production omit the `--dev` flag. -3. Run `node app.js` this will startup the server, which will default to run on port 3000. This can be set to an explicit port by running `node app.js -p 80` which will run the app up on port 80. +3. Install `aurelia-cli` which is required to run the aurelia bits: `npm install aurelia-cli -g` +4. Install `gulp` which is required to run builds: `npm install -g gulp` +5. Run `gulp` from the root of the checked out repo. -## Scripts +## Gulp tasks -All scripts rely on local npm modules therefore run `npm install` before running the below scripts: +### `lint` -### `npm run watch` +Lints all js files. Check `.eslintrc.json` for the rules it uses when linting. -Will run the up the node server, listen on port 3000 and watch the following file types for changes. If a change is detected it will restart the server. +### `sass` -- *.js -- *.hbs -- *.scss +Compiles `content/scss/main.scss` to `content/css/main.css`. Simples. -### `npm run test` +### `server` -Will run all spec unit tests in jasmine. +Starts the node server, as setup in `app.js`, using nodemon. Watches the following files, and on change will re-run the server: -### `npm run lint` +- `app.js` +- `api/**/*.js` -Runs `eslint` in `./`. Note the three `.eslintrc.json` configs in: +### `start-au-cli` -- ./ -- ./content/js -- ./spec +Runs `au run` which is an aurelia-cli command, this in turns watches the `src` folder and will transcompile all js and html file changes into `/content/dist`. For more information on these tasks check out: + +- The `/aurelia_project` directory that holds the gulp tasks specific to aurelia. +- `aurelia-cli` documentation [here](https://aurelia.io/docs/build-systems/aurelia-cli/). + +### `watch-sass` + +Watches all `scss` files in `/content/scss` and executes the sass task (detailed above) on a file change. + +### `default` + +Runs all of the above, in parallel. ## FAQs diff --git a/app-state.js b/api/app-state.js similarity index 100% rename from app-state.js rename to api/app-state.js diff --git a/api/controllers/api-logger-controller.js b/api/controllers/api-logger-controller.js new file mode 100644 index 0000000..df091dd --- /dev/null +++ b/api/controllers/api-logger-controller.js @@ -0,0 +1,18 @@ +const BaseController = require("./base-controller"); + +module.exports = class APILoggerController extends BaseController { + async get(ctx) { + let data = ctx.session.apiCalls; + + if (!data) { + ctx.body = data; + return; + } + + let filteredData = data.filter(x => !x.uri.trim().toLowerCase().endsWith("/healthcheck")); + + let reversed = filteredData.reverse(); + + ctx.body = reversed; + } +}; \ No newline at end of file diff --git a/api/controllers/base-controller.js b/api/controllers/base-controller.js new file mode 100644 index 0000000..3846a86 --- /dev/null +++ b/api/controllers/base-controller.js @@ -0,0 +1,2 @@ +module.exports = class BaseController { +}; \ No newline at end of file diff --git a/controllers/commentary-controller.js b/api/controllers/commentary-controller.js similarity index 100% rename from controllers/commentary-controller.js rename to api/controllers/commentary-controller.js diff --git a/api/controllers/employee-controller.js b/api/controllers/employee-controller.js new file mode 100644 index 0000000..e615f48 --- /dev/null +++ b/api/controllers/employee-controller.js @@ -0,0 +1,194 @@ +const _ = require("lodash"); +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const ValidationParser = require("../services/validation-parser"); +const EmployeeUtils = require("../services/employee-utils"); +const EmployeeRevisionsQuery = require("../queries/employee-revisions-query"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class EmployeeController extends BaseController { + async get(ctx) { + let employerId = ctx.params.employerId; + let employeeId = ctx.params.employeeId; + let apiRoute = `/Employer/${employerId}/Employee/${employeeId}`; + let response = await apiWrapper.get(ctx, apiRoute); + let payInstructions = await apiWrapper.getAndExtractLinks(ctx, `/Employer/${employerId}/Employee/${employeeId}/PayInstructions`); + + let filteredPayInstructions = payInstructions.filter(pi => { + return pi.ObjectType !== "P45PayInstruction"; + }); + + let canAddANewPayInstruction = filteredPayInstructions.filter(pi => pi.EndDate).length === filteredPayInstructions.length; + let employee = EmployeeUtils.parseFromApi(response.Employee); + + ctx.body = Object.assign(employee, { + Id: employeeId, + PayInstructions: filteredPayInstructions, + GroupedPayInstructions: this.getNormalGroupedPayInstructions(filteredPayInstructions), + GroupedYTDPayInstructions: this.getYTDGroupedPayInstructions(filteredPayInstructions), + CanAddANewPayInstruction: filteredPayInstructions.length === 0 || canAddANewPayInstruction, + P45PayInstruction: this.getP45PayInstruction(payInstructions), + Revisions: await this.getRevisions(ctx, employerId, employeeId) + }); + } + + async delete(ctx) { + let employerId = ctx.params.employerId; + let employeeId = ctx.params.employeeId; + let apiRoute = `/Employer/${employerId}/Employee/${employeeId}`; + let response = await apiWrapper.delete(ctx, apiRoute); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Employee deleted", + type: "success" + } + }; + } + } + + async post(ctx) { + let employerId = ctx.params.employerId; + let body = ctx.request.body; + let response = null; + + if (body.Id) { + let url = `Employer/${employerId}/Employee/${body.Id}`; + + response = await apiWrapper.put(ctx, url, { Employee: EmployeeUtils.parse(body, employerId) }); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + employeeId: body.Id, + status: { + message: "Employee details saved", + type: "success" + } + }; + } + } + else { + let url = `Employer/${employerId}/Employees`; + + response = await apiWrapper.post(ctx, url, { Employee: EmployeeUtils.parse(body, employerId) }); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + let id = response.Link["@href"].split("/").slice(-1)[0]; + + ctx.body = { + employeeId: id, + status: { + message: "Employee details saved", + type: "success" + } + }; + } + } + } + + async deleteRevision(ctx) { + let employerId = ctx.params.employerId; + let employeeId = ctx.params.employeeId; + let effectiveDate = ctx.params.effectiveDate; + let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/${effectiveDate}`; + let response = await apiWrapper.delete(ctx, apiRoute); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Revision deleted", + type: "success" + } + }; + } + } + + async getRevisions(ctx, employerId, employeeId) { + let queryStr = JSON.stringify(EmployeeRevisionsQuery) + .replace("$$EmployerKey$$", employerId) + .replace("$$EmployeeKey$$", employeeId); + + let query = JSON.parse(queryStr); + + let revisions = await apiWrapper.query(ctx, query); + + return Array.from(revisions.EmployeeRevisions.Revisions.Revision); + } + + getP45PayInstruction(instructions) { + let p45Instruction = instructions.find(pi => { + return pi.ObjectType === "P45PayInstruction"; + }); + + return p45Instruction; + } + + getNormalGroupedPayInstructions(instructions) { + let filtered = instructions.filter(i => i.ObjectType.toLowerCase().indexOf("ytd") === -1); + let grouped = this.getGroupedPayInstructions(filtered); + + return this.getProjectedPayInstructions(grouped); + } + + getYTDGroupedPayInstructions(instructions) { + let filtered = instructions.filter(i => i.ObjectType.toLowerCase().indexOf("ytd") !== -1); + let grouped = this.getGroupedPayInstructions(filtered); + + return this.getProjectedPayInstructions(grouped); + } + + getGroupedPayInstructions(instructions) { + let groupedPayInstructions = _.groupBy(instructions, (pi) => { + return pi.ObjectType; + }); + + return groupedPayInstructions; + } + + getProjectedPayInstructions(groupedPayInstructions) { + let projectedPayInstructions = Object.keys(groupedPayInstructions).map(key => { + let instructions = groupedPayInstructions[key]; + let pi; + + if (key.trim().toLowerCase().indexOf("ytd") !== -1) { + pi = require(`../services/pay-instructions/year-to-date/${key}`); + } + else { + pi = require(`../services/pay-instructions/normal/${key}`); + } + + let instance = new pi(); + let name = instance.name; + + return { + InstructionType: key, + InstructionFriendlyName: name, + Instructions: instructions + }; + }); + + return projectedPayInstructions; + } +}; \ No newline at end of file diff --git a/api/controllers/employer-controller.js b/api/controllers/employer-controller.js new file mode 100644 index 0000000..f28137a --- /dev/null +++ b/api/controllers/employer-controller.js @@ -0,0 +1,190 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const EmployerService = require("../services/employer-service"); +const ValidationParser = require("../services/validation-parser"); +const EmployerUtils = require("../services/employer-utils"); +const EmployerRevisionsQuery = require("../queries/employer-revisions-query"); +const EmployeesQuery = require("../queries/employees-query"); + +let apiWrapper = new ApiWrapper(); +let employerService = new EmployerService(); + +module.exports = class EmployerController extends BaseController { + async get(ctx) { + let id = ctx.params.id; + let response = await apiWrapper.get(ctx, `Employer/${id}`); + let employer = response.Employer; + let paySchedules = await employerService.getPaySchedules(ctx, id); + let rtiTransactions = await apiWrapper.getAndExtractLinks(ctx, `Employer/${id}/RtiTransactions`); + let revisions = await this.getRevisions(ctx, id); + let pensions = await this.getPensions(ctx, employer, id); + let payCodes = await this.getPayCodes(ctx, id); + let norminalCodes = await this.getNorminalCodes(ctx, id); + let payRunCount = await this.getPayRunCount(paySchedules); + let eeQueryStr = JSON.stringify(EmployeesQuery).replace("$$EmployerKey$$", id); + let eeQuery = JSON.parse(eeQueryStr); + let employees = await apiWrapper.query(ctx, eeQuery); + + console.log(norminalCodes); + + if (employer.RuleExclusions) { + employer.RuleExclusions = employer.RuleExclusions.split(" "); + } + + ctx.body = Object.assign(employer, { + Id: id, + Employees: employees.EmployeesTable.Employees, + Pensions: pensions, + PaySchedules: paySchedules.PaySchedulesTable.PaySchedule, + PayRuns: payRunCount > 0, + RTITransactions: rtiTransactions, + Revisions: revisions, + PayCodes: payCodes, + NominalCodes: norminalCodes + }); + } + + async paySchedules(ctx) { + let id = ctx.params.id; + + let paySchedules = await employerService.getPaySchedules(ctx, id); + + ctx.body = paySchedules.PaySchedulesTable.PaySchedule; + } + + async rtiSubmissions(ctx) { + let id = ctx.params.id; + + let rtiTransactions = await apiWrapper.getAndExtractLinks(ctx, `Employer/${id}/RtiTransactions`); + + ctx.body = rtiTransactions; + } + + async post(ctx) { + let body = ctx.request.body; + + let parsedBody = EmployerUtils.parse(body); + let employerId = body.Id; + let response = null; + + if (employerId) { + response = await apiWrapper.put(ctx, `Employer/${employerId}`, { Employer: parsedBody }); + } + else { + response = await apiWrapper.post(ctx, "Employers", { Employer: parsedBody }); + } + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + if (!employerId) { + employerId = response.Link["@href"].split("/").slice(-1)[0]; + } + + ctx.body = { + employerId: employerId, + status: { + message: "Employer details saved", + type: "success" + } + }; + } + } + + async delete(ctx) { + let id = ctx.params.id; + let apiRoute = `/Employer/${id}`; + let response = await apiWrapper.delete(ctx, apiRoute); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Employer deleted", + type: "success" + } + }; + } + } + + async deleteRevision(ctx) { + let id = ctx.params.id; + let effectiveDate = ctx.params.effectiveDate; + let apiRoute = `/Employer/${id}/${effectiveDate}`; + let response = await apiWrapper.delete(ctx, apiRoute); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Revision deleted", + type: "success" + } + }; + } + } + + async getPensions(ctx, employer, employerId) { + let pensions = await apiWrapper.getAndExtractLinks(ctx, `Employer/${employerId}/Pensions`); + + let extendedPensions = pensions.map(pension => { + if (employer.AutoEnrolment && employer.AutoEnrolment.Pension) { + pension.UseForAutoEnrolment = employer.AutoEnrolment.Pension["@href"].endsWith(pension.Id); + } + else { + pension.UseForAutoEnrolment = false; + } + + return pension; + }); + + return extendedPensions; + } + + async getPayRunCount(schedules) { + let payRunCount = 0; + + if (schedules.PaySchedulesTable.PaySchedule) { + schedules.PaySchedulesTable.PaySchedule.forEach(ps => { + if (ps.PayRuns) { + payRunCount = payRunCount + ps.PayRuns.length; + } + }); + } + + return payRunCount; + } + + async getRevisions(ctx, employerId) { + let queryStr = JSON.stringify(EmployerRevisionsQuery).replace("$$EmployerKey$$", employerId); + + let query = JSON.parse(queryStr); + + let revisions = await apiWrapper.query(ctx, query); + + return Array.from(revisions.EmployerRevisions.Revisions.Revision); + } + + async getPayCodes(ctx, employerId) { + let payCodes = await apiWrapper.getAndExtractLinks(ctx, `Employer/${employerId}/PayCodes`); + + return payCodes; + } + + async getNorminalCodes(ctx, employerId) { + let norminalCodes = await apiWrapper.getAndExtractLinks(ctx, `Employer/${employerId}/NominalCodes`); + + return norminalCodes; + } +}; \ No newline at end of file diff --git a/api/controllers/employers-controller.js b/api/controllers/employers-controller.js new file mode 100644 index 0000000..d5fc641 --- /dev/null +++ b/api/controllers/employers-controller.js @@ -0,0 +1,14 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const EmployerQuery = require("../queries/employer-query"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class EmployersController extends BaseController { + async get(ctx) { + let queryResponse = await apiWrapper.query(ctx, EmployerQuery); + let employers = queryResponse.EmployerTable.Employer; + + ctx.body = employers; + } +}; \ No newline at end of file diff --git a/api/controllers/job-controller.js b/api/controllers/job-controller.js new file mode 100644 index 0000000..b85a1c2 --- /dev/null +++ b/api/controllers/job-controller.js @@ -0,0 +1,20 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class JobController extends BaseController { + async get(ctx) { + let jobId = ctx.params.jobId; + let type = ctx.params.type.trim().toLowerCase(); + let apiRoute = type === "payrun" ? `/Jobs/PayRuns/${jobId}/Info` : `/Jobs/RTI/${jobId}/Info`; + let response = await apiWrapper.get(ctx, apiRoute); + let body = response.JobInfo; + + body.Title = type === "payrun" ? "Pay Run Info" : "RTI Full Payment Submission"; + body.Progress = parseFloat(body.Progress) * 100; + body.Errors = body.Errors && body.Errors.Error.length > 0 ? body.Errors.Error : []; + + ctx.body = body; + } +}; \ No newline at end of file diff --git a/api/controllers/p45-instruction-controller.js b/api/controllers/p45-instruction-controller.js new file mode 100644 index 0000000..f14dead --- /dev/null +++ b/api/controllers/p45-instruction-controller.js @@ -0,0 +1,38 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const ValidationParser = require("../services/validation-parser"); +let apiWrapper = new ApiWrapper(); + +module.exports = class P45InstructionController extends BaseController { + async post(ctx) { + let employerId = ctx.params.employerId; + let employeeId = ctx.params.employeeId; + let body = ctx.request.body; + let response = null; + + if (body.Id) { + let apiRoute = `Employer/${employerId}/Employee/${employeeId}/PayInstruction/${body.Id}`; + + response = await apiWrapper.put(ctx, apiRoute, { P45PayInstruction: body }); + } + else { + let apiRoute = `Employer/${employerId}/Employee/${employeeId}/PayInstructions`; + + response = await apiWrapper.post(ctx, apiRoute, { P45PayInstruction: body }); + } + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "P45 Pay Instruction saved", + type: "success" + } + }; + } + } +}; \ No newline at end of file diff --git a/api/controllers/pay-code-controller.js b/api/controllers/pay-code-controller.js new file mode 100644 index 0000000..2009c16 --- /dev/null +++ b/api/controllers/pay-code-controller.js @@ -0,0 +1,73 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const ValidationParser = require("../services/validation-parser"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class PayCodeController extends BaseController { + async post(ctx) { + let employerId = ctx.params.employerId; + let body = ctx.request.body; + let formattedBody = this.formatBodyForApi(body); + let response = null; + + if (body.Id) { + let url = `Employer/${employerId}/PayCode/${body.Id}`; + + response = await apiWrapper.put(ctx, url, { PayCode: formattedBody }); + } + else { + let url = `Employer/${employerId}/PayCodes`; + + response = await apiWrapper.post(ctx, url, { PayCode: formattedBody }); + } + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pay code saved", + type: "success" + } + }; + } + } + + async delete(ctx) { + let employerId = ctx.params.employerId; + let id = ctx.params.id; + let apiRoute = `/Employer/${employerId}/PayCode/${id}`; + let response = await apiWrapper.delete(ctx, apiRoute); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pay code deleted", + type: "success" + } + }; + } + } + + formatBodyForApi(body) { + let copy = JSON.parse(JSON.stringify(body)); + + copy.Id = null; + copy.employerId = null; + copy.ObjectType = null; + copy.NominalCode = { + "@href": `/Employer/${body.employerId}/NominalCode/${body.NominalCode}` + }; + + return copy; + } +}; \ No newline at end of file diff --git a/api/controllers/pay-instruction-controller.js b/api/controllers/pay-instruction-controller.js new file mode 100644 index 0000000..2e81fc2 --- /dev/null +++ b/api/controllers/pay-instruction-controller.js @@ -0,0 +1,123 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const ValidationParser = require("../services/validation-parser"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class PayInstructionController extends BaseController { + async get(ctx) { + let employerId = ctx.params.employerId; + let employeeId = ctx.params.employeeId; + let id = ctx.params.id; + + let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstruction/${id}`; + + let response = await apiWrapper.get(ctx, apiRoute); + + let instructionType = Object.keys(response)[0]; + + let body = Object.assign(response[instructionType], { + Id: id, + EmployeeId: employeeId, + EmployerId: employerId, + InstructionType: instructionType, + }); + + let instructionTypeInstance = this.getInstructionInstance(instructionType); + let instructionTypeExtendedViewModel = await instructionTypeInstance.extendViewModel(ctx, body); + + ctx.body = instructionTypeExtendedViewModel; + } + + async getByType(ctx) { + let employerId = ctx.params.employerId; + let employeeId = ctx.params.employeeId; + let instructionType = ctx.params.instructionType; + + let body = { + EmployeeId: employeeId, + EmployerId: employerId, + InstructionType: instructionType + }; + + let instructionTypeInstance = this.getInstructionInstance(instructionType); + let instructionTypeExtendedViewModel = await instructionTypeInstance.extendViewModel(ctx, body); + + ctx.body = instructionTypeExtendedViewModel; + } + + async post(ctx) { + let employerId = ctx.params.employerId; + let employeeId = ctx.params.employeeId; + let body = ctx.request.body; + let instructionType = body.InstructionType; + let cleanBody = this.getInstructionInstance(instructionType).parseForApi(body); + let request = {}; + + request[instructionType] = cleanBody; + + let response = null; + + if (body.Id) { + let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstruction/${body.Id}`; + + response = await apiWrapper.put(ctx, apiRoute, request); + } + else { + let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstructions`; + + response = await apiWrapper.post(ctx, apiRoute, request); + } + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pay instruction saved", + type: "success" + } + }; + } + } + + async delete(ctx) { + let employerId = ctx.params.employerId; + let employeeId = ctx.params.employeeId; + let payInstructionId = ctx.params.id; + + let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstruction/${payInstructionId}`; + + let response = await apiWrapper.delete(ctx, apiRoute); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pay Instruction deleted", + type: "success" + } + }; + } + } + + getInstructionInstance(type) { + let Instruction; + + if (type.toLowerCase().indexOf("ytd") !== -1) { + Instruction = require(`../services/pay-instructions/year-to-date/${type}`); + } + else { + Instruction = require(`../services/pay-instructions/normal/${type}`); + } + + return new Instruction(); + } +}; \ No newline at end of file diff --git a/api/controllers/pay-instructions-controller.js b/api/controllers/pay-instructions-controller.js new file mode 100644 index 0000000..3b3a6c6 --- /dev/null +++ b/api/controllers/pay-instructions-controller.js @@ -0,0 +1,42 @@ +const BaseController = require("./base-controller"); +const path = require("path"); +const fs = require("fs"); + +module.exports = class PayInstructionsController extends BaseController { + async get(ctx) { + let normalFolder = path.join(__dirname, "../services/pay-instructions/normal"); + let ytdFolder = path.join(__dirname, "../services/pay-instructions/year-to-date"); + + let normalPayInstructions = this.getInstructions(normalFolder, "normal"); + let ytdPayInstructions = this.getInstructions(ytdFolder, "year-to-date"); + + let allPayInstructions = normalPayInstructions.concat(ytdPayInstructions); + + ctx.body = allPayInstructions; + } + + getInstructions(folder, group) { + let excludedFiles = [ + "base-absence-pay-instruction", + "base-absence-ytd-pay-instruction", + "base-ytd-pay-instruction" + ]; + + let files = fs.readdirSync(folder); + + return files.map(file => { + return file.replace(".js", ""); + }).filter(formattedFilename => { + return excludedFiles.indexOf(formattedFilename) === -1; + }).map(formattedFilename => { + let instruction = require(path.join(folder, formattedFilename)); + let instance = new instruction(); + + return { + name: instance.name, + type: formattedFilename, + group: group + }; + }); + } +}; \ No newline at end of file diff --git a/api/controllers/pay-run-controller.js b/api/controllers/pay-run-controller.js new file mode 100644 index 0000000..639be3a --- /dev/null +++ b/api/controllers/pay-run-controller.js @@ -0,0 +1,100 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const ValidationParser = require("../services/validation-parser"); +const PayRunUtils = require("../services/pay-run-utils"); +const PayRunG2NQuery = require("../queries/payrun-g2n-query"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class PayRunController extends BaseController { + async get(ctx) { + let employerId = ctx.params.employerId; + let payScheduleId = ctx.params.payScheduleId; + let payRunId = ctx.params.payRunId; + + let payRunRoute = `/Employer/${employerId}/PaySchedule/${payScheduleId}/PayRun/${payRunId}`; + + let queryStr = JSON.stringify(PayRunG2NQuery) + .replace("$$EmployerKey$$", employerId) + .replace("$$PayScheduleKey$$", payScheduleId) + .replace("$$PayRunKey$$", payRunId); + + let query = JSON.parse(queryStr); + let queryResult = await apiWrapper.query(ctx, query); + let employees = queryResult.PayrunG2N.PaySchedule.PayRun.Employees; + + let commentaries = await apiWrapper.get(ctx, payRunRoute + "/Commentaries"); + + let mappedEmployees = []; + + if (employees) { + mappedEmployees = employees.map(employee => { + if (commentaries && commentaries.LinkCollection.Links) { + let commentaryLink = commentaries.LinkCollection.Links.Link.find(commentary => { + return commentary["@href"].split("/")[4] === employee.Key; + }); + + employee.Commentary = commentaryLink; + } + + return employee; + }); + } + + let body = Object.assign(queryResult.PayrunG2N.PaySchedule.PayRun, { + Employees: mappedEmployees, + PaySchedule: queryResult.PayrunG2N.PaySchedule.Name, + PayFrequency: queryResult.PayrunG2N.PaySchedule.PayFrequency + }); + + ctx.body = body; + } + + async post(ctx) { + let employerId = ctx.params.employerId; + let body = ctx.request.body; + let cleanBody = PayRunUtils.parse(body, employerId); + let response = await apiWrapper.post(ctx, "jobs/payruns", { PayRunJobInstruction: cleanBody }); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + let jobId = response.Link["@href"].split("/")[3]; + + ctx.body = { + status: { + message: "Pay Run job created", + type: "success", + job: { + id: jobId, + type: "payrun" + } + } + }; + } + } + + async delete(ctx) { + let employerId = ctx.params.employerId; + let payScheduleId = ctx.params.payScheduleId; + let payRunId = ctx.params.payRunId; + let response = await apiWrapper.delete(ctx, `/Employer/${employerId}/PaySchedule/${payScheduleId}/PayRun/${payRunId}`); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pay Run deleted", + type: "success" + } + }; + } + } +}; \ No newline at end of file diff --git a/api/controllers/pay-runs-controller.js b/api/controllers/pay-runs-controller.js new file mode 100644 index 0000000..8eea860 --- /dev/null +++ b/api/controllers/pay-runs-controller.js @@ -0,0 +1,16 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const PayRunsQuery = require("../queries/payruns-query"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class PayRunsController extends BaseController { + async get(ctx) { + let employerId = ctx.params.employerId; + let queryStr = JSON.stringify(PayRunsQuery).replace("$$EmployerKey$$", employerId); + let query = JSON.parse(queryStr); + let paymentDates = await apiWrapper.query(ctx, query); + + ctx.body = paymentDates.PayRunsQuery.PayRuns; + } +}; \ No newline at end of file diff --git a/api/controllers/pay-schedule-controller.js b/api/controllers/pay-schedule-controller.js new file mode 100644 index 0000000..e41402b --- /dev/null +++ b/api/controllers/pay-schedule-controller.js @@ -0,0 +1,80 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const ValidationParser = require("../services/validation-parser"); +const NextPayRunDatesQuery = require("../queries/next-payrun-dates-query"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class PayScheduleController extends BaseController { + async getNextPayRun(ctx) { + let employerId = ctx.params.employerId; + let payScheduleId = ctx.params.payScheduleId; + + let queryStr = JSON.stringify(NextPayRunDatesQuery) + .replace("$$EmployerKey$$", employerId) + .replace("$$PayScheduleKey$$", payScheduleId); + + let query = JSON.parse(queryStr); + let queryResult = await apiWrapper.query(ctx, query); + + ctx.body = { + paymentDate: queryResult.NextPayRunDates.NextPayDay, + periodStart: queryResult.NextPayRunDates.NextPeriodStart, + periodEnd: queryResult.NextPayRunDates.NextPeriodEnd + }; + } + + async post(ctx) { + let employerId = ctx.params.employerId; + let body = ctx.request.body; + let response = null; + + if (body.Id) { + let url = `Employer/${employerId}/paySchedule/${body.Id}`; + + body.Id = null; + + response = await apiWrapper.put(ctx, url, { PaySchedule: body }); + } + else { + response = await apiWrapper.post(ctx, `Employer/${employerId}/PaySchedules`, { PaySchedule: body }); + } + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pay schedule saved", + type: "success" + } + }; + } + } + + async deleteSchedule(ctx) { + let employerId = ctx.params.employerId; + let payScheduleId = ctx.params.payScheduleId; + + let apiRoute = `/Employer/${employerId}/PaySchedule/${payScheduleId}`; + + let response = await apiWrapper.delete(ctx, apiRoute); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pay schedule deleted", + type: "success" + } + }; + } + } +}; \ No newline at end of file diff --git a/api/controllers/pay-schedules-controller.js b/api/controllers/pay-schedules-controller.js new file mode 100644 index 0000000..ef7d36b --- /dev/null +++ b/api/controllers/pay-schedules-controller.js @@ -0,0 +1,13 @@ +const BaseController = require("./base-controller"); +const EmployerService = require("../services/employer-service"); + +let employerService = new EmployerService(); + +module.exports = class PaySchedulesController extends BaseController { + async get(ctx) { + let employerId = ctx.params.employerId; + let paySchedules = await employerService.getPaySchedules(ctx, employerId); + + ctx.body = paySchedules.PaySchedulesTable.PaySchedule; + } +}; \ No newline at end of file diff --git a/controllers/pay-slip-controller.js b/api/controllers/pay-slip-controller.js similarity index 53% rename from controllers/pay-slip-controller.js rename to api/controllers/pay-slip-controller.js index 858e992..45322be 100644 --- a/controllers/pay-slip-controller.js +++ b/api/controllers/pay-slip-controller.js @@ -16,4 +16,18 @@ module.exports = class PaySlipController extends BaseController { ctx.type = "text/plain; charset=utf-8"; ctx.body = JSON.stringify(response.PayslipReport, null, 4); } + + async getPaySlipPdf(ctx) { + let employerId = ctx.params.employerId; + let code = ctx.params.code; + let taxYear = ctx.params.taxYear; + let paymentDate = ctx.params.paymentDate + let paySchedule = ctx.params.paySchedule + + let apiRoute = `/Report/PAYSLIP3/run?EmployerKey=${employerId}&TaxYear=${taxYear}&PayScheduleKey=${paySchedule}&paymentDate=${paymentDate}&EmployeeCodes=${code}&TransformDefinitionKey=Payslip-A5-Basic-Pdf`; + let response = await apiWrapper.getFile(ctx, apiRoute); + + ctx.set("Content-type", "application/pdf"); + ctx.body = response.body; + } }; \ No newline at end of file diff --git a/api/controllers/pension-controller.js b/api/controllers/pension-controller.js new file mode 100644 index 0000000..aa90d63 --- /dev/null +++ b/api/controllers/pension-controller.js @@ -0,0 +1,82 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const ValidationParser = require("../services/validation-parser"); +const PensionUtils = require("../services/pension-utils"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class PensionController extends BaseController { + async post(ctx) { + let employerId = ctx.params.employerId; + let body = ctx.request.body; + let response = null; + + if (body.Id) { + let url = `Employer/${employerId}/Pension/${body.Id}`; + + response = await apiWrapper.put(ctx, url, { Pension: PensionUtils.parse(body) }); + } + else { + let url = `Employer/${employerId}/Pensions`; + + response = await apiWrapper.post(ctx, url, { Pension: PensionUtils.parse(body) }); + } + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pension saved", + type: "success" + } + }; + } + } + + async patch(ctx) { + let id = ctx.params.id; + let employerId = ctx.params.employerId; + + await apiWrapper.patch(ctx, `/Employer/${employerId}`, { + Employer: { + AutoEnrolment: { + Pension: { + "@href": `/Employer/${employerId}/Pension/${id}` + } + } + } + }); + + ctx.body = { + status: { + message: "Pension defaulted for Auto Enrolment", + type: "success" + } + }; + } + + async delete(ctx) { + let employerId = ctx.params.employerId; + let id = ctx.params.id; + let apiRoute = `/Employer/${employerId}/Pension/${id}`; + let response = await apiWrapper.delete(ctx, apiRoute); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + ctx.body = { + status: { + message: "Pension deleted", + type: "success" + } + }; + } + } +}; \ No newline at end of file diff --git a/api/controllers/rti-controller.js b/api/controllers/rti-controller.js new file mode 100644 index 0000000..4455c84 --- /dev/null +++ b/api/controllers/rti-controller.js @@ -0,0 +1,64 @@ +const BaseController = require("./base-controller"); +const ApiWrapper = require("../services/api-wrapper"); +const ValidationParser = require("../services/validation-parser"); +const moment = require("moment"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class RtiController extends BaseController { + async get(ctx) { + let employerId = ctx.params.employerId; + let rtiTransactionId = ctx.params.rtiTransactionId; + + let apiRoute = `/Employer/${employerId}/RtiTransaction/${rtiTransactionId}`; + let response = await apiWrapper.get(ctx, apiRoute); + + ctx.type = "text/plain; charset=utf-8"; + ctx.body = JSON.stringify(response.RtiFpsTransaction, null, 4); + } + + async post(ctx) { + let employerId = ctx.params.employerId; + let body = ctx.request.body; + let apiRoute = `/Employer/${employerId}/PaySchedule/${body.PayScheduleId}/PayRun/${body.PayRunId}`; + let payRun = await apiWrapper.get(ctx, apiRoute); + + let fpsBody = { + RtiType: "FPS", + Generate: body.Generate, + Transmit: body.Transmit, + Employer: { + "@href": `/Employer/${employerId}` + }, + PaySchedule: payRun.PayRun.PaySchedule, + TaxYear: payRun.PayRun.TaxYear, + TaxMonth: payRun.PayRun.TaxPeriod, + PaymentDate: payRun.PayRun.PaymentDate, + Timestamp: moment().format("YYYY-MM-DDTHH:mm:ss"), + HoldingDate: body.HoldingDate, + LateReason: body.LateReason + }; + + let response = await apiWrapper.post(ctx, "/Jobs/rti", { RtiJobInstruction: fpsBody }); + + if (ValidationParser.containsErrors(response)) { + ctx.body = { + errors: ValidationParser.extractErrors(response) + }; + } + else { + let jobId = response.Link["@href"].split("/")[3]; + + ctx.body = { + status: { + message: "RTI submission job created", + type: "success", + job: { + id: jobId, + type: "rti" + } + } + }; + } + } +}; \ No newline at end of file diff --git a/controllers/setup-controller.js b/api/controllers/setup-controller.js similarity index 56% rename from controllers/setup-controller.js rename to api/controllers/setup-controller.js index c8422a4..c1d4e02 100644 --- a/controllers/setup-controller.js +++ b/api/controllers/setup-controller.js @@ -12,14 +12,22 @@ module.exports = class SetupController extends BaseController { body = JSON.parse(body); } else { - body = {}; + body = { + Environment: "", + ConsumerKey: "", + ConsumerSecret: "" + }; } - body.title = "Setup"; - - await ctx.render("setup", await this.getExtendedViewModel(ctx, body)); + ctx.body = body; } + async hasBeenSetup(ctx) { + ctx.body = { + hasBeenSetup: this.hasApiBeenSetup(ctx) + }; + } + async post(ctx) { let body = ctx.request.body; let stringifiedBody = JSON.stringify(body); @@ -31,6 +39,15 @@ module.exports = class SetupController extends BaseController { httpOnly: false }); - await ctx.redirect("/employer"); + ctx.body = { + valid: true + }; } + + hasApiBeenSetup(ctx) { + let cookie = ctx.cookies.get(SetupController.cookieKey); + let hasBeenSetup = cookie !== undefined && cookie !== null; + + return hasBeenSetup; + } }; \ No newline at end of file diff --git a/api/controllers/version-controller.js b/api/controllers/version-controller.js new file mode 100644 index 0000000..774af99 --- /dev/null +++ b/api/controllers/version-controller.js @@ -0,0 +1,23 @@ +const BaseController = require("./base-controller"); +const SetupController = require("./setup-controller"); +const PackageJson = require("../../package.json"); +const ApiWrapper = require("../services/api-wrapper"); + +let apiWrapper = new ApiWrapper(); +let setupController = new SetupController(); + +module.exports = class VersionController extends BaseController { + async get(ctx) { + if (!setupController.hasApiBeenSetup(ctx)) { + ctx.body = {}; + return; + } + + let healthCheckResponse = await apiWrapper.get(ctx, "/Healthcheck"); + + ctx.body = { + version: PackageJson.version, + apiVersion: healthCheckResponse.HealthCheck.Version + }; + } +}; \ No newline at end of file diff --git a/models/PayInstructionType.js b/api/models/PayInstructionType.js similarity index 100% rename from models/PayInstructionType.js rename to api/models/PayInstructionType.js diff --git a/api/queries/employee-revisions-query.js b/api/queries/employee-revisions-query.js new file mode 100644 index 0000000..9a46e24 --- /dev/null +++ b/api/queries/employee-revisions-query.js @@ -0,0 +1,45 @@ +module.exports = { + "Query": { + "RootNodeName": "EmployeeRevisions", + "Variables": { + "Variable": [ + { + "@Name": "[EmployerKey]", + "@Value": "$$EmployerKey$$" + }, + { + "@Name": "[EmployeeKey]", + "@Value": "$$EmployeeKey$$" + } + ] + }, + "Groups": { + "Group": [ + { + "@GroupName": "Revisions", + "@ItemName": "Revision", + "@Selector": "/Employer/[EmployerKey]/Employee/[EmployeeKey]/Revisions", + "Output": [ + { + "@xsi:type": "RenderProperty", + "@Name": "EffectiveDate", + "@Property": "EffectiveDate", + "@Format": "yyyy-MM-dd" + }, + { + "@xsi:type": "RenderProperty", + "@Name": "Revision", + "@Property": "Revision" + } + ], + "Order": [ + { + "@xsi:type": "Descending", + "@Property": "Revision" + } + ] + } + ] + } + } +}; \ No newline at end of file diff --git a/api/queries/employees-query.js b/api/queries/employees-query.js new file mode 100644 index 0000000..28100a9 --- /dev/null +++ b/api/queries/employees-query.js @@ -0,0 +1,49 @@ +module.exports = { + "Query": { + "RootNodeName": "EmployeesTable", + "Groups": { + "Group": [ + { + "@ItemName": "Employees", + "@Selector": "/Employer/$$EmployerKey$$/Employees", + "@UniqueKeyVariable": "[EmployeeKey]", + "Output": [ + { + "@xsi:type": "RenderArrayHint" + }, + { + "@xsi:type": "RenderValue", + "@Name": "Key", + "@Value": "[EmployeeKey]" + }, + { + "@xsi:type": "RenderProperty", + "@Name": "Title", + "@Property": "Title" + }, + { + "@xsi:type": "RenderProperty", + "@Name": "Firstname", + "@Property": "FirstName" + }, + { + "@xsi:type": "RenderProperty", + "@Name": "Lastname", + "@Property": "LastName" + }, + { + "@xsi:type": "RenderProperty", + "@Name": "Initials", + "@Property": "Initials" + }, + { + "@xsi:type": "RenderProperty", + "@Name": "Code", + "@Property": "Code" + } + ] + } + ] + } + } +}; \ No newline at end of file diff --git a/queries/employer-query.js b/api/queries/employer-query.js similarity index 100% rename from queries/employer-query.js rename to api/queries/employer-query.js diff --git a/queries/employer-revisions-query.js b/api/queries/employer-revisions-query.js similarity index 100% rename from queries/employer-revisions-query.js rename to api/queries/employer-revisions-query.js diff --git a/queries/next-payrun-dates-query.js b/api/queries/next-payrun-dates-query.js similarity index 100% rename from queries/next-payrun-dates-query.js rename to api/queries/next-payrun-dates-query.js diff --git a/queries/pay-schedules-query.js b/api/queries/pay-schedules-query.js similarity index 100% rename from queries/pay-schedules-query.js rename to api/queries/pay-schedules-query.js diff --git a/queries/payrun-g2n-query.js b/api/queries/payrun-g2n-query.js similarity index 100% rename from queries/payrun-g2n-query.js rename to api/queries/payrun-g2n-query.js diff --git a/queries/payruns-query.js b/api/queries/payruns-query.js similarity index 100% rename from queries/payruns-query.js rename to api/queries/payruns-query.js diff --git a/api/routes.js b/api/routes.js new file mode 100644 index 0000000..f8f63d7 --- /dev/null +++ b/api/routes.js @@ -0,0 +1,129 @@ +const router = require("koa-router")(); +const EmployerController = require("./controllers/employer-controller"); +const EmployersController = require("./controllers/employers-controller"); +const EmployeeController = require("./controllers/employee-controller"); +const PayScheduleController = require("./controllers/pay-schedule-controller"); +const PaySchedulesController = require("./controllers/pay-schedules-controller"); +const PayInstructionController = require("./controllers/pay-instruction-controller"); +const PayInstructionsController = require("./controllers/pay-instructions-controller"); +const PayRunController = require("./controllers/pay-run-controller"); +const PayRunsController = require("./controllers/pay-runs-controller"); +const CommentaryController = require("./controllers/commentary-controller"); +const PaySlipController = require("./controllers/pay-slip-controller"); +const JobController = require("./controllers/job-controller"); +const RTIController = require("./controllers/rti-controller"); +const APILoggerController = require("./controllers/api-logger-controller"); +const PensionController = require("./controllers/pension-controller"); +const PayCodeController = require("./controllers/pay-code-controller"); +const P45InstructionController = require("./controllers/p45-instruction-controller"); +const SetupController = require("./controllers/setup-controller"); +const VersionController = require("./controllers/version-controller"); + +let employerController = new EmployerController(); +let employersController = new EmployersController(); +let employeeController = new EmployeeController(); +let payScheduleController = new PayScheduleController(); +let paySchedulesController = new PaySchedulesController(); +let payInstructionController = new PayInstructionController(); +let payInstructionsController = new PayInstructionsController(); +let payRunController = new PayRunController(); +let payRunsController = new PayRunsController(); +let commentaryController = new CommentaryController(); +let paySlipController = new PaySlipController(); +let jobController = new JobController(); +let rtiController = new RTIController(); +let apiLoggerController = new APILoggerController(); +let pensionController = new PensionController(); +let payCodeController = new PayCodeController(); +let p45InstructionController = new P45InstructionController(); +let setupController = new SetupController(); +let versionController = new VersionController(); + +router + // root/get started + .get("/", async ctx => { + await ctx.render("aurelia"); + }) + + // version + .get("/api/version", async ctx => await versionController.get(ctx)) + + // setup + .get("/api/has-been-setup", async ctx => await setupController.hasBeenSetup(ctx)) + .get("/api/setup", async ctx => await setupController.get(ctx)) + .post("/api/setup", async ctx => await setupController.post(ctx)) + + // api calls + .get("/api/api-calls", async ctx => await apiLoggerController.get(ctx)) + + // employers + .get("/api/employers", async ctx => await employersController.get(ctx)) + + // employer + .get("/api/employer/:id", async ctx => await employerController.get(ctx)) + .get("/api/employer/:id/pay-schedules", async ctx => await employerController.paySchedules(ctx)) + .get("/api/employer/:id/rti-submissions", async ctx => await employerController.rtiSubmissions(ctx)) + .post("/api/employer", async ctx => await employerController.post(ctx)) + .delete("/api/employer/:id", async ctx => await employerController.delete(ctx)) + .delete("/api/employer/:id/revision/:effectiveDate", async ctx => await employerController.deleteRevision(ctx)) + + // pay schedules + .get("/api/employer/:employerId/pay-schedules", async ctx => await paySchedulesController.get(ctx)) + + // pay schedule + .get("/api/employer/:employerId/paySchedule/:payScheduleId/next-pay-run", async ctx => await payScheduleController.getNextPayRun(ctx)) + .post("/api/employer/:employerId/paySchedule", async ctx => await payScheduleController.post(ctx)) + .post("/api/employer/:employerId/paySchedule/:payScheduleId/delete", async ctx => await payScheduleController.deleteSchedule(ctx)) + + // job + .get("/api/job/:jobId/:type", async ctx => await jobController.get(ctx)) + + // pension + .post("/api/employer/:employerId/pension", async ctx => await pensionController.post(ctx)) + .patch("/api/employer/:employerId/pension/:id", async ctx => await pensionController.patch(ctx)) + .delete("/api/employer/:employerId/pension/:id", async ctx => await pensionController.delete(ctx)) + + // employee + .get("/api/employer/:employerId/employee/:employeeId", async ctx => await employeeController.get(ctx)) + .post("/api/employer/:employerId/employee", async ctx => await employeeController.post(ctx)) + .delete("/api/employer/:employerId/employee/:employeeId", async ctx => await employeeController.delete(ctx)) + .delete("/api/employer/:employerId/employee/:employeeId/revision/:effectiveDate", async ctx => await employeeController.deleteRevision(ctx)) + + // pay instruction + .get("/api/employer/:employerId/employee/:employeeId/payInstruction/:id", async ctx => payInstructionController.get(ctx)) + .get("/api/employer/:employerId/employee/:employeeId/:instructionType", async ctx => payInstructionController.getByType(ctx)) + .post("/api/employer/:employerId/employee/:employeeId/payInstruction", async ctx => payInstructionController.post(ctx)) + .delete("/api/employer/:employerId/employee/:employeeId/payInstruction/:id", async ctx => payInstructionController.delete(ctx)) + + // pay instructions + .get("/api/pay-instructions", async ctx => payInstructionsController.get(ctx)) + + // pay run + .post("/api/employer/:employerId/payRun", async ctx => await payRunController.post(ctx)) + .get("/api/employer/:employerId/paySchedule/:payScheduleId/payRun/:payRunId", async ctx => await payRunController.get(ctx)) + .delete("/api/employer/:employerId/paySchedule/:payScheduleId/payRun/:payRunId", async ctx => await payRunController.delete(ctx)) + + // pay runs + .get("/api/employer/:employerId/payRuns", async ctx => await payRunsController.get(ctx)) + + // comentary + .get("/api/employer/:employerId/employee/:employeeId/commentary/:commentaryId", async ctx => await commentaryController.getCommentary(ctx)) + + // pay slip + .get("/api/employer/:employerId/employee/:employeeId/paySlipData/:code/:taxPeriod/:taxYear", async ctx => await paySlipController.getPaySlipData(ctx)) + .get("/api/employer/:employerId/employee/:employeeId/paySlipPdf/:code/:taxPeriod/:taxYear", async ctx => await paySlipController.getPaySlipPdf(ctx)) + + // rti transaction + .get("/api/employer/:employerId/rtiTransaction/:rtiTransactionId", async ctx => await rtiController.get(ctx)) + .post("/api/employer/:employerId/rtiTransaction", async ctx => await rtiController.post(ctx)) + + // p45 pay instruction + .post("/api/employer/:employerId/Employee/:employeeId/P45Instruction", async ctx => await p45InstructionController.post(ctx)) + + // pay codes + .post("/api/employer/:employerId/payCode", async ctx => await payCodeController.post(ctx)) + .patch("/api/employer/:employerId/payCode/:id", async ctx => await payCodeController.patch(ctx)) + .delete("/api/employer/:employerId/payCode/:id", async ctx => await payCodeController.delete(ctx)) +; + +module.exports = router.routes(); \ No newline at end of file diff --git a/services/api-logger.js b/api/services/api-logger.js similarity index 81% rename from services/api-logger.js rename to api/services/api-logger.js index b3a943e..e020583 100644 --- a/services/api-logger.js +++ b/api/services/api-logger.js @@ -1,5 +1,3 @@ -const Constants = require("../Constants"); - module.exports = class APILogger { static get context() { return this._context; @@ -17,17 +15,23 @@ module.exports = class APILogger { } if (type.trim().toLowerCase() === "request") { + let relativeUri = call.uri.trim().toLowerCase() + .replace("https://api.test.payrun.io/", "") + .replace("https://api.payrun.io/", ""); + + let body = call.body ? this.formatForHtml(JSON.stringify(JSON.parse(call.body), null, 4)) : ""; + calls.push({ id: call.debugId, method: call.method, uri: call.uri, - relativeUri: call.uri.trim().toLowerCase().replace(Constants.apiUrl, ""), + relativeUri: relativeUri, headers: { Authorization: call.headers.Authorization, Accept: call.headers.accept }, hasRequestBody: call.body && call.method === "POST", - requestBody: call.body ? this.formatForHtml(JSON.stringify(JSON.parse(call.body), null, 4)) : "" + requestBody: call.body ? `-d ${body}` : "" }); } else { diff --git a/services/api-wrapper.js b/api/services/api-wrapper.js similarity index 97% rename from services/api-wrapper.js rename to api/services/api-wrapper.js index c54fb61..5766113 100644 --- a/services/api-wrapper.js +++ b/api/services/api-wrapper.js @@ -114,13 +114,14 @@ module.exports = class APIWrapper { } getOptions(ctx, relativeUrl, method) { - let ck = ctx.cookies.get("setupCookieKey"); + let setupCookie = ctx.cookies.get("setupCookieKey"); - if (!ck) { + if (!setupCookie) { return; } - let setup = JSON.parse(ck); + let setup = JSON.parse(setupCookie); + let oauth = OAuth({ consumer: { key: setup.ConsumerKey, diff --git a/services/employee-utils.js b/api/services/employee-utils.js similarity index 67% rename from services/employee-utils.js rename to api/services/employee-utils.js index 4160845..74ef03a 100644 --- a/services/employee-utils.js +++ b/api/services/employee-utils.js @@ -1,16 +1,15 @@ -const FormUtils = require("./form-utils"); - module.exports = class EmployeeUtils { static parse(employee, employerId) { let copy = JSON.parse(JSON.stringify(employee)); - copy.IsAgencyWorker = FormUtils.checkboxToBool(copy.IsAgencyWorker); - copy.EEACitizen = FormUtils.checkboxToBool(copy.EEACitizen); - copy.EPM6 = FormUtils.checkboxToBool(copy.EPM6); - copy.PaymentToANonIndividual = FormUtils.checkboxToBool(copy.PaymentToANonIndividual); - copy.IrregularEmployment = FormUtils.checkboxToBool(copy.IrregularEmployment); - copy.OnStrike = FormUtils.checkboxToBool(copy.OnStrike); - copy.Deactivated = FormUtils.checkboxToBool(copy.Deactivated); + copy.Id = null; + copy.EmployerId = null; + copy.PayInstructions = null; + copy.GroupedPayInstructions = null; + copy.CanAddANewPayInstruction = null; + copy.GroupedYTDPayInstructions = null; + copy.P45PayInstruction = null; + copy.Revisions = null; if (copy.PaySchedule) { copy.PaySchedule = { @@ -71,6 +70,24 @@ module.exports = class EmployeeUtils { copy.PaySchedule = id; } + if (copy.WorkingWeek) { + if (!Array.isArray(copy.WorkingWeek)) { + copy.WorkingWeek = copy.WorkingWeek.split(" "); + } + } + + if (copy.NicLiability) { + if (!Array.isArray(copy.NicLiability)) { + copy.NicLiability = copy.NicLiability.split(" "); + } + } + + if (copy.RuleExclusions) { + if (!Array.isArray(copy.RuleExclusions)) { + copy.RuleExclusions = copy.RuleExclusions.split(" "); + } + } + return copy; } }; \ No newline at end of file diff --git a/api/services/employer-service.js b/api/services/employer-service.js new file mode 100644 index 0000000..fd3c606 --- /dev/null +++ b/api/services/employer-service.js @@ -0,0 +1,12 @@ +const ApiWrapper = require("./api-wrapper"); +const PaySchedulesQuery = require("../queries/pay-schedules-query"); + +const apiWrapper = new ApiWrapper(); + +module.exports = class EmployerService { + async getPaySchedules(ctx, employerId) { + let queryStr = JSON.stringify(PaySchedulesQuery).replace("$$EmployerKey$$", employerId); + let query = JSON.parse(queryStr); + return await apiWrapper.query(ctx, query); + } +}; \ No newline at end of file diff --git a/services/employer-utils.js b/api/services/employer-utils.js similarity index 54% rename from services/employer-utils.js rename to api/services/employer-utils.js index a1c1069..5803087 100644 --- a/services/employer-utils.js +++ b/api/services/employer-utils.js @@ -2,8 +2,15 @@ module.exports = class EmployerUtils { static parse(employer) { let copy = JSON.parse(JSON.stringify(employer)); - copy.ClaimEmploymentAllowance = (employer.ClaimEmploymentAllowance && employer.ClaimEmploymentAllowance.toLowerCase() === "on"); - copy.ClaimSmallEmployerRelief = (employer.ClaimSmallEmployerRelief && employer.ClaimSmallEmployerRelief.toLowerCase() === "on"); + copy.Id = null; + copy.Employees = null; + copy.Pensions = null; + copy.PaySchedules = null; + copy.PayRuns = null; + copy.RTITransactions = null; + copy.Revisions = null; + copy.PayCodes = null; + copy.NorminalCodes = null; if (copy.RuleExclusions) { copy.RuleExclusions = employer.RuleExclusions.join(" "); diff --git a/services/form-utils.js b/api/services/form-utils.js similarity index 100% rename from services/form-utils.js rename to api/services/form-utils.js diff --git a/api/services/pay-instructions/base-instruction.js b/api/services/pay-instructions/base-instruction.js new file mode 100644 index 0000000..371d26c --- /dev/null +++ b/api/services/pay-instructions/base-instruction.js @@ -0,0 +1,32 @@ +module.exports = class BaseInstruction { + get name() { + throw Error("get name() needs implementing against each instruction"); + } + + async extendViewModel(ctx, vm) { + // override this to extend the passed in view model with instruction type specific properties. + vm.Name = this.name; + + return vm; + } + + parseForApi(body) { + let copy = JSON.parse(JSON.stringify(body)); + + // clear out utility properties as otherwise the api will return an error as they are unexpected. + copy.Id = null; + copy.EmployeeId = null; + copy.MinStartDate = null; + copy.InstructionType = null; + copy.EmployerId = null; + copy.Name = null; + + // reorder properties so we always have the StartDate, EndDate and Description at the beginning of the + // list, as required by the api. + return Object.assign({ + StartDate: copy.StartDate, + EndDate: copy.EndDate, + Description: copy.Description + }, copy); + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/AoePayInstruction.js b/api/services/pay-instructions/normal/AoePayInstruction.js new file mode 100644 index 0000000..cbb1733 --- /dev/null +++ b/api/services/pay-instructions/normal/AoePayInstruction.js @@ -0,0 +1,31 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class AoePayInstruction extends BaseInstruction { + get name() { + return "Attachment of Earnings"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + CaseNumber: cleanBody.CaseNumber, + AoeType: cleanBody.AoeType, + IssueDate: cleanBody.IssueDate, + StopDate: cleanBody.StopDate, + TotalToPay: cleanBody.TotalToPay, + PreviousPayments: cleanBody.PreviousPayments, + PreviousArrears: cleanBody.PreviousArrears, + ClaimAdminFee: cleanBody.ClaimAdminFee, + ProtectedEarningsAmount: cleanBody.ProtectedEarningsAmount, + DeductionAmount: cleanBody.DeductionAmount, + ProtectedEarningsPercentage: cleanBody.ProtectedEarningsPercentage, + DeductionPercentage: cleanBody.DeductionPercentage + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/BenefitPayInstruction.js b/api/services/pay-instructions/normal/BenefitPayInstruction.js new file mode 100644 index 0000000..5764f4f --- /dev/null +++ b/api/services/pay-instructions/normal/BenefitPayInstruction.js @@ -0,0 +1,25 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class BenefitPayInstruction extends BaseInstruction { + get name() { + return "Benefit"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + Code: cleanBody.Code, + TotalCost: cleanBody.TotalCost, + EmployeeContribution: cleanBody.EmployeeContribution, + CashEquivalent: cleanBody.CashEquivalent, + AccountingMethod: cleanBody.AccountingMethod, + BenefitEndDate: cleanBody.BenefitEndDate + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/NiAdjustmentPayInstruction.js b/api/services/pay-instructions/normal/NiAdjustmentPayInstruction.js new file mode 100644 index 0000000..20ae637 --- /dev/null +++ b/api/services/pay-instructions/normal/NiAdjustmentPayInstruction.js @@ -0,0 +1,42 @@ +const NiPayInstruction = require("./NiPayInstruction"); + +module.exports = class NiAdjustmentPayInstruction extends NiPayInstruction { + get name() { + return "NI Adjustment"; + } + + async extendViewModel(ctx, vm) { + let extendedViewModel = await super.extendViewModel(ctx, vm); + + extendedViewModel.NiLetter = "A"; + extendedViewModel.TaxYear = "2015"; + extendedViewModel.DirCalculationMethod = "Off"; + + return extendedViewModel; + } + + parseForApi(body) { + let copy = JSON.parse(JSON.stringify(body)); + + copy = Object.assign({ + Periods: copy.Periods, + DirCalculationMethod: copy.DirCalculationMethod + }, copy); + + let cleanBody = super.parseForApi(copy); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + DirCalculationMethod: cleanBody.DirCalculationMethod, + NiLetter: cleanBody.NiLetter, + + Periods: cleanBody.Periods, + TaxYear: cleanBody.TaxYear, + Reason: cleanBody.Reason + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/NiPayInstruction.js b/api/services/pay-instructions/normal/NiPayInstruction.js new file mode 100644 index 0000000..16bafe3 --- /dev/null +++ b/api/services/pay-instructions/normal/NiPayInstruction.js @@ -0,0 +1,21 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class NiPayInstruction extends BaseInstruction { + get name() { + return "National Insurance"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + DirCalculationMethod: cleanBody.DirCalculationMethod, + NiLetter: cleanBody.NiLetter + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/PensionPayInstruction.js b/api/services/pay-instructions/normal/PensionPayInstruction.js new file mode 100644 index 0000000..d5cfb8b --- /dev/null +++ b/api/services/pay-instructions/normal/PensionPayInstruction.js @@ -0,0 +1,53 @@ +const BaseInstruction = require("../base-instruction"); +const ApiWrapper = require("../../api-wrapper"); + +let apiWrapper = new ApiWrapper(); + +module.exports = class PensionPayInstruction extends BaseInstruction { + get name() { + return "Pension"; + } + + async extendViewModel(ctx, vm) { + let extendedViewModel = await super.extendViewModel(ctx, vm); + let pensions = await apiWrapper.getAndExtractLinks(ctx, `Employer/${vm.EmployerId}/Pensions`); + + extendedViewModel.Pensions = pensions.map(pension => { + return { + Id: pension.Id, + Name: `${pension.ProviderName} - ${pension.SchemeName}` + }; + }); + + return extendedViewModel; + } + + parseForApi(body) { + let employerId = body.EmployerId; + let cleanBody = super.parseForApi(body); + + cleanBody.SalarySacrifice = (cleanBody.SalarySacrifice !== undefined && cleanBody.SalarySacrifice !== null && cleanBody.SalarySacrifice.toLowerCase() === "on"); + cleanBody.Pension = { + "@href": `/Employer/${employerId}/Pension/${body.Pension}` + }; + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + Code: cleanBody.Code, + EmployeeContributionCash: cleanBody.EmployeeContributionCash, + EmployerContributionCash: cleanBody.EmployerContributionCash, + EmployeeContributionPercent: cleanBody.EmployeeContributionPercent, + EmployerContributionPercent: cleanBody.EmployerContributionPercent, + AdditionalVoluntaryContributionCash: cleanBody.AdditionalVoluntaryContributionCash, + AdditionalVoluntaryContributionPercent: cleanBody.AdditionalVoluntaryContributionPercent, + LowerThreshold: cleanBody.LowerThreshold, + UpperThreshold: cleanBody.UpperThreshold, + SalarySacrifice: cleanBody.SalarySacrifice, + TaxationMethod: cleanBody.TaxationMethod, + ProRataMethod: cleanBody.ProRataMethod, + Pension: cleanBody.Pension + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/PrimitivePayInstruction.js b/api/services/pay-instructions/normal/PrimitivePayInstruction.js new file mode 100644 index 0000000..8ab03be --- /dev/null +++ b/api/services/pay-instructions/normal/PrimitivePayInstruction.js @@ -0,0 +1,21 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class PrimitivePayInstruction extends BaseInstruction { + get name() { + return "Primitive"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + Code: cleanBody.Code, + Value: cleanBody.Value + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/RatePayInstruction.js b/api/services/pay-instructions/normal/RatePayInstruction.js new file mode 100644 index 0000000..f4d5f10 --- /dev/null +++ b/api/services/pay-instructions/normal/RatePayInstruction.js @@ -0,0 +1,34 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class RatePayInstruction extends BaseInstruction { + get name() { + return "Rate"; + } + + parseForApi(body) { + let copy = JSON.parse(JSON.stringify(body)); + + copy = Object.assign({ + Rate: copy.Rate, + RateUoM: copy.RateUoM, + Units: copy.Units + }, copy); + + copy.Code = null; + + let cleanBody = super.parseForApi(copy); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + Code: cleanBody.Code, + Rate: cleanBody.Rate, + RateUoM: cleanBody.RateUoM, + Units: cleanBody.Units, + RoundingOption: cleanBody.RoundingOption + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/SalaryPayInstruction.js b/api/services/pay-instructions/normal/SalaryPayInstruction.js new file mode 100644 index 0000000..7969b17 --- /dev/null +++ b/api/services/pay-instructions/normal/SalaryPayInstruction.js @@ -0,0 +1,22 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class SalaryPayInstruction extends BaseInstruction { + get name() { + return "Salary"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + AnnualSalary: cleanBody.AnnualSalary, + ProRataMethod: cleanBody.ProRataMethod, + RoundingOption: cleanBody.RoundingOption + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/ShppPayInstruction.js b/api/services/pay-instructions/normal/ShppPayInstruction.js new file mode 100644 index 0000000..372ad90 --- /dev/null +++ b/api/services/pay-instructions/normal/ShppPayInstruction.js @@ -0,0 +1,30 @@ +const AbsencePayInstruction = require("./base-absence-pay-instruction"); + +module.exports = class ShppPayInstruction extends AbsencePayInstruction { + get name() { + return "Shared Parental Leave"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + AbsenceStart: cleanBody.AbsenceStart, + AbsenceEnd: cleanBody.AbsenceEnd, + StatutoryOffset: cleanBody.StatutoryOffset, + + AverageWeeklyEarningOverride: cleanBody.AverageWeeklyEarningOverride, + BabyDueDate: cleanBody.BabyDueDate, + BabyBornDate: cleanBody.BabyBornDate, + SmpSapWeeksTaken: cleanBody.SmpSapWeeksTaken, + SplStartDate: cleanBody.SplStartDate, + SplEndDate: cleanBody.SplEndDate, + MothersDateOfDeath: cleanBody.MothersDateOfDeath + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/SmpPayInstruction.js b/api/services/pay-instructions/normal/SmpPayInstruction.js new file mode 100644 index 0000000..4a51932 --- /dev/null +++ b/api/services/pay-instructions/normal/SmpPayInstruction.js @@ -0,0 +1,32 @@ +const AbsencePayInstruction = require("./base-absence-pay-instruction"); + +module.exports = class SmpPayInstruction extends AbsencePayInstruction { + get name() { + return "Statutory Maternity Pay"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + AbsenceStart: cleanBody.AbsenceStart, + AbsenceEnd: cleanBody.AbsenceEnd, + StatutoryOffset: cleanBody.StatutoryOffset, + + AverageWeeklyEarningOverride: cleanBody.AverageWeeklyEarningOverride, + PayAsLumpSum: cleanBody.PayAsLumpSum, + PayPartWeek: cleanBody.PayPartWeek, + BabyDueDate: cleanBody.BabyDueDate, + BabyBornDate: cleanBody.BabyBornDate, + Stillbirth: cleanBody.Stillbirth, + MinStartDate: cleanBody.MinStartDate, + InstructionType: cleanBody.InstructionType, + EmployerId: cleanBody.EmployerId + }; + } +}; \ No newline at end of file diff --git a/services/payInstructions/SspPayInstruction.js b/api/services/pay-instructions/normal/SspPayInstruction.js similarity index 91% rename from services/payInstructions/SspPayInstruction.js rename to api/services/pay-instructions/normal/SspPayInstruction.js index 5a2dd88..2db30f9 100644 --- a/services/payInstructions/SspPayInstruction.js +++ b/api/services/pay-instructions/normal/SspPayInstruction.js @@ -1,4 +1,4 @@ -const AbsencePayInstruction = require("./AbsencePayInstruction"); +const AbsencePayInstruction = require("./base-absence-pay-instruction"); module.exports = class SspPayInstruction extends AbsencePayInstruction { get name() { diff --git a/api/services/pay-instructions/normal/StudentLoanPayInstruction.js b/api/services/pay-instructions/normal/StudentLoanPayInstruction.js new file mode 100644 index 0000000..128e89f --- /dev/null +++ b/api/services/pay-instructions/normal/StudentLoanPayInstruction.js @@ -0,0 +1,20 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class StudentLoanPayInstruction extends BaseInstruction { + get name() { + return "Student Loan"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + StudentLoanCalculationMethod: cleanBody.StudentLoanCalculationMethod + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/TaxPayInstruction.js b/api/services/pay-instructions/normal/TaxPayInstruction.js new file mode 100644 index 0000000..bb0bae5 --- /dev/null +++ b/api/services/pay-instructions/normal/TaxPayInstruction.js @@ -0,0 +1,22 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class TaxPayInstruction extends BaseInstruction { + get name() { + return "Tax"; + } + + parseForApi(body) { + let cleanBody = super.parseForApi(body); + + return { + StartDate: cleanBody.StartDate, + EndDate: cleanBody.EndDate, + Description: cleanBody.Description, + PayLineTag: cleanBody.PayLineTag, + + TaxBasis: cleanBody.TaxBasis, + TaxCode: cleanBody.TaxCode, + WithholdRefund: cleanBody.WithholdRefund && cleanBody.WithholdRefund.toLowerCase() === "on" + }; + } +}; \ No newline at end of file diff --git a/api/services/pay-instructions/normal/base-absence-pay-instruction.js b/api/services/pay-instructions/normal/base-absence-pay-instruction.js new file mode 100644 index 0000000..2a55c65 --- /dev/null +++ b/api/services/pay-instructions/normal/base-absence-pay-instruction.js @@ -0,0 +1,4 @@ +const BaseInstruction = require("../base-instruction"); + +module.exports = class AbsencePayInstruction extends BaseInstruction { +}; \ No newline at end of file diff --git a/services/payInstructions/yearToDate/NiYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/NiYtdPayInstruction.js similarity index 67% rename from services/payInstructions/yearToDate/NiYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/NiYtdPayInstruction.js index 2494ba5..5b0b9e2 100644 --- a/services/payInstructions/yearToDate/NiYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/NiYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseYtdPayInstruction = require("./BaseYtdPayInstruction"); +const BaseYtdPayInstruction = require("./base-ytd-pay-instruction"); module.exports = class TaxYtdPayInstruction extends BaseYtdPayInstruction { get name() { diff --git a/services/payInstructions/yearToDate/PensionYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/PensionYtdPayInstruction.js similarity index 95% rename from services/payInstructions/yearToDate/PensionYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/PensionYtdPayInstruction.js index 8775aa6..4c69bf2 100644 --- a/services/payInstructions/yearToDate/PensionYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/PensionYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseYtdPayInstruction = require("./BaseYtdPayInstruction"); +const BaseYtdPayInstruction = require("./base-ytd-pay-instruction"); const ApiWrapper = require("../../../services/api-wrapper"); let apiWrapper = new ApiWrapper(); @@ -50,5 +50,5 @@ module.exports = class PensionYtdPayInstruction extends BaseYtdPayInstruction { "@href": `/Employer/${employerId}/Pension/${body.Pension}` } }; - } + } }; \ No newline at end of file diff --git a/services/payInstructions/yearToDate/PrimitiveYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/PrimitiveYtdPayInstruction.js similarity index 66% rename from services/payInstructions/yearToDate/PrimitiveYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/PrimitiveYtdPayInstruction.js index d7046ae..7ed70dc 100644 --- a/services/payInstructions/yearToDate/PrimitiveYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/PrimitiveYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseYtdPayInstruction = require("./BaseYtdPayInstruction"); +const BaseYtdPayInstruction = require("./base-ytd-pay-instruction"); module.exports = class PrimitiveYtdPayInstruction extends BaseYtdPayInstruction { get name() { diff --git a/services/payInstructions/yearToDate/SapYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/SapYtdPayInstruction.js similarity index 90% rename from services/payInstructions/yearToDate/SapYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/SapYtdPayInstruction.js index 74b0f22..6bc38f5 100644 --- a/services/payInstructions/yearToDate/SapYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/SapYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseAbsenceYtdPayInstruction = require("./BaseAbsenceYtdPayInstruction"); +const BaseAbsenceYtdPayInstruction = require("./base-absence-ytd-pay-instruction"); module.exports = class SapYtdPayInstruction extends BaseAbsenceYtdPayInstruction { get name() { @@ -31,9 +31,9 @@ module.exports = class SapYtdPayInstruction extends BaseAbsenceYtdPayInstruction WeeksUsed: cleanBody.WeeksUsed, Description: cleanBody.Description, IsAdjustment: cleanBody.IsAdjustment, - KeepInTouchDays: { + /*KeepInTouchDays: { Date: cleanBody.KeepInTouchDays.split("|") - }, + },*/ MinStartDate: cleanBody.MinStartDate, InstructionType: cleanBody.InstructionType, EmployerId: cleanBody.EmployerId diff --git a/services/payInstructions/yearToDate/ShppYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/ShppYtdPayInstruction.js similarity index 64% rename from services/payInstructions/yearToDate/ShppYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/ShppYtdPayInstruction.js index 569aa29..8fa32e0 100644 --- a/services/payInstructions/yearToDate/ShppYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/ShppYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseAbsenceYtdPayInstruction = require("./BaseAbsenceYtdPayInstruction"); +const BaseAbsenceYtdPayInstruction = require("./base-absence-ytd-pay-instruction"); module.exports = class ShppYtdPayInstruction extends BaseAbsenceYtdPayInstruction { get name() { diff --git a/services/payInstructions/yearToDate/SmpYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/SmpYtdPayInstruction.js similarity index 90% rename from services/payInstructions/yearToDate/SmpYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/SmpYtdPayInstruction.js index a810d7b..9b6f5ab 100644 --- a/services/payInstructions/yearToDate/SmpYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/SmpYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseAbsenceYtdPayInstruction = require("./BaseAbsenceYtdPayInstruction"); +const BaseAbsenceYtdPayInstruction = require("./base-absence-ytd-pay-instruction"); module.exports = class SmpYtdPayInstruction extends BaseAbsenceYtdPayInstruction { get name() { @@ -31,9 +31,9 @@ module.exports = class SmpYtdPayInstruction extends BaseAbsenceYtdPayInstruction WeeksUsed: cleanBody.WeeksUsed, Description: cleanBody.Description, IsAdjustment: cleanBody.IsAdjustment, - KeepInTouchDays: { + /*KeepInTouchDays: { Date: cleanBody.KeepInTouchDays.split("|") - }, + },*/ MinStartDate: cleanBody.MinStartDate, InstructionType: cleanBody.InstructionType, EmployerId: cleanBody.EmployerId diff --git a/services/payInstructions/yearToDate/SppYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/SppYtdPayInstruction.js similarity index 64% rename from services/payInstructions/yearToDate/SppYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/SppYtdPayInstruction.js index 23edddb..a742338 100644 --- a/services/payInstructions/yearToDate/SppYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/SppYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseAbsenceYtdPayInstruction = require("./BaseAbsenceYtdPayInstruction"); +const BaseAbsenceYtdPayInstruction = require("./base-absence-ytd-pay-instruction"); module.exports = class SppYtdPayInstruction extends BaseAbsenceYtdPayInstruction { get name() { diff --git a/services/payInstructions/yearToDate/SspYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/SspYtdPayInstruction.js similarity index 92% rename from services/payInstructions/yearToDate/SspYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/SspYtdPayInstruction.js index 51c32ad..ef3616f 100644 --- a/services/payInstructions/yearToDate/SspYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/SspYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseAbsenceYtdPayInstruction = require("./BaseAbsenceYtdPayInstruction"); +const BaseAbsenceYtdPayInstruction = require("./base-absence-ytd-pay-instruction"); module.exports = class SppYtdPayInstruction extends BaseAbsenceYtdPayInstruction { get name() { diff --git a/services/payInstructions/yearToDate/StudentLoanYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/StudentLoanYtdPayInstruction.js similarity index 67% rename from services/payInstructions/yearToDate/StudentLoanYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/StudentLoanYtdPayInstruction.js index e41938b..d11e9bc 100644 --- a/services/payInstructions/yearToDate/StudentLoanYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/StudentLoanYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseYtdPayInstruction = require("./BaseYtdPayInstruction"); +const BaseYtdPayInstruction = require("./base-ytd-pay-instruction"); module.exports = class StudentLoanYtdPayInstruction extends BaseYtdPayInstruction { get name() { diff --git a/services/payInstructions/yearToDate/TaxYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/TaxYtdPayInstruction.js similarity index 64% rename from services/payInstructions/yearToDate/TaxYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/TaxYtdPayInstruction.js index 7093033..a6c0208 100644 --- a/services/payInstructions/yearToDate/TaxYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/TaxYtdPayInstruction.js @@ -1,4 +1,4 @@ -const BaseYtdPayInstruction = require("./BaseYtdPayInstruction"); +const BaseYtdPayInstruction = require("./base-ytd-pay-instruction"); module.exports = class TaxYtdPayInstruction extends BaseYtdPayInstruction { get name() { diff --git a/services/payInstructions/yearToDate/BaseAbsenceYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/base-absence-ytd-pay-instruction.js similarity index 54% rename from services/payInstructions/yearToDate/BaseAbsenceYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/base-absence-ytd-pay-instruction.js index 49de16d..500c2d4 100644 --- a/services/payInstructions/yearToDate/BaseAbsenceYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/base-absence-ytd-pay-instruction.js @@ -1,4 +1,4 @@ -const BaseYtdPayInstruction = require("./BaseYtdPayInstruction"); +const BaseYtdPayInstruction = require("./base-ytd-pay-instruction"); module.exports = class AbsenceYtdPayInstruction extends BaseYtdPayInstruction { }; \ No newline at end of file diff --git a/services/payInstructions/yearToDate/BaseYtdPayInstruction.js b/api/services/pay-instructions/year-to-date/base-ytd-pay-instruction.js similarity index 51% rename from services/payInstructions/yearToDate/BaseYtdPayInstruction.js rename to api/services/pay-instructions/year-to-date/base-ytd-pay-instruction.js index b33e30a..bb9738e 100644 --- a/services/payInstructions/yearToDate/BaseYtdPayInstruction.js +++ b/api/services/pay-instructions/year-to-date/base-ytd-pay-instruction.js @@ -1,16 +1,13 @@ -const BaseInstruction = require("../BaseInstruction"); +const BaseInstruction = require("../base-instruction"); module.exports = class BaseYtdPayInstruction extends BaseInstruction { parseForApi(body) { let cleanBody = super.parseForApi(body); - if (cleanBody.IsAdjustment && cleanBody.IsAdjustment.toLowerCase() === "on") { - cleanBody.IsAdjustment = true; - } - else { + if (!cleanBody.IsAdjustment) { cleanBody.IsAdjustment = false; } - + return cleanBody; - } + } }; \ No newline at end of file diff --git a/services/pay-run-utils.js b/api/services/pay-run-utils.js similarity index 83% rename from services/pay-run-utils.js rename to api/services/pay-run-utils.js index 3517761..279fd37 100644 --- a/services/pay-run-utils.js +++ b/api/services/pay-run-utils.js @@ -3,9 +3,11 @@ module.exports = class PayRunUtils { let copy = JSON.parse(JSON.stringify(run)); copy.PaySchedule = { - "@href": `/Employer/${employerId}/PaySchedule/${copy.PaySchedule}` + "@href": `/Employer/${employerId}/PaySchedule/${copy.PayScheduleId}` }; + copy.PayScheduleId = null; + return copy; } }; \ No newline at end of file diff --git a/services/pension-utils.js b/api/services/pension-utils.js similarity index 84% rename from services/pension-utils.js rename to api/services/pension-utils.js index a9e3d5d..ca31377 100644 --- a/services/pension-utils.js +++ b/api/services/pension-utils.js @@ -2,7 +2,10 @@ module.exports = class PensionUtils { static parse(pension) { let copy = JSON.parse(JSON.stringify(pension)); - copy.EmployerId = null; + copy.Id = null; + copy.employerId = null; + copy.ObjectType = null; + copy.UseForAutoEnrolment = null; copy.AECompatible = (copy.AECompatible !== undefined && copy.AECompatible.toLowerCase() === "on"); copy.UseAEThresholds = (copy.UseAEThresholds !== undefined && copy.UseAEThresholds.toLowerCase() === "on"); copy.SalarySacrifice = (copy.SalarySacrifice !== undefined && copy.SalarySacrifice.toLowerCase() === "on"); diff --git a/services/status-utils.js b/api/services/status-utils.js similarity index 100% rename from services/status-utils.js rename to api/services/status-utils.js diff --git a/services/validation-parser.js b/api/services/validation-parser.js similarity index 100% rename from services/validation-parser.js rename to api/services/validation-parser.js diff --git a/spec/.eslintrc.json b/api/spec/.eslintrc.json similarity index 100% rename from spec/.eslintrc.json rename to api/spec/.eslintrc.json diff --git a/spec/app-state.spec.js b/api/spec/app-state.spec.js similarity index 100% rename from spec/app-state.spec.js rename to api/spec/app-state.spec.js diff --git a/app.js b/app.js index ba6d35b..e31c0d1 100644 --- a/app.js +++ b/app.js @@ -2,6 +2,7 @@ const Koa = require("koa"); const Router = require("koa-router"); const Helmet = require("koa-helmet"); const Serve = require("koa-static"); +const Mount = require("koa-mount"); const HandlebarsRenderer = require("koa-hbs-renderer"); const Handlebars = require("handlebars"); const BodyParser = require("koa-bodyparser"); @@ -9,10 +10,9 @@ const Session = require("koa-session"); const MemoryStore = require("koa-session-memory"); const path = require("path"); const argv = require("minimist")(process.argv.slice(2)); -const Routes = require("./routes"); +const Routes = require("./api/routes"); const Raven = require("raven"); -const APILogger = require("./services/api-logger"); -const SetupController = require("./controllers/setup-controller"); +const APILogger = require("./api/services/api-logger"); let app = new Koa(); let router = new Router(); @@ -46,25 +46,10 @@ app await next(); }) - .use(async (ctx, next) => { - let setupCookie = ctx.cookies.get(SetupController.cookieKey); - - let href = ctx.href; - let path = ctx.path; - - if (!setupCookie) { - if (href.indexOf("/css/") == -1 - && href.indexOf("/js/") == -1 - && href.indexOf("/favicon.ico") == -1 - && href.indexOf("/setup") == -1 - && path !== "/" - && path !== "/api-calls/data") { - await ctx.redirect("/"); - } - } - - await next(); - }) + // .use(async (ctx, next) => { + // let setupCookie = ctx.cookies.get(SetupController.cookieKey); + // await next(); + // }) .use(async (ctx, next) => { try { await next(); @@ -91,14 +76,15 @@ app hbs: Handlebars, paths: { views: path.join(__dirname, "views"), - layouts: path.join(__dirname, "views", "layouts"), - helpers: path.join(__dirname, "helpers"), - partials: path.join(__dirname, "views", "partials") + //layouts: path.join(__dirname, "views", "layouts"), + //helpers: path.join(__dirname, "helpers"), + //partials: path.join(__dirname, "views", "partials") } })) .use(Helmet()) .use(BodyParser()) - .use(Serve("./content")) + .use(Mount("/content", Serve("./content"))) + //.use(Serve("./content")) .use(router.routes()) .use(router.allowedMethods()); diff --git a/aurelia_project/aurelia.json b/aurelia_project/aurelia.json new file mode 100644 index 0000000..ca44107 --- /dev/null +++ b/aurelia_project/aurelia.json @@ -0,0 +1,179 @@ +{ + "name": "aurelia-app", + "type": "project:application", + "bundler": { + "id": "cli", + "displayName": "Aurelia-CLI" + }, + "build": { + "targets": [ + { + "id": "web", + "displayName": "Web", + "port": 9000, + "baseDir": ".", + "output": "content/dist" + } + ], + "options": { + "minify": "stage & prod", + "sourcemaps": "dev & stage" + }, + "bundles": [ + { + "name": "app-bundle.js", + "source": [ + "[**/*.js]", + "**/*.{css,html}" + ] + }, + { + "name": "vendor-bundle.js", + "prepend": [ + "node_modules/bluebird/js/browser/bluebird.core.js", + { + "path": "node_modules/aurelia-cli/lib/resources/scripts/configure-bluebird-no-long-stacktraces.js", + "env": "stage & prod" + }, + { + "path": "node_modules/aurelia-cli/lib/resources/scripts/configure-bluebird.js", + "env": "dev" + }, + "node_modules/requirejs/require.js" + ], + "dependencies": [ + "aurelia-binding", + "aurelia-bootstrapper", + "aurelia-dependency-injection", + "aurelia-event-aggregator", + "aurelia-framework", + "aurelia-history", + "aurelia-history-browser", + "aurelia-http-client", + "aurelia-loader", + "aurelia-loader-default", + "aurelia-logging", + "aurelia-logging-console", + "aurelia-metadata", + "aurelia-pal", + "aurelia-pal-browser", + "aurelia-path", + "aurelia-polyfills", + "aurelia-route-recognizer", + "aurelia-router", + "aurelia-task-queue", + "aurelia-templating", + "aurelia-templating-binding", + { + "name": "aurelia-templating-resources", + "path": "../node_modules/aurelia-templating-resources/dist/amd", + "main": "aurelia-templating-resources" + }, + { + "name": "aurelia-templating-router", + "path": "../node_modules/aurelia-templating-router/dist/amd", + "main": "aurelia-templating-router" + }, + { + "name": "aurelia-testing", + "path": "../node_modules/aurelia-testing/dist/amd", + "main": "aurelia-testing", + "env": "dev" + }, + { + "name": "aurelia-validation", + "path": "../node_modules/aurelia-validation/dist/amd", + "main": "aurelia-validation" + }, + { + "name": "aurelia-dialog", + "path": "../node_modules/aurelia-dialog/dist/amd", + "main": "aurelia-dialog", + "resources": ["resources/*.js"] + }, + "text", + "moment", + { + "name": "nprogress", + "path": "../node_modules/nprogress", + "main": "nprogress", + "resources": [ + "nprogress.css" + ] + }, + { + "name": "github-buttons", + "path": "../content/js/buttons" + } + ] + } + ], + "loader": { + "type": "require", + "configTarget": "vendor-bundle.js", + "includeBundleMetadataInConfig": "auto", + "plugins": [ + { + "name": "text", + "extensions": [ + ".html", + ".css" + ], + "stub": true + } + ] + } + }, + "platform": { + "id": "web", + "displayName": "Web", + "port": 9000, + "baseDir": ".", + "output": "content/dist" + }, + "transpiler": { + "id": "babel", + "displayName": "Babel", + "fileExtension": ".js", + "options": { + "plugins": [ + "transform-es2015-modules-amd" + ] + }, + "source": "src/**/*.js" + }, + "markupProcessor": { + "id": "none", + "displayName": "None", + "fileExtension": ".html", + "source": "src/**/*.html" + }, + "cssProcessor": { + "id": "none", + "displayName": "None", + "fileExtension": ".css", + "source": "src/**/*.css" + }, + "editor": { + "id": "none", + "displayName": "None" + }, + "unitTestRunners": [ + { + "id": "none", + "displayName": "None" + } + ], + "integrationTestRunner": { + "id": "none", + "displayName": "None" + }, + "paths": { + "root": "src", + "resources": "resources", + "elements": "resources/elements", + "attributes": "resources/attributes", + "valueConverters": "resources/value-converters", + "bindingBehaviors": "resources/binding-behaviors" + } +} \ No newline at end of file diff --git a/aurelia_project/environments/dev.js b/aurelia_project/environments/dev.js new file mode 100644 index 0000000..3495e9a --- /dev/null +++ b/aurelia_project/environments/dev.js @@ -0,0 +1,4 @@ +export default { + debug: true, + testing: true +}; diff --git a/aurelia_project/environments/prod.js b/aurelia_project/environments/prod.js new file mode 100644 index 0000000..da32a4b --- /dev/null +++ b/aurelia_project/environments/prod.js @@ -0,0 +1,4 @@ +export default { + debug: false, + testing: false +}; diff --git a/aurelia_project/environments/stage.js b/aurelia_project/environments/stage.js new file mode 100644 index 0000000..dafe69b --- /dev/null +++ b/aurelia_project/environments/stage.js @@ -0,0 +1,4 @@ +export default { + debug: true, + testing: false +}; diff --git a/aurelia_project/generators/attribute.js b/aurelia_project/generators/attribute.js new file mode 100644 index 0000000..7be5039 --- /dev/null +++ b/aurelia_project/generators/attribute.js @@ -0,0 +1,44 @@ +import {inject} from 'aurelia-dependency-injection'; +import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli'; + +@inject(Project, CLIOptions, UI) +export default class AttributeGenerator { + constructor(project, options, ui) { + this.project = project; + this.options = options; + this.ui = ui; + } + + execute() { + return this.ui + .ensureAnswer(this.options.args[0], 'What would you like to call the custom attribute?') + .then(name => { + let fileName = this.project.makeFileName(name); + let className = this.project.makeClassName(name); + + this.project.attributes.add( + ProjectItem.text(`${fileName}.js`, this.generateSource(className)) + ); + + return this.project.commitChanges() + .then(() => this.ui.log(`Created ${fileName}.`)); + }); + } + + generateSource(className) { + return `import {inject} from 'aurelia-framework'; + +@inject(Element) +export class ${className}CustomAttribute { + constructor(element) { + this.element = element; + } + + valueChanged(newValue, oldValue) { + + } +} + +`; + } +} diff --git a/aurelia_project/generators/attribute.json b/aurelia_project/generators/attribute.json new file mode 100644 index 0000000..ddf940c --- /dev/null +++ b/aurelia_project/generators/attribute.json @@ -0,0 +1,4 @@ +{ + "name": "attribute", + "description": "Creates a custom attribute class and places it in the project resources." +} diff --git a/aurelia_project/generators/binding-behavior.js b/aurelia_project/generators/binding-behavior.js new file mode 100644 index 0000000..8726a10 --- /dev/null +++ b/aurelia_project/generators/binding-behavior.js @@ -0,0 +1,41 @@ +import {inject} from 'aurelia-dependency-injection'; +import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli'; + +@inject(Project, CLIOptions, UI) +export default class BindingBehaviorGenerator { + constructor(project, options, ui) { + this.project = project; + this.options = options; + this.ui = ui; + } + + execute() { + return this.ui + .ensureAnswer(this.options.args[0], 'What would you like to call the binding behavior?') + .then(name => { + let fileName = this.project.makeFileName(name); + let className = this.project.makeClassName(name); + + this.project.bindingBehaviors.add( + ProjectItem.text(`${fileName}.js`, this.generateSource(className)) + ); + + return this.project.commitChanges() + .then(() => this.ui.log(`Created ${fileName}.`)); + }); + } + + generateSource(className) { + return `export class ${className}BindingBehavior { + bind(binding, source) { + + } + + unbind(binding, source) { + + } +} + +` + } +} diff --git a/aurelia_project/generators/binding-behavior.json b/aurelia_project/generators/binding-behavior.json new file mode 100644 index 0000000..60906a1 --- /dev/null +++ b/aurelia_project/generators/binding-behavior.json @@ -0,0 +1,4 @@ +{ + "name": "binding-behavior", + "description": "Creates a binding behavior class and places it in the project resources." +} diff --git a/aurelia_project/generators/component.js b/aurelia_project/generators/component.js new file mode 100644 index 0000000..8f381c7 --- /dev/null +++ b/aurelia_project/generators/component.js @@ -0,0 +1,51 @@ +import { inject } from 'aurelia-dependency-injection'; +import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli'; + +var path = require('path'); + +@inject(Project, CLIOptions, UI) +export default class ElementGenerator { + constructor(project, options, ui) { + this.project = project; + this.options = options; + this.ui = ui; + } + + execute() { + let self = this; + + return this.ui + .ensureAnswer(this.options.args[0], 'What would you like to call the component?') + .then(name => { + + return self.ui.ensureAnswer(this.options.args[1], 'What sub-folder would you like to add it to?\nIf it doesn\'t exist it will be created for you.\n\nDefault folder is the source folder (src).', ".") + .then(subFolders => { + + let fileName = this.project.makeFileName(name); + let className = this.project.makeClassName(name); + + self.project.root.add( + ProjectItem.text(path.join(subFolders, fileName + ".js"), this.generateJSSource(className)), + ProjectItem.text(path.join(subFolders, fileName + ".html"), this.generateHTMLSource(className)) + ); + + return this.project.commitChanges() + .then(() => this.ui.log(`Created ${name} in the '${path.join(self.project.root.name, subFolders)}' folder`)); + }); + }); + } + + generateJSSource(className) { + return `export class ${className} { + constructor() { + this.message = 'Hello world'; + } +}` + } + + generateHTMLSource(className) { + return `` + } +} \ No newline at end of file diff --git a/aurelia_project/generators/component.json b/aurelia_project/generators/component.json new file mode 100644 index 0000000..ec39075 --- /dev/null +++ b/aurelia_project/generators/component.json @@ -0,0 +1,4 @@ +{ + "name": "component", + "description": "Creates a custom component class and template (view model and view), placing them in the project source folder (or optionally in sub folders)." +} \ No newline at end of file diff --git a/aurelia_project/generators/element.js b/aurelia_project/generators/element.js new file mode 100644 index 0000000..a1b48b9 --- /dev/null +++ b/aurelia_project/generators/element.js @@ -0,0 +1,48 @@ +import {inject} from 'aurelia-dependency-injection'; +import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli'; + +@inject(Project, CLIOptions, UI) +export default class ElementGenerator { + constructor(project, options, ui) { + this.project = project; + this.options = options; + this.ui = ui; + } + + execute() { + return this.ui + .ensureAnswer(this.options.args[0], 'What would you like to call the custom element?') + .then(name => { + let fileName = this.project.makeFileName(name); + let className = this.project.makeClassName(name); + + this.project.elements.add( + ProjectItem.text(`${fileName}.js`, this.generateJSSource(className)), + ProjectItem.text(`${fileName}.html`, this.generateHTMLSource(className)) + ); + + return this.project.commitChanges() + .then(() => this.ui.log(`Created ${fileName}.`)); + }); + } + + generateJSSource(className) { + return `import {bindable} from 'aurelia-framework'; + +export class ${className} { + @bindable value; + + valueChanged(newValue, oldValue) { + + } +} + +`; + } + + generateHTMLSource(className) { + return ``; + } +} diff --git a/aurelia_project/generators/element.json b/aurelia_project/generators/element.json new file mode 100644 index 0000000..68d8c54 --- /dev/null +++ b/aurelia_project/generators/element.json @@ -0,0 +1,4 @@ +{ + "name": "element", + "description": "Creates a custom element class and template, placing them in the project resources." +} diff --git a/aurelia_project/generators/generator.js b/aurelia_project/generators/generator.js new file mode 100644 index 0000000..4162842 --- /dev/null +++ b/aurelia_project/generators/generator.js @@ -0,0 +1,73 @@ +import {inject} from 'aurelia-dependency-injection'; +import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli'; + +@inject(Project, CLIOptions, UI) +export default class GeneratorGenerator { + constructor(project, options, ui) { + this.project = project; + this.options = options; + this.ui = ui; + } + + execute() { + return this.ui + .ensureAnswer(this.options.args[0], 'What would you like to call the generator?') + .then(name => { + let fileName = this.project.makeFileName(name); + let className = this.project.makeClassName(name); + + this.project.generators.add( + ProjectItem.text(`${fileName}.js`, this.generateSource(className)) + ); + + return this.project.commitChanges() + .then(() => this.ui.log(`Created ${fileName}.`)); + }); + } + + generateSource(className) { + return `import {inject} from 'aurelia-dependency-injection'; +import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli'; + +@inject(Project, CLIOptions, UI) +export default class ${className}Generator { + constructor(project, options, ui) { + this.project = project; + this.options = options; + this.ui = ui; + } + + execute() { + return this.ui + .ensureAnswer(this.options.args[0], 'What would you like to call the new item?') + .then(name => { + let fileName = this.project.makeFileName(name); + let className = this.project.makeClassName(name); + + this.project.elements.add( + ProjectItem.text(\`\${fileName}.js\`, this.generateSource(className)) + ); + + return this.project.commitChanges() + .then(() => this.ui.log(\`Created \${fileName}.\`)); + }); + } + + generateSource(className) { +return \`import {bindable} from 'aurelia-framework'; + +export class \${className} { + @bindable value; + + valueChanged(newValue, oldValue) { + + } +} + +\` + } +} + +`; + } +} diff --git a/aurelia_project/generators/generator.json b/aurelia_project/generators/generator.json new file mode 100644 index 0000000..be946a5 --- /dev/null +++ b/aurelia_project/generators/generator.json @@ -0,0 +1,4 @@ +{ + "name": "generator", + "description": "Creates a generator class and places it in the project generators folder." +} diff --git a/aurelia_project/generators/task.js b/aurelia_project/generators/task.js new file mode 100644 index 0000000..a70f10b --- /dev/null +++ b/aurelia_project/generators/task.js @@ -0,0 +1,41 @@ +import {inject} from 'aurelia-dependency-injection'; +import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli'; + +@inject(Project, CLIOptions, UI) +export default class TaskGenerator { + constructor(project, options, ui) { + this.project = project; + this.options = options; + this.ui = ui; + } + + execute() { + return this.ui + .ensureAnswer(this.options.args[0], 'What would you like to call the task?') + .then(name => { + let fileName = this.project.makeFileName(name); + let functionName = this.project.makeFunctionName(name); + + this.project.tasks.add( + ProjectItem.text(`${fileName}.js`, this.generateSource(functionName)) + ); + + return this.project.commitChanges() + .then(() => this.ui.log(`Created ${fileName}.`)); + }); + } + + generateSource(functionName) { + return `import gulp from 'gulp'; +import changed from 'gulp-changed'; +import project from '../aurelia.json'; + +export default function ${functionName}() { + return gulp.src(project.paths.???) + .pipe(changed(project.paths.output, {extension: '.???'})) + .pipe(gulp.dest(project.paths.output)); +} + +`; + } +} diff --git a/aurelia_project/generators/task.json b/aurelia_project/generators/task.json new file mode 100644 index 0000000..fd15bc6 --- /dev/null +++ b/aurelia_project/generators/task.json @@ -0,0 +1,4 @@ +{ + "name": "task", + "description": "Creates a task and places it in the project tasks folder." +} diff --git a/aurelia_project/generators/value-converter.js b/aurelia_project/generators/value-converter.js new file mode 100644 index 0000000..df79971 --- /dev/null +++ b/aurelia_project/generators/value-converter.js @@ -0,0 +1,41 @@ +import {inject} from 'aurelia-dependency-injection'; +import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli'; + +@inject(Project, CLIOptions, UI) +export default class ValueConverterGenerator { + constructor(project, options, ui) { + this.project = project; + this.options = options; + this.ui = ui; + } + + execute() { + return this.ui + .ensureAnswer(this.options.args[0], 'What would you like to call the value converter?') + .then(name => { + let fileName = this.project.makeFileName(name); + let className = this.project.makeClassName(name); + + this.project.valueConverters.add( + ProjectItem.text(`${fileName}.js`, this.generateSource(className)) + ); + + return this.project.commitChanges() + .then(() => this.ui.log(`Created ${fileName}.`)); + }); + } + + generateSource(className) { + return `export class ${className}ValueConverter { + toView(value) { + + } + + fromView(value) { + + } +} + +`; + } +} diff --git a/aurelia_project/generators/value-converter.json b/aurelia_project/generators/value-converter.json new file mode 100644 index 0000000..1108122 --- /dev/null +++ b/aurelia_project/generators/value-converter.json @@ -0,0 +1,4 @@ +{ + "name": "value-converter", + "description": "Creates a value converter class and places it in the project resources." +} diff --git a/aurelia_project/tasks/build.js b/aurelia_project/tasks/build.js new file mode 100644 index 0000000..28fe5db --- /dev/null +++ b/aurelia_project/tasks/build.js @@ -0,0 +1,28 @@ +import gulp from 'gulp'; +import {CLIOptions, build as buildCLI} from 'aurelia-cli'; +import transpile from './transpile'; +import processMarkup from './process-markup'; +import copyFiles from './copy-files'; +import project from '../aurelia.json'; + +let build = gulp.series( + readProjectConfiguration, + gulp.parallel( + transpile, + processMarkup, + copyFiles + ), + writeBundles +); + +let main = build; + +function readProjectConfiguration() { + return buildCLI.src(project); +} + +function writeBundles() { + return buildCLI.dest(); +} + +export { main as default }; diff --git a/aurelia_project/tasks/copy-files.js b/aurelia_project/tasks/copy-files.js new file mode 100644 index 0000000..61a24d1 --- /dev/null +++ b/aurelia_project/tasks/copy-files.js @@ -0,0 +1,45 @@ +import gulp from 'gulp'; +import path from 'path'; +import minimatch from 'minimatch'; +import changedInPlace from 'gulp-changed-in-place'; +import project from '../aurelia.json'; + +export default function copyFiles(done) { + if (typeof project.build.copyFiles !== 'object') { + done(); + return; + } + + const instruction = getNormalizedInstruction(); + const files = Object.keys(instruction); + + return gulp.src(files) + .pipe(changedInPlace({ firstPass: true })) + .pipe(gulp.dest(x => { + const filePath = prepareFilePath(x.path); + const key = files.find(f => minimatch(filePath, f)); + return instruction[key]; + })); +} + +function getNormalizedInstruction() { + const files = project.build.copyFiles; + let normalizedInstruction = {}; + + for (let key in files) { + normalizedInstruction[path.posix.normalize(key)] = files[key]; + } + + return normalizedInstruction; +} + +function prepareFilePath(filePath) { + let preparedPath = filePath.replace(process.cwd(), '').substring(1); + + //if we are running on windows we have to fix the path + if (/^win/.test(process.platform)) { + preparedPath = preparedPath.replace(/\\/g, '/'); + } + + return preparedPath; +} diff --git a/aurelia_project/tasks/process-markup.js b/aurelia_project/tasks/process-markup.js new file mode 100644 index 0000000..ad4f2ac --- /dev/null +++ b/aurelia_project/tasks/process-markup.js @@ -0,0 +1,10 @@ +import gulp from 'gulp'; +import changedInPlace from 'gulp-changed-in-place'; +import project from '../aurelia.json'; +import {build} from 'aurelia-cli'; + +export default function processMarkup() { + return gulp.src(project.markupProcessor.source) + .pipe(changedInPlace({firstPass: true})) + .pipe(build.bundle()); +} diff --git a/aurelia_project/tasks/run.js b/aurelia_project/tasks/run.js new file mode 100644 index 0000000..9aebf92 --- /dev/null +++ b/aurelia_project/tasks/run.js @@ -0,0 +1,10 @@ +import gulp from 'gulp'; +import build from './build'; +import watch from './watch'; + +let run = gulp.series(build, done => { + watch(); + done(); +}); + +export default run; diff --git a/aurelia_project/tasks/transpile.js b/aurelia_project/tasks/transpile.js new file mode 100644 index 0000000..3c5df73 --- /dev/null +++ b/aurelia_project/tasks/transpile.js @@ -0,0 +1,32 @@ +import gulp from 'gulp'; +import changedInPlace from 'gulp-changed-in-place'; +import plumber from 'gulp-plumber'; +import babel from 'gulp-babel'; +import sourcemaps from 'gulp-sourcemaps'; +import notify from 'gulp-notify'; +import rename from 'gulp-rename'; +import project from '../aurelia.json'; +import {CLIOptions, build} from 'aurelia-cli'; + +function configureEnvironment() { + let env = CLIOptions.getEnvironment(); + + return gulp.src(`aurelia_project/environments/${env}.js`) + .pipe(changedInPlace({firstPass: true})) + .pipe(rename('environment.js')) + .pipe(gulp.dest(project.paths.root)); +} + +function buildJavaScript() { + return gulp.src(project.transpiler.source) + .pipe(plumber({errorHandler: notify.onError('Error: <%= error.message %>')})) + .pipe(changedInPlace({firstPass: true})) + .pipe(sourcemaps.init()) + .pipe(babel(project.transpiler.options)) + .pipe(build.bundle()); +} + +export default gulp.series( + configureEnvironment, + buildJavaScript +); diff --git a/aurelia_project/tasks/watch.js b/aurelia_project/tasks/watch.js new file mode 100644 index 0000000..9624f92 --- /dev/null +++ b/aurelia_project/tasks/watch.js @@ -0,0 +1,126 @@ +import gulp from 'gulp'; +import minimatch from 'minimatch'; +import gulpWatch from 'gulp-watch'; +import debounce from 'debounce'; +import { build } from 'aurelia-cli'; +import project from '../aurelia.json'; +import transpile from './transpile'; +import processMarkup from './process-markup'; +import copyFiles from './copy-files'; + +const debounceWaitTime = 100; +let isBuilding = false; +let pendingRefreshPaths = []; +let watchCallback = () => { }; +let watches = [ + { name: 'transpile', callback: transpile, source: project.transpiler.source }, + { name: 'markup', callback: processMarkup, source: project.markupProcessor.source } +]; + +if (typeof project.build.copyFiles === 'object') { + for (let src of Object.keys(project.build.copyFiles)) { + watches.push({ name: 'file copy', callback: copyFiles, source: src }); + } +} + +let watch = (callback) => { + watchCallback = callback || watchCallback; + + // watch every glob individually + for(let watcher of watches) { + if (Array.isArray(watcher.source)) { + for(let glob of watcher.source) { + watchPath(glob); + } + } else { + watchPath(watcher.source); + } + } +}; + +let watchPath = (p) => { + gulpWatch( + p, + { + read: false, // performance optimization: do not read actual file contents + verbose: true + }, + (vinyl) => processChange(vinyl)); +}; + +let processChange = (vinyl) => { + if (vinyl.path && vinyl.cwd && vinyl.path.startsWith(vinyl.cwd)) { + let pathToAdd = vinyl.path.substr(vinyl.cwd.length + 1); + log(`Watcher: Adding path ${pathToAdd} to pending build changes...`); + pendingRefreshPaths.push(pathToAdd); + refresh(); + } +} + +let refresh = debounce(() => { + if (isBuilding) { + log('Watcher: A build is already in progress, deferring change detection...'); + return; + } + + isBuilding = true; + + let paths = pendingRefreshPaths.splice(0); + let refreshTasks = []; + + // determine which tasks need to be executed + // based on the files that have changed + for (let watcher of watches) { + if (Array.isArray(watcher.source)) { + for(let source of watcher.source) { + if (paths.find(path => minimatch(path, source))) { + refreshTasks.push(watcher); + } + } + } + else { + if (paths.find(path => minimatch(path, watcher.source))) { + refreshTasks.push(watcher); + } + } + } + + if (refreshTasks.length === 0) { + log('Watcher: No relevant changes found, skipping next build.'); + isBuilding = false; + return; + } + + log(`Watcher: Running ${refreshTasks.map(x => x.name).join(', ')} tasks on next build...`); + + let toExecute = gulp.series( + readProjectConfiguration, + gulp.parallel(refreshTasks.map(x => x.callback)), + writeBundles, + (done) => { + isBuilding = false; + watchCallback(); + done(); + if (pendingRefreshPaths.length > 0) { + log('Watcher: Found more pending changes after finishing build, triggering next one...'); + refresh(); + } + } + ); + + toExecute(); +}, debounceWaitTime); + +function log(message) { + console.log(message); +} + +function readProjectConfiguration() { + return build.src(project); +} + +function writeBundles() { + return build.dest(); +} + +export default watch; \ No newline at end of file diff --git a/bin/build-css b/bin/build-css deleted file mode 100755 index 24eaadb..0000000 --- a/bin/build-css +++ /dev/null @@ -1 +0,0 @@ -node-sass --include-path scss content/scss/main.scss content/css/main.css \ No newline at end of file diff --git a/bin/watch-css b/bin/watch-css deleted file mode 100755 index 7594cb7..0000000 --- a/bin/watch-css +++ /dev/null @@ -1 +0,0 @@ -nodemon -e scss -x "npm run build-css" \ No newline at end of file diff --git a/bin/watch-hbs b/bin/watch-hbs deleted file mode 100755 index 3b8f729..0000000 --- a/bin/watch-hbs +++ /dev/null @@ -1 +0,0 @@ -nodemon -e js,hbs app.js \ No newline at end of file diff --git a/constants.js b/constants.js deleted file mode 100644 index 6a9a12d..0000000 --- a/constants.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = class Globals { - static setup(setup) { - this._setup = setup; - } - - static get apiUrl() { - if (this._setup && this._setup.Environment.toLowerCase() === "test") { - return "https://api.test.payrun.io/"; - } - - return "https://api.payrun.io/"; - } - - static get consumerKey() { - return this._setup ? this._setup.ConsumerKey : "kXrXIxDAJ0SzjCjgYyvhNg"; - } - - static get consumerSecret() { - return this._setup ? this._setup.ConsumerSecret : "k55ebIyfF0ehiO4VY6SibA1Q90Nf3n0q6ylYGusp1lg"; - } -}; \ No newline at end of file diff --git a/content/css/main.css b/content/css/main.css index 62d9293..717c183 100644 --- a/content/css/main.css +++ b/content/css/main.css @@ -92,8 +92,16 @@ a.btn-default { display: block; margin-bottom: 10px; } -.bootbox-close-button { - display: none; } +.status .btn-outline-secondary { + float: right; + margin-top: -2px; } + +ux-dialog-overlay.active { + background-color: black; + opacity: 0.75 !important; } + +ux-dialog { + min-width: 700px !important; } .tab-pane { padding-top: 20px; } @@ -118,8 +126,13 @@ th { .display-none { display: none; } +.splash { + font-size: 100px; + position: absolute; + top: calc(50% - 50px); + left: calc(50% - 50px); } + .api-calls { - display: none; height: 300px; position: fixed; bottom: 0; @@ -189,6 +202,14 @@ th { .api-calls .api-calls-container hr:last-child { visibility: collapse; } +.coming-soon { + width: 75%; + margin: 0 auto; + padding: 20px; + background-color: #e9ecef; + border-radius: 20px; + margin-top: 30px; } + .job-info .row { margin-bottom: 10px; } @@ -201,25 +222,87 @@ th { .job-info-container h5 .close { color: white; } +.keep-in-touch-days .keep-in-touch-day { + margin-bottom: 5px; } + +.pension-modal-container { + width: 1000px; } + +.pay-instruction-modal-container { + width: 1000px; } + .pay-run-info .row { margin-bottom: 20px; } -.coming-soon { - width: 75%; - margin: 0 auto; - padding: 20px; - background-color: #e9ecef; - border-radius: 20px; - margin-top: 30px; } - -.keep-in-touch-days .keep-in-touch-day { - margin-bottom: 5px; } +.pay-code-modal-container { + width: 1000px; } .setup .jumbotron { padding: 30px; } .setup .jumbotron .lead { margin-bottom: 0px; } +/* Make clicks pass-through */ +#nprogress { + pointer-events: none; + /* Fancy blur effect */ + /* Remove these to get rid of the spinner */ } + #nprogress .bar { + background: #00b100; + position: fixed; + z-index: 1031; + top: 0; + left: 0; + width: 100%; + height: 2px; } + #nprogress .peg { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px #00b100, 0 0 5px #00b100; + opacity: 1.0; + -webkit-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); } + #nprogress .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 15px; + right: 15px; } + #nprogress .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + border: solid 2px transparent; + border-top-color: #00b100; + border-left-color: #00b100; + border-radius: 50%; + -webkit-animation: nprogress-spinner 400ms linear infinite; + animation: nprogress-spinner 400ms linear infinite; } + +.nprogress-custom-parent { + overflow: hidden; + position: relative; } + +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { + position: absolute; } + +@-webkit-keyframes nprogress-spinner { + 0% { + -webkit-transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(360deg); } } + +@keyframes nprogress-spinner { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } + input.parsley-error, select.parsley-error, textarea.parsley-error { diff --git a/content/js/.eslintrc.json b/content/js/.eslintrc.json deleted file mode 100644 index c7ea00c..0000000 --- a/content/js/.eslintrc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "env": { - "browser": true - }, - "globals": { - "$": true, - "window": true, - "Templates": true, - "tippy": true, - "Handlebars": true, - "bootbox": true, - "showValidationErrors": true, - "showStatus": true, - "getUrlVars": true - } -} \ No newline at end of file diff --git a/content/js/api-logs.js b/content/js/api-logs.js deleted file mode 100644 index d96ead8..0000000 --- a/content/js/api-logs.js +++ /dev/null @@ -1,82 +0,0 @@ -var previousCallData = []; - -$(function() { - if (!Templates.loaded) { - Templates.onLoaded = getLogs(); - } - else { - getLogs(); - } - - $(document).on("click", ".btn-copy", function () { - var $self = $(this); - var $code = $self.parent().find("code"); - var text = $code.text(); - - copyTextToClipboard(text); - }); - - $(document).on("click", ".summary", function () { - var $self = $(this); - var id = $self.attr("data-id"); - var apiCall = previousCallData.find(x => x.id.toString() === id.toString()); - - if (apiCall) { - var content = Templates["apiCallDetailsTemplate"](apiCall); - var $apiCallsContainer = $(".api-calls-container"); - - $apiCallsContainer.find(".request-and-response").html(content); - - $apiCallsContainer.animate({ scrollTop: 0 }, 500); - } - }); -}); - -function getLogs() { - $.get("/api-calls/data").then(function(data) { - var context = { - data: data - }; - - if (previousCallData.length !== data.length) { - $(".api-calls-container").html(Templates["apiCallsTemplate"](context)); - - tippy(".btn"); - } - - previousCallData = data; - - setTimeout(getLogs, 1500); - }); -} - -function copyTextToClipboard(text) { - if (!navigator.clipboard) { - fallbackCopyTextToClipboard(text); - return; - } - - navigator.clipboard.writeText(text).then(() => { }, () => { - fallbackCopyTextToClipboard(text); - }); -} - -function fallbackCopyTextToClipboard(text) { - var textarea = document.createElement("textarea"); - - textarea.textContent = text; - document.body.appendChild(textarea); - - var selection = document.getSelection(); - var range = document.createRange(); - - range.selectNode(textarea); - selection.removeAllRanges(); - selection.addRange(range); - - console.log("copy success", document.execCommand("copy")); - - selection.removeAllRanges(); - - document.body.removeChild(textarea); -} \ No newline at end of file diff --git a/content/js/buttons.js b/content/js/buttons.js new file mode 100644 index 0000000..0f3b81d --- /dev/null +++ b/content/js/buttons.js @@ -0,0 +1 @@ +!function(){"use strict";var d,l,s,e,t,o,h=window.document,n=h.location,p=window.encodeURIComponent,c=window.decodeURIComponent,r=window.Math,u=function(e){return h.createElement(e)};l="github-button",d=(/^http:/.test(n)?"http":"https")+"://buttons.github.io",s="/buttons.html",e=function(e){d=e},t="currentScript",o=!{}.hasOwnProperty.call(h,t)&&h[t]&&delete h[t]&&h[t]?h[t].src:void 0;var f,g,a;f=function(e,t,o){e.addEventListener?e.addEventListener(""+t,o):e.attachEvent("on"+t,o)},g=function(t,o,n){var r;f(t,o,r=function(e){return t.removeEventListener?t.removeEventListener(""+o,r):t.detachEvent("on"+o,r),n(e)})},a=function(e){var t,o;/m/.test(h.readyState)||!/g/.test(h.readyState)&&!h.documentElement.doScroll?setTimeout(e):h.addEventListener?(o=0,g(h,"DOMContentLoaded",t=function(){!o&&(o=1)&&e()}),g(window,"load",t)):(t=function(){/m/.test(h.readyState)&&(h.detachEvent("onreadystatechange",t),e())},h.attachEvent("onreadystatechange",t))};var m,w,b,v,x,i,C,y,F,k,z="body{margin:0}a{color:#24292e;text-decoration:none;outline:0}.widget{display:inline-block;overflow:hidden;font-family:-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;font-size:0;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn,.social-count{display:inline-block;font-weight:600;vertical-align:bottom;cursor:pointer;border:1px solid #d1d2d3;border-radius:0.25em}.btn:focus,.social-count:focus{border-color:#c8e1ff}.btn{background-color:#eff3f6;background-image:-webkit-linear-gradient(top, #fafbfc, #e4ebf0);background-image:-moz-linear-gradient(top, #fafbfc, #e4ebf0);background-image:linear-gradient(to bottom, #fafbfc, #e4ebf0);background-repeat:repeat-x;background-size:110% 110%;-ms-filter:\"progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFAFBFC', endColorstr='#FFE4EBF0')\";*filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFAFBFC', endColorstr='#FFE4EBF0')}.btn:active{background-color:#e9ecef;background-image:none;border-color:#afb1b2;box-shadow:inset 0 0.15em 0.3em rgba(27,31,35,0.15)}.btn:hover{background-color:#e6ebf1;background-image:-webkit-linear-gradient(top, #f0f3f6, #dce3ec);background-image:-moz-linear-gradient(top, #f0f3f6, #dce3ec);background-image:linear-gradient(to bottom, #f0f3f6, #dce3ec);border-color:#afb1b2;-ms-filter:\"progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF0F3F6', endColorstr='#FFDCE3EC')\";*filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF0F3F6', endColorstr='#FFDCE3EC')}.social-count{position:relative;background-color:#fff}.social-count:hover{color:#0366d6}.octicon{position:relative;display:inline-block;vertical-align:top;fill:currentColor}.btn,.social-count{height:18px;padding:0 5px;line-height:18px}.btn{font-size:11px}.social-count{margin-left:5px;font-size:10px}.octicon{height:14px;top:2px}.large .btn,.large .social-count{height:26px;line-height:26px}.large .btn{padding:0 10px;font-size:12px}.large .social-count{padding:0 7px;margin-left:7px;font-size:11px}.large .octicon{height:18px;top:4px}.social-count b,.social-count i{position:absolute;top:50%;right:100%;display:block;width:0;height:0;margin-top:-4px;_font-size:0;_line-height:0;border:solid transparent;border-width:4px 4px 4px 0}.social-count b{margin-right:0;border-right-color:#d1d2d3}.social-count:focus b{border-right-color:#c8e1ff}.social-count i{margin-right:-1.5px;border-right-color:#fff}.social-count b,.social-count i{_border-top-color:red !important;_border-bottom-color:red !important;_border-left-color:red !important;_filter:chroma(color=red)}.large .social-count b,.large .social-count i{margin-top:-6px;border-width:6px 6px 6px 0}\n",E={"mark-github":{width:16,height:16,path:''},eye:{width:16,height:16,path:''},star:{width:14,height:16,path:''},"repo-forked":{width:10,height:16,path:''},"issue-opened":{width:14,height:16,path:''},"cloud-download":{width:16,height:16,path:''}};m=function(e,t){return e=(""+e).toLowerCase().replace(/^octicon-/,""),E.hasOwnProperty(e)||(e="mark-github"),'"},b={},w=function(e,t){var o,n,r,a,i,l,c,d;1<(l=b[e]||(b[e]=[])).push(t)||(a=0,n=function(){if(!a&&(a=1))for(delete b[e];t=l.shift();)t.apply(null,arguments)},(o=window.XMLHttpRequest)&&"withCredentials"in o.prototype?(d=new o,f(d,"abort",n),f(d,"error",n),f(d,"load",function(){n(200!==d.status,function(){try{return JSON.parse(d.responseText)}catch(e){}}())}),d.open("GET",e),d.send()):((r=this||window)._=function(e){r._=null,n(200!==e.meta.status,e.data)},(c=r.document.createElement("script")).async=!0,c.src=e+(/\?/.test(e)?"&":"?")+"callback=_",f(c,"error",i=function(){r._&&r._({meta:{}})}),c.readyState&&f(c,"readystatechange",function(){"loaded"===c.readyState&&i()}),r.document.getElementsByTagName("head")[0].appendChild(c)))},v=function(e,t,o){var r,a,n,i,l,c,d,s,h,p,u,f,g,b;t&&(n=this,c=e.ownerDocument,l=function(e){return c.createTextNode(e)},(d=(i=function(e){return c.createElement(e)})("style")).type="text/css",e.appendChild(d),d.styleSheet?d.styleSheet.cssText=z:d.appendChild(l(z)),(s=e.appendChild(i("div"))).className="widget"+(/^large$/i.test(t["data-size"])?" large":""),a=function(){o&&o(s)},(h=i("a")).href=t.href,h.target="_blank",/\.github\.com$/.test("."+h.hostname)?/^https?:\/\/((gist\.)?github\.com\/[^\/?#]+\/[^\/?#]+\/archive\/|github\.com\/[^\/?#]+\/[^\/?#]+\/releases\/download\/|codeload\.github\.com\/)/.test(h.href)&&(h.target="_top"):(h.href="#",h.target="_self"),h.className="btn",(p=t["aria-label"])&&h.setAttribute("aria-label",p),h.innerHTML=m(t["data-icon"],/^large$/i.test(t["data-size"])?16:14),h.appendChild(l(" ")),h.appendChild(i("span")).appendChild(l(t["data-text"]||"")),r=s.appendChild(h),/^(true|1)$/i.test(t["data-show-count"])&&"github.com"===r.hostname?!(g=r.pathname.replace(/^(?!\/)/,"/").match(/^\/([^\/?#]+)(?:\/([^\/?#]+)(?:\/(?:(subscription)|(fork)|(issues)|([^\/?#]+)))?)?(?:[\/?#]|$)/))||g[6]?a():(g[2]?(u="/repos/"+g[1]+"/"+g[2],g[3]?(b="subscribers_count",f="watchers"):g[4]?(b="forks_count",f="network"):g[5]?(b="open_issues_count",f="issues"):(b="stargazers_count",f="stargazers")):(u="/users/"+g[1],f=b="followers"),w.call(n,"https://api.github.com"+u,function(e,t){var o,n;e||(n=t[b],(o=i("a")).href=t.html_url+"/"+f,o.target="_blank",o.className="social-count",o.setAttribute("aria-label",n+" "+b.replace(/_count$/,"").replace("_"," ")+" on GitHub"),o.appendChild(i("b")),o.appendChild(i("i")),o.appendChild(i("span")).appendChild(c.createTextNode((""+n).replace(/\B(?=(\d{3})+(?!\d))/g,","))),r.parentNode.insertBefore(o,r.nextSibling)),a()})):a())},x=function(){var e,t,o,n,r,a,i;if(t=[],h.querySelectorAll)t=h.querySelectorAll("a."+l);else for(o=0,r=(i=h.getElementsByTagName("a")).length;o 0) { - showValidationErrors(data.Errors, true); - return; - } - - var baseUrlWithoutQueryString = window.location.href.split("?")[0]; - var baseUrlWithoutHash = baseUrlWithoutQueryString.split("#")[0]; - var rand = Math.random(); - var hash = it.indexOf("ytd") !== -1 ? "#year-to-date-instructions" : "#instructions"; - var urlToRedirectTo = baseUrlWithoutHash + "?status=Pay instruction saved&statusType=success&rand=" + rand + hash; - - window.location.replace(urlToRedirectTo); - }); - }); - - $(".btn-delete-instruction").on("click", function() { - var $self = $(this); - var id = $self.attr("data-id"); - var employeeId = $self.attr("data-employee-id"); - var employerId = $self.attr("data-employer-id"); - - bootbox.confirm({ - title: "Are you sure?", - message: "Are you sure you want to delete this pay instruction?", - callback: function(result) { - if (result) { - var postUrl = `/employer/${employerId}/employee/${employeeId}/payInstruction/${id}/delete`; - - $.post(postUrl).done(function(data) { - if (data.errors) { - showValidationErrors(data.errors); - return; - } - - var $tr = $self.closest("tr"); - - $tr.find("td").fadeOut("fast", function() { - var $table = $tr.closest("table"); - - if ($table.find("tbody tr").length < 2) { - $table.closest("div.card").remove(); - } - - $tr.remove(); - - showStatus("Instruction successfully deleted", "success"); - }); - }); - } - } - }); - }); -}); \ No newline at end of file diff --git a/content/js/employer.js b/content/js/employer.js deleted file mode 100644 index 5b2a300..0000000 --- a/content/js/employer.js +++ /dev/null @@ -1,163 +0,0 @@ -$(function() { - var hash = window.location.hash; - - if (hash) { - $(`ul.nav a[href="${hash}"]`).tab("show"); - } - - if (getUrlVars().jobId) { - bindJobInfo(); - } - - $(".nav-tabs a").on("click", function() { - $(this).tab("show"); - - window.location.hash = this.hash; - }); - - $(".btn-default-for-ae").on("click", function() { - var $self = $(this); - var id = $self.attr("data-id"); - var employerId = $self.attr("data-employer-id"); - - $.post(`/employer/${employerId}/pension/${id}/ae-default`).done(function() { - showStatus("Pension defaulted for auto enrolment", "success"); - - $self.fadeOut(); - }); - }); - - $(".btn-delete-pay-schedule").on("click", function() { - var $self = $(this); - var id = $self.attr("data-pay-schedule-id"); - var employerId = $self.attr("data-employer-id"); - - bootbox.confirm({ - title: "Are you sure?", - message: "Are you sure you want to delete this pay schedule?", - callback: function(result) { - if (result) { - $.post("/employer/" + employerId + "/paySchedule/" + id + "/delete") - .done(function(data) { - if (data.errors) { - showValidationErrors(data.errors); - return; - } - - var $tr = $self.closest("tr"); - - $tr.find("td").fadeOut("fast", function() { - $tr.remove(); - }); - }); - } - } - }); - }); - - $(".btn-delete-pay-run").on("click", function() { - var $self = $(this); - var id = $self.attr("data-pay-run-id"); - var scheduleId = $self.attr("data-pay-schedule-id"); - var employerId = $self.attr("data-employer-id"); - - bootbox.confirm({ - title: "Are you sure?", - message: "Are you sure you want to delete this payrun?", - callback: function (result) { - if (result) { - $.post("/employer/" + employerId + "/paySchedule/" + scheduleId + "/PayRun/" + id + "/delete") - .done(function() { - var $tr = $self.closest("tr"); - - $tr.find("td").fadeOut("fast", function() { - $tr.remove(); - }); - }) - .fail(function(xhr, status, error) { - alert(error); - }); - } - } - }); - }); - - $(".btn-delete-pension").on("click", function() { - var $self = $(this); - var employerId = $self.attr("data-employer-id"); - var id = $self.attr("data-id"); - - bootbox.confirm({ - title: "Are you sure?", - message: "Are you sure you want to delete this pension record?", - callback: function(result) { - if (result) { - $.post(`/employer/${employerId}/pension/${id}/delete`) - .done(function() { - var $tr = $self.closest("tr"); - - $tr.find("td").fadeOut("fast", function() { - var $table = $tr.closest("table"); - - if ($table.find("tbody tr").length < 2) { - $table.remove(); - } - - $tr.remove(); - }); - }) - .fail(function(xhr, status, error) { - alert(error); - }); - } - } - }); - }); - - $(document).on("click", ".job-info-container .close", function () { - closeJobInfo(); - }); -}); - -function bindJobInfo() { - var jobId = getUrlVars().jobId; - var employerId = $("input[type=hidden]#employer-id").val(); - - var url = "/employer/" + employerId + "/job/" + jobId + "/payrun"; - - $.getJSON(url, function(data) { - if (!window.hideJobInfo) { - // if the job has completed and there are no errors to display then start increasing the - // completed job count. Once the completed job count has reached 3 (3 seconds based on the setTimeout further down) - // then close the job info panel. This is so that users can see that a job has been run (esp. where the job is v. small) - if (data.Progress === 100 && (data.Errors === null || data.Errors.length === 0)) { - if (window.completedJobCount === undefined) { - window.completedJobCount = 0; - } - - window.completedJobCount++; - - if (window.completedJobCount === 3) { - closeJobInfo(); - - var url = window.location.href; - var urlWithoutQs = $.trim(url.split("?")[0]); - var urlWithStatus = urlWithoutQs + "?status=Pay run ran successfully&statusType=success#runs"; - - window.location.href = urlWithStatus; - } - } - - $(".job-info-container").html(Templates["jobInfoTemplate"](data)); - - setTimeout(bindJobInfo, 1000); - } - }); -} - -function closeJobInfo() { - var $jobInfoContainer = $(".job-info-container"); - - $jobInfoContainer.slideUp(); // todo: may be good to change this animation. - window.hideJobInfo = true; -} \ No newline at end of file diff --git a/content/js/global.js b/content/js/global.js deleted file mode 100644 index 6a1adf4..0000000 --- a/content/js/global.js +++ /dev/null @@ -1,166 +0,0 @@ -$(function() { - var openAPICallsOnLoad = $("input[type=hidden]#open-api-calls").val().toLowerCase() === "true"; - var apiCallsHeight = $("input[type=hidden]#api-calls-height").val(); - - $(".api-calls").resizable({ - handleSelector: ".row.resize-handle", - resizeWidth: false, - resizeHeight: true, - resizeHeightFrom: "top", - onDrag: function (e, $el, newWidth, newHeight) { - setAPICallsHeight(newHeight); - } - }); - - if (openAPICallsOnLoad) { - openAPICalls(); - setAPICallsHeight(apiCallsHeight); - } - - $(".view-api-calls").on("click", function() { - openAPICalls(); - - $.post("/api-calls/is-open", { open: true }); - }); - - $(".close-api-calls").on("click", function() { - $("body").removeClass("api-calls-open"); - $("body").removeAttr("style"); - $(".api-calls").hide(); - - $.post("/api-calls/is-open", { open: false }); - }); - - $(".launch-modal").on("click", function(e){ - e.preventDefault(); - - var $modal = $("#myModal"); - - if (this.hasAttribute("data-modal-title")) { - var title = this.getAttribute("data-modal-title"); - - $modal.find("h4.modal-title").text(title); - } - - $modal.find(".modal-dialog").removeClass("modal-lg").removeClass("modal-sm"); - - if (this.hasAttribute("data-modal-size")) { - var size = this.getAttribute("data-modal-size"); - - $modal.find(".modal-dialog").addClass(size); - } - - $modal.modal("show").find(".modal-body").load($(this).attr("href")); - }); - - $("#myModal button[type=submit]").on("click", function() { - var form = $("#myModal form"); - - if (form.parsley) { - form.parsley().validate(); - - if (form.parsley().isValid()) { - form.submit(); - } - } - }); - - window.Parsley.on("form:success", function() { - $("#validation-errors").hide(); - }); - - window.Parsley.on("form:error", function() { - var errorMessages = this.$element.find(".parsley-error").map(function() { - return $(this).attr("data-required-message"); - }).toArray(); - - var modal = this.$element.closest("#myModal").length > 0; - - showValidationErrors(errorMessages, modal); - }); -}); - -function openAPICalls() { - $("body").addClass("api-calls-open"); - $(".api-calls").show(); -} - -function setAPICallsHeight(height) { - if (height < 50) { - height = 50; - } - - $(".api-calls").height(height); - $("body.api-calls-open").css("margin-bottom", height + "px"); - $(".api-calls-container").css("height", height - 36 + "px"); - - $.post("/api-calls/size", { size: height }); - - return false; -} - -function showValidationErrors(errors, modal) { - // hide any successful status messages that are currently being shown - $(".alert-success").hide(); - - var errorMessages = errors.map(function(error) { - return "
  • " + error + "
  • "; - }); - - var $validationErrors = $("#validation-errors"); - - if (modal) { - $validationErrors = $("#myModal").find("#validation-errors"); - } - - $validationErrors.find("ul").html(errorMessages); - $validationErrors.show(); - - $("html, body").animate({ - scrollTop: $validationErrors.offset().top - }, 500); -} - -// eslint-disable-next-line no-unused-vars -function showStatus(message, type) { - var $alert = $(".status.alert"); - - $alert - .removeClass("alert-") - .removeClass("alert-primary") - .removeClass("alert-secondary") - .removeClass("alert-success") - .removeClass("alert-danger") - .removeClass("alert-warning") - .removeClass("alert-info") - .addClass(`alert-${type}`); - - $alert.find("span").eq(0).html(message); - $alert.fadeIn(); -} - -// eslint-disable-next-line no-unused-vars -function getUrlVars() { - var output = []; - var parts = window.location.href.slice(window.location.href.indexOf("?") + 1).split("&"); - - for (var i = 0; i < parts.length; i++) { - var qsParts = parts[i].split("="); - - if (qsParts.length === 1) { - continue; - } - - var name = qsParts[0]; - var value = qsParts[1].split("#")[0]; - - if (value) { - // get the query string value without the hash value - value = value.split("#")[0]; - } - - output[name] = value; - } - - return output; -} \ No newline at end of file diff --git a/content/js/handlebars-v4.0.11.js b/content/js/handlebars-v4.0.11.js deleted file mode 100644 index 95fe5d4..0000000 --- a/content/js/handlebars-v4.0.11.js +++ /dev/null @@ -1,4841 +0,0 @@ -/* eslint-disable */ -/**! - - @license - handlebars v4.0.11 - -Copyright (C) 2011-2017 by Yehuda Katz - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -*/ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["Handlebars"] = factory(); - else - root["Handlebars"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _handlebarsRuntime = __webpack_require__(2); - - var _handlebarsRuntime2 = _interopRequireDefault(_handlebarsRuntime); - - // Compiler imports - - var _handlebarsCompilerAst = __webpack_require__(35); - - var _handlebarsCompilerAst2 = _interopRequireDefault(_handlebarsCompilerAst); - - var _handlebarsCompilerBase = __webpack_require__(36); - - var _handlebarsCompilerCompiler = __webpack_require__(41); - - var _handlebarsCompilerJavascriptCompiler = __webpack_require__(42); - - var _handlebarsCompilerJavascriptCompiler2 = _interopRequireDefault(_handlebarsCompilerJavascriptCompiler); - - var _handlebarsCompilerVisitor = __webpack_require__(39); - - var _handlebarsCompilerVisitor2 = _interopRequireDefault(_handlebarsCompilerVisitor); - - var _handlebarsNoConflict = __webpack_require__(34); - - var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict); - - var _create = _handlebarsRuntime2['default'].create; - function create() { - var hb = _create(); - - hb.compile = function (input, options) { - return _handlebarsCompilerCompiler.compile(input, options, hb); - }; - hb.precompile = function (input, options) { - return _handlebarsCompilerCompiler.precompile(input, options, hb); - }; - - hb.AST = _handlebarsCompilerAst2['default']; - hb.Compiler = _handlebarsCompilerCompiler.Compiler; - hb.JavaScriptCompiler = _handlebarsCompilerJavascriptCompiler2['default']; - hb.Parser = _handlebarsCompilerBase.parser; - hb.parse = _handlebarsCompilerBase.parse; - - return hb; - } - - var inst = create(); - inst.create = create; - - _handlebarsNoConflict2['default'](inst); - - inst.Visitor = _handlebarsCompilerVisitor2['default']; - - inst['default'] = inst; - - exports['default'] = inst; - module.exports = exports['default']; - -/***/ }), -/* 1 */ -/***/ (function(module, exports) { - - "use strict"; - - exports["default"] = function (obj) { - return obj && obj.__esModule ? obj : { - "default": obj - }; - }; - - exports.__esModule = true; - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireWildcard = __webpack_require__(3)['default']; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _handlebarsBase = __webpack_require__(4); - - var base = _interopRequireWildcard(_handlebarsBase); - - // Each of these augment the Handlebars object. No need to setup here. - // (This is done to easily share code between commonjs and browse envs) - - var _handlebarsSafeString = __webpack_require__(21); - - var _handlebarsSafeString2 = _interopRequireDefault(_handlebarsSafeString); - - var _handlebarsException = __webpack_require__(6); - - var _handlebarsException2 = _interopRequireDefault(_handlebarsException); - - var _handlebarsUtils = __webpack_require__(5); - - var Utils = _interopRequireWildcard(_handlebarsUtils); - - var _handlebarsRuntime = __webpack_require__(22); - - var runtime = _interopRequireWildcard(_handlebarsRuntime); - - var _handlebarsNoConflict = __webpack_require__(34); - - var _handlebarsNoConflict2 = _interopRequireDefault(_handlebarsNoConflict); - - // For compatibility and usage outside of module systems, make the Handlebars object a namespace - function create() { - var hb = new base.HandlebarsEnvironment(); - - Utils.extend(hb, base); - hb.SafeString = _handlebarsSafeString2['default']; - hb.Exception = _handlebarsException2['default']; - hb.Utils = Utils; - hb.escapeExpression = Utils.escapeExpression; - - hb.VM = runtime; - hb.template = function (spec) { - return runtime.template(spec, hb); - }; - - return hb; - } - - var inst = create(); - inst.create = create; - - _handlebarsNoConflict2['default'](inst); - - inst['default'] = inst; - - exports['default'] = inst; - module.exports = exports['default']; - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - - "use strict"; - - exports["default"] = function (obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {}; - - if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - } - - newObj["default"] = obj; - return newObj; - } - }; - - exports.__esModule = true; - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.HandlebarsEnvironment = HandlebarsEnvironment; - - var _utils = __webpack_require__(5); - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - var _helpers = __webpack_require__(10); - - var _decorators = __webpack_require__(18); - - var _logger = __webpack_require__(20); - - var _logger2 = _interopRequireDefault(_logger); - - var VERSION = '4.0.11'; - exports.VERSION = VERSION; - var COMPILER_REVISION = 7; - - exports.COMPILER_REVISION = COMPILER_REVISION; - var REVISION_CHANGES = { - 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it - 2: '== 1.0.0-rc.3', - 3: '== 1.0.0-rc.4', - 4: '== 1.x.x', - 5: '== 2.0.0-alpha.x', - 6: '>= 2.0.0-beta.1', - 7: '>= 4.0.0' - }; - - exports.REVISION_CHANGES = REVISION_CHANGES; - var objectType = '[object Object]'; - - function HandlebarsEnvironment(helpers, partials, decorators) { - this.helpers = helpers || {}; - this.partials = partials || {}; - this.decorators = decorators || {}; - - _helpers.registerDefaultHelpers(this); - _decorators.registerDefaultDecorators(this); - } - - HandlebarsEnvironment.prototype = { - constructor: HandlebarsEnvironment, - - logger: _logger2['default'], - log: _logger2['default'].log, - - registerHelper: function registerHelper(name, fn) { - if (_utils.toString.call(name) === objectType) { - if (fn) { - throw new _exception2['default']('Arg not supported with multiple helpers'); - } - _utils.extend(this.helpers, name); - } else { - this.helpers[name] = fn; - } - }, - unregisterHelper: function unregisterHelper(name) { - delete this.helpers[name]; - }, - - registerPartial: function registerPartial(name, partial) { - if (_utils.toString.call(name) === objectType) { - _utils.extend(this.partials, name); - } else { - if (typeof partial === 'undefined') { - throw new _exception2['default']('Attempting to register a partial called "' + name + '" as undefined'); - } - this.partials[name] = partial; - } - }, - unregisterPartial: function unregisterPartial(name) { - delete this.partials[name]; - }, - - registerDecorator: function registerDecorator(name, fn) { - if (_utils.toString.call(name) === objectType) { - if (fn) { - throw new _exception2['default']('Arg not supported with multiple decorators'); - } - _utils.extend(this.decorators, name); - } else { - this.decorators[name] = fn; - } - }, - unregisterDecorator: function unregisterDecorator(name) { - delete this.decorators[name]; - } - }; - - var log = _logger2['default'].log; - - exports.log = log; - exports.createFrame = _utils.createFrame; - exports.logger = _logger2['default']; - -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - - 'use strict'; - - exports.__esModule = true; - exports.extend = extend; - exports.indexOf = indexOf; - exports.escapeExpression = escapeExpression; - exports.isEmpty = isEmpty; - exports.createFrame = createFrame; - exports.blockParams = blockParams; - exports.appendContextPath = appendContextPath; - var escape = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`', - '=': '=' - }; - - var badChars = /[&<>"'`=]/g, - possible = /[&<>"'`=]/; - - function escapeChar(chr) { - return escape[chr]; - } - - function extend(obj /* , ...source */) { - for (var i = 1; i < arguments.length; i++) { - for (var key in arguments[i]) { - if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { - obj[key] = arguments[i][key]; - } - } - } - - return obj; - } - - var toString = Object.prototype.toString; - - exports.toString = toString; - // Sourced from lodash - // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt - /* eslint-disable func-style */ - var isFunction = function isFunction(value) { - return typeof value === 'function'; - }; - // fallback for older versions of Chrome and Safari - /* istanbul ignore next */ - if (isFunction(/x/)) { - exports.isFunction = isFunction = function (value) { - return typeof value === 'function' && toString.call(value) === '[object Function]'; - }; - } - exports.isFunction = isFunction; - - /* eslint-enable func-style */ - - /* istanbul ignore next */ - var isArray = Array.isArray || function (value) { - return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; - }; - - exports.isArray = isArray; - // Older IE versions do not directly support indexOf so we must implement our own, sadly. - - function indexOf(array, value) { - for (var i = 0, len = array.length; i < len; i++) { - if (array[i] === value) { - return i; - } - } - return -1; - } - - function escapeExpression(string) { - if (typeof string !== 'string') { - // don't escape SafeStrings, since they're already safe - if (string && string.toHTML) { - return string.toHTML(); - } else if (string == null) { - return ''; - } else if (!string) { - return string + ''; - } - - // Force a string conversion as this will be done by the append regardless and - // the regex test will do this transparently behind the scenes, causing issues if - // an object's to string has escaped characters in it. - string = '' + string; - } - - if (!possible.test(string)) { - return string; - } - return string.replace(badChars, escapeChar); - } - - function isEmpty(value) { - if (!value && value !== 0) { - return true; - } else if (isArray(value) && value.length === 0) { - return true; - } else { - return false; - } - } - - function createFrame(object) { - var frame = extend({}, object); - frame._parent = object; - return frame; - } - - function blockParams(params, ids) { - params.path = ids; - return params; - } - - function appendContextPath(contextPath, id) { - return (contextPath ? contextPath + '.' : '') + id; - } - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _Object$defineProperty = __webpack_require__(7)['default']; - - exports.__esModule = true; - - var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; - - function Exception(message, node) { - var loc = node && node.loc, - line = undefined, - column = undefined; - if (loc) { - line = loc.start.line; - column = loc.start.column; - - message += ' - ' + line + ':' + column; - } - - var tmp = Error.prototype.constructor.call(this, message); - - // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. - for (var idx = 0; idx < errorProps.length; idx++) { - this[errorProps[idx]] = tmp[errorProps[idx]]; - } - - /* istanbul ignore else */ - if (Error.captureStackTrace) { - Error.captureStackTrace(this, Exception); - } - - try { - if (loc) { - this.lineNumber = line; - - // Work around issue under safari where we can't directly set the column value - /* istanbul ignore next */ - if (_Object$defineProperty) { - Object.defineProperty(this, 'column', { - value: column, - enumerable: true - }); - } else { - this.column = column; - } - } - } catch (nop) { - /* Ignore if the browser is very particular */ - } - } - - Exception.prototype = new Error(); - - exports['default'] = Exception; - module.exports = exports['default']; - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - - module.exports = { "default": __webpack_require__(8), __esModule: true }; - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - - var $ = __webpack_require__(9); - module.exports = function defineProperty(it, key, desc){ - return $.setDesc(it, key, desc); - }; - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - - var $Object = Object; - module.exports = { - create: $Object.create, - getProto: $Object.getPrototypeOf, - isEnum: {}.propertyIsEnumerable, - getDesc: $Object.getOwnPropertyDescriptor, - setDesc: $Object.defineProperty, - setDescs: $Object.defineProperties, - getKeys: $Object.keys, - getNames: $Object.getOwnPropertyNames, - getSymbols: $Object.getOwnPropertySymbols, - each: [].forEach - }; - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.registerDefaultHelpers = registerDefaultHelpers; - - var _helpersBlockHelperMissing = __webpack_require__(11); - - var _helpersBlockHelperMissing2 = _interopRequireDefault(_helpersBlockHelperMissing); - - var _helpersEach = __webpack_require__(12); - - var _helpersEach2 = _interopRequireDefault(_helpersEach); - - var _helpersHelperMissing = __webpack_require__(13); - - var _helpersHelperMissing2 = _interopRequireDefault(_helpersHelperMissing); - - var _helpersIf = __webpack_require__(14); - - var _helpersIf2 = _interopRequireDefault(_helpersIf); - - var _helpersLog = __webpack_require__(15); - - var _helpersLog2 = _interopRequireDefault(_helpersLog); - - var _helpersLookup = __webpack_require__(16); - - var _helpersLookup2 = _interopRequireDefault(_helpersLookup); - - var _helpersWith = __webpack_require__(17); - - var _helpersWith2 = _interopRequireDefault(_helpersWith); - - function registerDefaultHelpers(instance) { - _helpersBlockHelperMissing2['default'](instance); - _helpersEach2['default'](instance); - _helpersHelperMissing2['default'](instance); - _helpersIf2['default'](instance); - _helpersLog2['default'](instance); - _helpersLookup2['default'](instance); - _helpersWith2['default'](instance); - } - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - exports['default'] = function (instance) { - instance.registerHelper('blockHelperMissing', function (context, options) { - var inverse = options.inverse, - fn = options.fn; - - if (context === true) { - return fn(this); - } else if (context === false || context == null) { - return inverse(this); - } else if (_utils.isArray(context)) { - if (context.length > 0) { - if (options.ids) { - options.ids = [options.name]; - } - - return instance.helpers.each(context, options); - } else { - return inverse(this); - } - } else { - if (options.data && options.ids) { - var data = _utils.createFrame(options.data); - data.contextPath = _utils.appendContextPath(options.data.contextPath, options.name); - options = { data: data }; - } - - return fn(context, options); - } - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - exports['default'] = function (instance) { - instance.registerHelper('each', function (context, options) { - if (!options) { - throw new _exception2['default']('Must pass iterator to #each'); - } - - var fn = options.fn, - inverse = options.inverse, - i = 0, - ret = '', - data = undefined, - contextPath = undefined; - - if (options.data && options.ids) { - contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; - } - - if (_utils.isFunction(context)) { - context = context.call(this); - } - - if (options.data) { - data = _utils.createFrame(options.data); - } - - function execIteration(field, index, last) { - if (data) { - data.key = field; - data.index = index; - data.first = index === 0; - data.last = !!last; - - if (contextPath) { - data.contextPath = contextPath + field; - } - } - - ret = ret + fn(context[field], { - data: data, - blockParams: _utils.blockParams([context[field], field], [contextPath + field, null]) - }); - } - - if (context && typeof context === 'object') { - if (_utils.isArray(context)) { - for (var j = context.length; i < j; i++) { - if (i in context) { - execIteration(i, i, i === context.length - 1); - } - } - } else { - var priorKey = undefined; - - for (var key in context) { - if (context.hasOwnProperty(key)) { - // We're running the iterations one step out of sync so we can detect - // the last iteration without have to scan the object twice and create - // an itermediate keys array. - if (priorKey !== undefined) { - execIteration(priorKey, i - 1); - } - priorKey = key; - i++; - } - } - if (priorKey !== undefined) { - execIteration(priorKey, i - 1, true); - } - } - } - - if (i === 0) { - ret = inverse(this); - } - - return ret; - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - exports['default'] = function (instance) { - instance.registerHelper('helperMissing', function () /* [args, ]options */{ - if (arguments.length === 1) { - // A missing field in a {{foo}} construct. - return undefined; - } else { - // Someone is actually trying to call something, blow up. - throw new _exception2['default']('Missing helper: "' + arguments[arguments.length - 1].name + '"'); - } - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - exports['default'] = function (instance) { - instance.registerHelper('if', function (conditional, options) { - if (_utils.isFunction(conditional)) { - conditional = conditional.call(this); - } - - // Default behavior is to render the positive path if the value is truthy and not empty. - // The `includeZero` option may be set to treat the condtional as purely not empty based on the - // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative. - if (!options.hash.includeZero && !conditional || _utils.isEmpty(conditional)) { - return options.inverse(this); - } else { - return options.fn(this); - } - }); - - instance.registerHelper('unless', function (conditional, options) { - return instance.helpers['if'].call(this, conditional, { fn: options.inverse, inverse: options.fn, hash: options.hash }); - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - - 'use strict'; - - exports.__esModule = true; - - exports['default'] = function (instance) { - instance.registerHelper('log', function () /* message, options */{ - var args = [undefined], - options = arguments[arguments.length - 1]; - for (var i = 0; i < arguments.length - 1; i++) { - args.push(arguments[i]); - } - - var level = 1; - if (options.hash.level != null) { - level = options.hash.level; - } else if (options.data && options.data.level != null) { - level = options.data.level; - } - args[0] = level; - - instance.log.apply(instance, args); - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - - 'use strict'; - - exports.__esModule = true; - - exports['default'] = function (instance) { - instance.registerHelper('lookup', function (obj, field) { - return obj && obj[field]; - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - exports['default'] = function (instance) { - instance.registerHelper('with', function (context, options) { - if (_utils.isFunction(context)) { - context = context.call(this); - } - - var fn = options.fn; - - if (!_utils.isEmpty(context)) { - var data = options.data; - if (options.data && options.ids) { - data = _utils.createFrame(options.data); - data.contextPath = _utils.appendContextPath(options.data.contextPath, options.ids[0]); - } - - return fn(context, { - data: data, - blockParams: _utils.blockParams([context], [data && data.contextPath]) - }); - } else { - return options.inverse(this); - } - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.registerDefaultDecorators = registerDefaultDecorators; - - var _decoratorsInline = __webpack_require__(19); - - var _decoratorsInline2 = _interopRequireDefault(_decoratorsInline); - - function registerDefaultDecorators(instance) { - _decoratorsInline2['default'](instance); - } - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - exports['default'] = function (instance) { - instance.registerDecorator('inline', function (fn, props, container, options) { - var ret = fn; - if (!props.partials) { - props.partials = {}; - ret = function (context, options) { - // Create a new partials stack frame prior to exec. - var original = container.partials; - container.partials = _utils.extend({}, original, props.partials); - var ret = fn(context, options); - container.partials = original; - return ret; - }; - } - - props.partials[options.args[0]] = options.fn; - - return ret; - }); - }; - - module.exports = exports['default']; - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - var logger = { - methodMap: ['debug', 'info', 'warn', 'error'], - level: 'info', - - // Maps a given level value to the `methodMap` indexes above. - lookupLevel: function lookupLevel(level) { - if (typeof level === 'string') { - var levelMap = _utils.indexOf(logger.methodMap, level.toLowerCase()); - if (levelMap >= 0) { - level = levelMap; - } else { - level = parseInt(level, 10); - } - } - - return level; - }, - - // Can be overridden in the host environment - log: function log(level) { - level = logger.lookupLevel(level); - - if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) { - var method = logger.methodMap[level]; - if (!console[method]) { - // eslint-disable-line no-console - method = 'log'; - } - - for (var _len = arguments.length, message = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - message[_key - 1] = arguments[_key]; - } - - console[method].apply(console, message); // eslint-disable-line no-console - } - } - }; - - exports['default'] = logger; - module.exports = exports['default']; - -/***/ }), -/* 21 */ -/***/ (function(module, exports) { - - // Build out our basic SafeString type - 'use strict'; - - exports.__esModule = true; - function SafeString(string) { - this.string = string; - } - - SafeString.prototype.toString = SafeString.prototype.toHTML = function () { - return '' + this.string; - }; - - exports['default'] = SafeString; - module.exports = exports['default']; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _Object$seal = __webpack_require__(23)['default']; - - var _interopRequireWildcard = __webpack_require__(3)['default']; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.checkRevision = checkRevision; - exports.template = template; - exports.wrapProgram = wrapProgram; - exports.resolvePartial = resolvePartial; - exports.invokePartial = invokePartial; - exports.noop = noop; - - var _utils = __webpack_require__(5); - - var Utils = _interopRequireWildcard(_utils); - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - var _base = __webpack_require__(4); - - function checkRevision(compilerInfo) { - var compilerRevision = compilerInfo && compilerInfo[0] || 1, - currentRevision = _base.COMPILER_REVISION; - - if (compilerRevision !== currentRevision) { - if (compilerRevision < currentRevision) { - var runtimeVersions = _base.REVISION_CHANGES[currentRevision], - compilerVersions = _base.REVISION_CHANGES[compilerRevision]; - throw new _exception2['default']('Template was precompiled with an older version of Handlebars than the current runtime. ' + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); - } else { - // Use the embedded version info since the runtime doesn't know about this revision yet - throw new _exception2['default']('Template was precompiled with a newer version of Handlebars than the current runtime. ' + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); - } - } - } - - function template(templateSpec, env) { - /* istanbul ignore next */ - if (!env) { - throw new _exception2['default']('No environment passed to template'); - } - if (!templateSpec || !templateSpec.main) { - throw new _exception2['default']('Unknown template object: ' + typeof templateSpec); - } - - templateSpec.main.decorator = templateSpec.main_d; - - // Note: Using env.VM references rather than local var references throughout this section to allow - // for external users to override these as psuedo-supported APIs. - env.VM.checkRevision(templateSpec.compiler); - - function invokePartialWrapper(partial, context, options) { - if (options.hash) { - context = Utils.extend({}, context, options.hash); - if (options.ids) { - options.ids[0] = true; - } - } - - partial = env.VM.resolvePartial.call(this, partial, context, options); - var result = env.VM.invokePartial.call(this, partial, context, options); - - if (result == null && env.compile) { - options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env); - result = options.partials[options.name](context, options); - } - if (result != null) { - if (options.indent) { - var lines = result.split('\n'); - for (var i = 0, l = lines.length; i < l; i++) { - if (!lines[i] && i + 1 === l) { - break; - } - - lines[i] = options.indent + lines[i]; - } - result = lines.join('\n'); - } - return result; - } else { - throw new _exception2['default']('The partial ' + options.name + ' could not be compiled when running in runtime-only mode'); - } - } - - // Just add water - var container = { - strict: function strict(obj, name) { - if (!(name in obj)) { - throw new _exception2['default']('"' + name + '" not defined in ' + obj); - } - return obj[name]; - }, - lookup: function lookup(depths, name) { - var len = depths.length; - for (var i = 0; i < len; i++) { - if (depths[i] && depths[i][name] != null) { - return depths[i][name]; - } - } - }, - lambda: function lambda(current, context) { - return typeof current === 'function' ? current.call(context) : current; - }, - - escapeExpression: Utils.escapeExpression, - invokePartial: invokePartialWrapper, - - fn: function fn(i) { - var ret = templateSpec[i]; - ret.decorator = templateSpec[i + '_d']; - return ret; - }, - - programs: [], - program: function program(i, data, declaredBlockParams, blockParams, depths) { - var programWrapper = this.programs[i], - fn = this.fn(i); - if (data || depths || blockParams || declaredBlockParams) { - programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths); - } else if (!programWrapper) { - programWrapper = this.programs[i] = wrapProgram(this, i, fn); - } - return programWrapper; - }, - - data: function data(value, depth) { - while (value && depth--) { - value = value._parent; - } - return value; - }, - merge: function merge(param, common) { - var obj = param || common; - - if (param && common && param !== common) { - obj = Utils.extend({}, common, param); - } - - return obj; - }, - // An empty object to use as replacement for null-contexts - nullContext: _Object$seal({}), - - noop: env.VM.noop, - compilerInfo: templateSpec.compiler - }; - - function ret(context) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var data = options.data; - - ret._setup(options); - if (!options.partial && templateSpec.useData) { - data = initData(context, data); - } - var depths = undefined, - blockParams = templateSpec.useBlockParams ? [] : undefined; - if (templateSpec.useDepths) { - if (options.depths) { - depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; - } else { - depths = [context]; - } - } - - function main(context /*, options*/) { - return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths); - } - main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams); - return main(context, options); - } - ret.isTop = true; - - ret._setup = function (options) { - if (!options.partial) { - container.helpers = container.merge(options.helpers, env.helpers); - - if (templateSpec.usePartial) { - container.partials = container.merge(options.partials, env.partials); - } - if (templateSpec.usePartial || templateSpec.useDecorators) { - container.decorators = container.merge(options.decorators, env.decorators); - } - } else { - container.helpers = options.helpers; - container.partials = options.partials; - container.decorators = options.decorators; - } - }; - - ret._child = function (i, data, blockParams, depths) { - if (templateSpec.useBlockParams && !blockParams) { - throw new _exception2['default']('must pass block params'); - } - if (templateSpec.useDepths && !depths) { - throw new _exception2['default']('must pass parent depths'); - } - - return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); - }; - return ret; - } - - function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { - function prog(context) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - var currentDepths = depths; - if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) { - currentDepths = [context].concat(depths); - } - - return fn(container, context, container.helpers, container.partials, options.data || data, blockParams && [options.blockParams].concat(blockParams), currentDepths); - } - - prog = executeDecorators(fn, prog, container, depths, data, blockParams); - - prog.program = i; - prog.depth = depths ? depths.length : 0; - prog.blockParams = declaredBlockParams || 0; - return prog; - } - - function resolvePartial(partial, context, options) { - if (!partial) { - if (options.name === '@partial-block') { - partial = options.data['partial-block']; - } else { - partial = options.partials[options.name]; - } - } else if (!partial.call && !options.name) { - // This is a dynamic partial that returned a string - options.name = partial; - partial = options.partials[partial]; - } - return partial; - } - - function invokePartial(partial, context, options) { - // Use the current closure context to save the partial-block if this partial - var currentPartialBlock = options.data && options.data['partial-block']; - options.partial = true; - if (options.ids) { - options.data.contextPath = options.ids[0] || options.data.contextPath; - } - - var partialBlock = undefined; - if (options.fn && options.fn !== noop) { - (function () { - options.data = _base.createFrame(options.data); - // Wrapper function to get access to currentPartialBlock from the closure - var fn = options.fn; - partialBlock = options.data['partial-block'] = function partialBlockWrapper(context) { - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - - // Restore the partial-block from the closure for the execution of the block - // i.e. the part inside the block of the partial call. - options.data = _base.createFrame(options.data); - options.data['partial-block'] = currentPartialBlock; - return fn(context, options); - }; - if (fn.partials) { - options.partials = Utils.extend({}, options.partials, fn.partials); - } - })(); - } - - if (partial === undefined && partialBlock) { - partial = partialBlock; - } - - if (partial === undefined) { - throw new _exception2['default']('The partial ' + options.name + ' could not be found'); - } else if (partial instanceof Function) { - return partial(context, options); - } - } - - function noop() { - return ''; - } - - function initData(context, data) { - if (!data || !('root' in data)) { - data = data ? _base.createFrame(data) : {}; - data.root = context; - } - return data; - } - - function executeDecorators(fn, prog, container, depths, data, blockParams) { - if (fn.decorator) { - var props = {}; - prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths); - Utils.extend(prog, props); - } - return prog; - } - -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { - - module.exports = { "default": __webpack_require__(24), __esModule: true }; - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - - __webpack_require__(25); - module.exports = __webpack_require__(30).Object.seal; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - - // 19.1.2.17 Object.seal(O) - var isObject = __webpack_require__(26); - - __webpack_require__(27)('seal', function($seal){ - return function seal(it){ - return $seal && isObject(it) ? $seal(it) : it; - }; - }); - -/***/ }), -/* 26 */ -/***/ (function(module, exports) { - - module.exports = function(it){ - return typeof it === 'object' ? it !== null : typeof it === 'function'; - }; - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - - // most Object methods by ES6 should accept primitives - var $export = __webpack_require__(28) - , core = __webpack_require__(30) - , fails = __webpack_require__(33); - module.exports = function(KEY, exec){ - var fn = (core.Object || {})[KEY] || Object[KEY] - , exp = {}; - exp[KEY] = exec(fn); - $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); - }; - -/***/ }), -/* 28 */ -/***/ (function(module, exports, __webpack_require__) { - - var global = __webpack_require__(29) - , core = __webpack_require__(30) - , ctx = __webpack_require__(31) - , PROTOTYPE = 'prototype'; - - var $export = function(type, name, source){ - var IS_FORCED = type & $export.F - , IS_GLOBAL = type & $export.G - , IS_STATIC = type & $export.S - , IS_PROTO = type & $export.P - , IS_BIND = type & $export.B - , IS_WRAP = type & $export.W - , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) - , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] - , key, own, out; - if(IS_GLOBAL)source = name; - for(key in source){ - // contains in native - own = !IS_FORCED && target && key in target; - if(own && key in exports)continue; - // export native or passed - out = own ? target[key] : source[key]; - // prevent global pollution for namespaces - exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] - // bind timers to global for call from export context - : IS_BIND && own ? ctx(out, global) - // wrap global constructors for prevent change them in library - : IS_WRAP && target[key] == out ? (function(C){ - var F = function(param){ - return this instanceof C ? new C(param) : C(param); - }; - F[PROTOTYPE] = C[PROTOTYPE]; - return F; - // make static versions for prototype methods - })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; - if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out; - } - }; - // type bitmap - $export.F = 1; // forced - $export.G = 2; // global - $export.S = 4; // static - $export.P = 8; // proto - $export.B = 16; // bind - $export.W = 32; // wrap - module.exports = $export; - -/***/ }), -/* 29 */ -/***/ (function(module, exports) { - - // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 - var global = module.exports = typeof window != 'undefined' && window.Math == Math - ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); - if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef - -/***/ }), -/* 30 */ -/***/ (function(module, exports) { - - var core = module.exports = {version: '1.2.6'}; - if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef - -/***/ }), -/* 31 */ -/***/ (function(module, exports, __webpack_require__) { - - // optional / simple context binding - var aFunction = __webpack_require__(32); - module.exports = function(fn, that, length){ - aFunction(fn); - if(that === undefined)return fn; - switch(length){ - case 1: return function(a){ - return fn.call(that, a); - }; - case 2: return function(a, b){ - return fn.call(that, a, b); - }; - case 3: return function(a, b, c){ - return fn.call(that, a, b, c); - }; - } - return function(/* ...args */){ - return fn.apply(that, arguments); - }; - }; - -/***/ }), -/* 32 */ -/***/ (function(module, exports) { - - module.exports = function(it){ - if(typeof it != 'function')throw TypeError(it + ' is not a function!'); - return it; - }; - -/***/ }), -/* 33 */ -/***/ (function(module, exports) { - - module.exports = function(exec){ - try { - return !!exec(); - } catch(e){ - return true; - } - }; - -/***/ }), -/* 34 */ -/***/ (function(module, exports) { - - /* WEBPACK VAR INJECTION */(function(global) {/* global window */ - 'use strict'; - - exports.__esModule = true; - - exports['default'] = function (Handlebars) { - /* istanbul ignore next */ - var root = typeof global !== 'undefined' ? global : window, - $Handlebars = root.Handlebars; - /* istanbul ignore next */ - Handlebars.noConflict = function () { - if (root.Handlebars === Handlebars) { - root.Handlebars = $Handlebars; - } - return Handlebars; - }; - }; - - module.exports = exports['default']; - /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) - -/***/ }), -/* 35 */ -/***/ (function(module, exports) { - - 'use strict'; - - exports.__esModule = true; - var AST = { - // Public API used to evaluate derived attributes regarding AST nodes - helpers: { - // a mustache is definitely a helper if: - // * it is an eligible helper, and - // * it has at least one parameter or hash segment - helperExpression: function helperExpression(node) { - return node.type === 'SubExpression' || (node.type === 'MustacheStatement' || node.type === 'BlockStatement') && !!(node.params && node.params.length || node.hash); - }, - - scopedId: function scopedId(path) { - return (/^\.|this\b/.test(path.original) - ); - }, - - // an ID is simple if it only has one part, and that part is not - // `..` or `this`. - simpleId: function simpleId(path) { - return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth; - } - } - }; - - // Must be exported as an object rather than the root of the module as the jison lexer - // must modify the object to operate properly. - exports['default'] = AST; - module.exports = exports['default']; - -/***/ }), -/* 36 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - var _interopRequireWildcard = __webpack_require__(3)['default']; - - exports.__esModule = true; - exports.parse = parse; - - var _parser = __webpack_require__(37); - - var _parser2 = _interopRequireDefault(_parser); - - var _whitespaceControl = __webpack_require__(38); - - var _whitespaceControl2 = _interopRequireDefault(_whitespaceControl); - - var _helpers = __webpack_require__(40); - - var Helpers = _interopRequireWildcard(_helpers); - - var _utils = __webpack_require__(5); - - exports.parser = _parser2['default']; - - var yy = {}; - _utils.extend(yy, Helpers); - - function parse(input, options) { - // Just return if an already-compiled AST was passed in. - if (input.type === 'Program') { - return input; - } - - _parser2['default'].yy = yy; - - // Altering the shared object here, but this is ok as parser is a sync operation - yy.locInfo = function (locInfo) { - return new yy.SourceLocation(options && options.srcName, locInfo); - }; - - var strip = new _whitespaceControl2['default'](options); - return strip.accept(_parser2['default'].parse(input)); - } - -/***/ }), -/* 37 */ -/***/ (function(module, exports) { - - // File ignored in coverage tests via setting in .istanbul.yml - /* Jison generated parser */ - "use strict"; - - exports.__esModule = true; - var handlebars = (function () { - var parser = { trace: function trace() {}, - yy: {}, - symbols_: { "error": 2, "root": 3, "program": 4, "EOF": 5, "program_repetition0": 6, "statement": 7, "mustache": 8, "block": 9, "rawBlock": 10, "partial": 11, "partialBlock": 12, "content": 13, "COMMENT": 14, "CONTENT": 15, "openRawBlock": 16, "rawBlock_repetition_plus0": 17, "END_RAW_BLOCK": 18, "OPEN_RAW_BLOCK": 19, "helperName": 20, "openRawBlock_repetition0": 21, "openRawBlock_option0": 22, "CLOSE_RAW_BLOCK": 23, "openBlock": 24, "block_option0": 25, "closeBlock": 26, "openInverse": 27, "block_option1": 28, "OPEN_BLOCK": 29, "openBlock_repetition0": 30, "openBlock_option0": 31, "openBlock_option1": 32, "CLOSE": 33, "OPEN_INVERSE": 34, "openInverse_repetition0": 35, "openInverse_option0": 36, "openInverse_option1": 37, "openInverseChain": 38, "OPEN_INVERSE_CHAIN": 39, "openInverseChain_repetition0": 40, "openInverseChain_option0": 41, "openInverseChain_option1": 42, "inverseAndProgram": 43, "INVERSE": 44, "inverseChain": 45, "inverseChain_option0": 46, "OPEN_ENDBLOCK": 47, "OPEN": 48, "mustache_repetition0": 49, "mustache_option0": 50, "OPEN_UNESCAPED": 51, "mustache_repetition1": 52, "mustache_option1": 53, "CLOSE_UNESCAPED": 54, "OPEN_PARTIAL": 55, "partialName": 56, "partial_repetition0": 57, "partial_option0": 58, "openPartialBlock": 59, "OPEN_PARTIAL_BLOCK": 60, "openPartialBlock_repetition0": 61, "openPartialBlock_option0": 62, "param": 63, "sexpr": 64, "OPEN_SEXPR": 65, "sexpr_repetition0": 66, "sexpr_option0": 67, "CLOSE_SEXPR": 68, "hash": 69, "hash_repetition_plus0": 70, "hashSegment": 71, "ID": 72, "EQUALS": 73, "blockParams": 74, "OPEN_BLOCK_PARAMS": 75, "blockParams_repetition_plus0": 76, "CLOSE_BLOCK_PARAMS": 77, "path": 78, "dataName": 79, "STRING": 80, "NUMBER": 81, "BOOLEAN": 82, "UNDEFINED": 83, "NULL": 84, "DATA": 85, "pathSegments": 86, "SEP": 87, "$accept": 0, "$end": 1 }, - terminals_: { 2: "error", 5: "EOF", 14: "COMMENT", 15: "CONTENT", 18: "END_RAW_BLOCK", 19: "OPEN_RAW_BLOCK", 23: "CLOSE_RAW_BLOCK", 29: "OPEN_BLOCK", 33: "CLOSE", 34: "OPEN_INVERSE", 39: "OPEN_INVERSE_CHAIN", 44: "INVERSE", 47: "OPEN_ENDBLOCK", 48: "OPEN", 51: "OPEN_UNESCAPED", 54: "CLOSE_UNESCAPED", 55: "OPEN_PARTIAL", 60: "OPEN_PARTIAL_BLOCK", 65: "OPEN_SEXPR", 68: "CLOSE_SEXPR", 72: "ID", 73: "EQUALS", 75: "OPEN_BLOCK_PARAMS", 77: "CLOSE_BLOCK_PARAMS", 80: "STRING", 81: "NUMBER", 82: "BOOLEAN", 83: "UNDEFINED", 84: "NULL", 85: "DATA", 87: "SEP" }, - productions_: [0, [3, 2], [4, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [7, 1], [13, 1], [10, 3], [16, 5], [9, 4], [9, 4], [24, 6], [27, 6], [38, 6], [43, 2], [45, 3], [45, 1], [26, 3], [8, 5], [8, 5], [11, 5], [12, 3], [59, 5], [63, 1], [63, 1], [64, 5], [69, 1], [71, 3], [74, 3], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [20, 1], [56, 1], [56, 1], [79, 2], [78, 1], [86, 3], [86, 1], [6, 0], [6, 2], [17, 1], [17, 2], [21, 0], [21, 2], [22, 0], [22, 1], [25, 0], [25, 1], [28, 0], [28, 1], [30, 0], [30, 2], [31, 0], [31, 1], [32, 0], [32, 1], [35, 0], [35, 2], [36, 0], [36, 1], [37, 0], [37, 1], [40, 0], [40, 2], [41, 0], [41, 1], [42, 0], [42, 1], [46, 0], [46, 1], [49, 0], [49, 2], [50, 0], [50, 1], [52, 0], [52, 2], [53, 0], [53, 1], [57, 0], [57, 2], [58, 0], [58, 1], [61, 0], [61, 2], [62, 0], [62, 1], [66, 0], [66, 2], [67, 0], [67, 1], [70, 1], [70, 2], [76, 1], [76, 2]], - performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$ - /**/) { - - var $0 = $$.length - 1; - switch (yystate) { - case 1: - return $$[$0 - 1]; - break; - case 2: - this.$ = yy.prepareProgram($$[$0]); - break; - case 3: - this.$ = $$[$0]; - break; - case 4: - this.$ = $$[$0]; - break; - case 5: - this.$ = $$[$0]; - break; - case 6: - this.$ = $$[$0]; - break; - case 7: - this.$ = $$[$0]; - break; - case 8: - this.$ = $$[$0]; - break; - case 9: - this.$ = { - type: 'CommentStatement', - value: yy.stripComment($$[$0]), - strip: yy.stripFlags($$[$0], $$[$0]), - loc: yy.locInfo(this._$) - }; - - break; - case 10: - this.$ = { - type: 'ContentStatement', - original: $$[$0], - value: $$[$0], - loc: yy.locInfo(this._$) - }; - - break; - case 11: - this.$ = yy.prepareRawBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); - break; - case 12: - this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1] }; - break; - case 13: - this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], false, this._$); - break; - case 14: - this.$ = yy.prepareBlock($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0], true, this._$); - break; - case 15: - this.$ = { open: $$[$0 - 5], path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; - break; - case 16: - this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; - break; - case 17: - this.$ = { path: $$[$0 - 4], params: $$[$0 - 3], hash: $$[$0 - 2], blockParams: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 5], $$[$0]) }; - break; - case 18: - this.$ = { strip: yy.stripFlags($$[$0 - 1], $$[$0 - 1]), program: $$[$0] }; - break; - case 19: - var inverse = yy.prepareBlock($$[$0 - 2], $$[$0 - 1], $$[$0], $$[$0], false, this._$), - program = yy.prepareProgram([inverse], $$[$0 - 1].loc); - program.chained = true; - - this.$ = { strip: $$[$0 - 2].strip, program: program, chain: true }; - - break; - case 20: - this.$ = $$[$0]; - break; - case 21: - this.$ = { path: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 2], $$[$0]) }; - break; - case 22: - this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); - break; - case 23: - this.$ = yy.prepareMustache($$[$0 - 3], $$[$0 - 2], $$[$0 - 1], $$[$0 - 4], yy.stripFlags($$[$0 - 4], $$[$0]), this._$); - break; - case 24: - this.$ = { - type: 'PartialStatement', - name: $$[$0 - 3], - params: $$[$0 - 2], - hash: $$[$0 - 1], - indent: '', - strip: yy.stripFlags($$[$0 - 4], $$[$0]), - loc: yy.locInfo(this._$) - }; - - break; - case 25: - this.$ = yy.preparePartialBlock($$[$0 - 2], $$[$0 - 1], $$[$0], this._$); - break; - case 26: - this.$ = { path: $$[$0 - 3], params: $$[$0 - 2], hash: $$[$0 - 1], strip: yy.stripFlags($$[$0 - 4], $$[$0]) }; - break; - case 27: - this.$ = $$[$0]; - break; - case 28: - this.$ = $$[$0]; - break; - case 29: - this.$ = { - type: 'SubExpression', - path: $$[$0 - 3], - params: $$[$0 - 2], - hash: $$[$0 - 1], - loc: yy.locInfo(this._$) - }; - - break; - case 30: - this.$ = { type: 'Hash', pairs: $$[$0], loc: yy.locInfo(this._$) }; - break; - case 31: - this.$ = { type: 'HashPair', key: yy.id($$[$0 - 2]), value: $$[$0], loc: yy.locInfo(this._$) }; - break; - case 32: - this.$ = yy.id($$[$0 - 1]); - break; - case 33: - this.$ = $$[$0]; - break; - case 34: - this.$ = $$[$0]; - break; - case 35: - this.$ = { type: 'StringLiteral', value: $$[$0], original: $$[$0], loc: yy.locInfo(this._$) }; - break; - case 36: - this.$ = { type: 'NumberLiteral', value: Number($$[$0]), original: Number($$[$0]), loc: yy.locInfo(this._$) }; - break; - case 37: - this.$ = { type: 'BooleanLiteral', value: $$[$0] === 'true', original: $$[$0] === 'true', loc: yy.locInfo(this._$) }; - break; - case 38: - this.$ = { type: 'UndefinedLiteral', original: undefined, value: undefined, loc: yy.locInfo(this._$) }; - break; - case 39: - this.$ = { type: 'NullLiteral', original: null, value: null, loc: yy.locInfo(this._$) }; - break; - case 40: - this.$ = $$[$0]; - break; - case 41: - this.$ = $$[$0]; - break; - case 42: - this.$ = yy.preparePath(true, $$[$0], this._$); - break; - case 43: - this.$ = yy.preparePath(false, $$[$0], this._$); - break; - case 44: - $$[$0 - 2].push({ part: yy.id($$[$0]), original: $$[$0], separator: $$[$0 - 1] });this.$ = $$[$0 - 2]; - break; - case 45: - this.$ = [{ part: yy.id($$[$0]), original: $$[$0] }]; - break; - case 46: - this.$ = []; - break; - case 47: - $$[$0 - 1].push($$[$0]); - break; - case 48: - this.$ = [$$[$0]]; - break; - case 49: - $$[$0 - 1].push($$[$0]); - break; - case 50: - this.$ = []; - break; - case 51: - $$[$0 - 1].push($$[$0]); - break; - case 58: - this.$ = []; - break; - case 59: - $$[$0 - 1].push($$[$0]); - break; - case 64: - this.$ = []; - break; - case 65: - $$[$0 - 1].push($$[$0]); - break; - case 70: - this.$ = []; - break; - case 71: - $$[$0 - 1].push($$[$0]); - break; - case 78: - this.$ = []; - break; - case 79: - $$[$0 - 1].push($$[$0]); - break; - case 82: - this.$ = []; - break; - case 83: - $$[$0 - 1].push($$[$0]); - break; - case 86: - this.$ = []; - break; - case 87: - $$[$0 - 1].push($$[$0]); - break; - case 90: - this.$ = []; - break; - case 91: - $$[$0 - 1].push($$[$0]); - break; - case 94: - this.$ = []; - break; - case 95: - $$[$0 - 1].push($$[$0]); - break; - case 98: - this.$ = [$$[$0]]; - break; - case 99: - $$[$0 - 1].push($$[$0]); - break; - case 100: - this.$ = [$$[$0]]; - break; - case 101: - $$[$0 - 1].push($$[$0]); - break; - } - }, - table: [{ 3: 1, 4: 2, 5: [2, 46], 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 1: [3] }, { 5: [1, 4] }, { 5: [2, 2], 7: 5, 8: 6, 9: 7, 10: 8, 11: 9, 12: 10, 13: 11, 14: [1, 12], 15: [1, 20], 16: 17, 19: [1, 23], 24: 15, 27: 16, 29: [1, 21], 34: [1, 22], 39: [2, 2], 44: [2, 2], 47: [2, 2], 48: [1, 13], 51: [1, 14], 55: [1, 18], 59: 19, 60: [1, 24] }, { 1: [2, 1] }, { 5: [2, 47], 14: [2, 47], 15: [2, 47], 19: [2, 47], 29: [2, 47], 34: [2, 47], 39: [2, 47], 44: [2, 47], 47: [2, 47], 48: [2, 47], 51: [2, 47], 55: [2, 47], 60: [2, 47] }, { 5: [2, 3], 14: [2, 3], 15: [2, 3], 19: [2, 3], 29: [2, 3], 34: [2, 3], 39: [2, 3], 44: [2, 3], 47: [2, 3], 48: [2, 3], 51: [2, 3], 55: [2, 3], 60: [2, 3] }, { 5: [2, 4], 14: [2, 4], 15: [2, 4], 19: [2, 4], 29: [2, 4], 34: [2, 4], 39: [2, 4], 44: [2, 4], 47: [2, 4], 48: [2, 4], 51: [2, 4], 55: [2, 4], 60: [2, 4] }, { 5: [2, 5], 14: [2, 5], 15: [2, 5], 19: [2, 5], 29: [2, 5], 34: [2, 5], 39: [2, 5], 44: [2, 5], 47: [2, 5], 48: [2, 5], 51: [2, 5], 55: [2, 5], 60: [2, 5] }, { 5: [2, 6], 14: [2, 6], 15: [2, 6], 19: [2, 6], 29: [2, 6], 34: [2, 6], 39: [2, 6], 44: [2, 6], 47: [2, 6], 48: [2, 6], 51: [2, 6], 55: [2, 6], 60: [2, 6] }, { 5: [2, 7], 14: [2, 7], 15: [2, 7], 19: [2, 7], 29: [2, 7], 34: [2, 7], 39: [2, 7], 44: [2, 7], 47: [2, 7], 48: [2, 7], 51: [2, 7], 55: [2, 7], 60: [2, 7] }, { 5: [2, 8], 14: [2, 8], 15: [2, 8], 19: [2, 8], 29: [2, 8], 34: [2, 8], 39: [2, 8], 44: [2, 8], 47: [2, 8], 48: [2, 8], 51: [2, 8], 55: [2, 8], 60: [2, 8] }, { 5: [2, 9], 14: [2, 9], 15: [2, 9], 19: [2, 9], 29: [2, 9], 34: [2, 9], 39: [2, 9], 44: [2, 9], 47: [2, 9], 48: [2, 9], 51: [2, 9], 55: [2, 9], 60: [2, 9] }, { 20: 25, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 36, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 37, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 4: 38, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 13: 40, 15: [1, 20], 17: 39 }, { 20: 42, 56: 41, 64: 43, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 45, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 5: [2, 10], 14: [2, 10], 15: [2, 10], 18: [2, 10], 19: [2, 10], 29: [2, 10], 34: [2, 10], 39: [2, 10], 44: [2, 10], 47: [2, 10], 48: [2, 10], 51: [2, 10], 55: [2, 10], 60: [2, 10] }, { 20: 46, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 47, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 48, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 42, 56: 49, 64: 43, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [2, 78], 49: 50, 65: [2, 78], 72: [2, 78], 80: [2, 78], 81: [2, 78], 82: [2, 78], 83: [2, 78], 84: [2, 78], 85: [2, 78] }, { 23: [2, 33], 33: [2, 33], 54: [2, 33], 65: [2, 33], 68: [2, 33], 72: [2, 33], 75: [2, 33], 80: [2, 33], 81: [2, 33], 82: [2, 33], 83: [2, 33], 84: [2, 33], 85: [2, 33] }, { 23: [2, 34], 33: [2, 34], 54: [2, 34], 65: [2, 34], 68: [2, 34], 72: [2, 34], 75: [2, 34], 80: [2, 34], 81: [2, 34], 82: [2, 34], 83: [2, 34], 84: [2, 34], 85: [2, 34] }, { 23: [2, 35], 33: [2, 35], 54: [2, 35], 65: [2, 35], 68: [2, 35], 72: [2, 35], 75: [2, 35], 80: [2, 35], 81: [2, 35], 82: [2, 35], 83: [2, 35], 84: [2, 35], 85: [2, 35] }, { 23: [2, 36], 33: [2, 36], 54: [2, 36], 65: [2, 36], 68: [2, 36], 72: [2, 36], 75: [2, 36], 80: [2, 36], 81: [2, 36], 82: [2, 36], 83: [2, 36], 84: [2, 36], 85: [2, 36] }, { 23: [2, 37], 33: [2, 37], 54: [2, 37], 65: [2, 37], 68: [2, 37], 72: [2, 37], 75: [2, 37], 80: [2, 37], 81: [2, 37], 82: [2, 37], 83: [2, 37], 84: [2, 37], 85: [2, 37] }, { 23: [2, 38], 33: [2, 38], 54: [2, 38], 65: [2, 38], 68: [2, 38], 72: [2, 38], 75: [2, 38], 80: [2, 38], 81: [2, 38], 82: [2, 38], 83: [2, 38], 84: [2, 38], 85: [2, 38] }, { 23: [2, 39], 33: [2, 39], 54: [2, 39], 65: [2, 39], 68: [2, 39], 72: [2, 39], 75: [2, 39], 80: [2, 39], 81: [2, 39], 82: [2, 39], 83: [2, 39], 84: [2, 39], 85: [2, 39] }, { 23: [2, 43], 33: [2, 43], 54: [2, 43], 65: [2, 43], 68: [2, 43], 72: [2, 43], 75: [2, 43], 80: [2, 43], 81: [2, 43], 82: [2, 43], 83: [2, 43], 84: [2, 43], 85: [2, 43], 87: [1, 51] }, { 72: [1, 35], 86: 52 }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 52: 53, 54: [2, 82], 65: [2, 82], 72: [2, 82], 80: [2, 82], 81: [2, 82], 82: [2, 82], 83: [2, 82], 84: [2, 82], 85: [2, 82] }, { 25: 54, 38: 56, 39: [1, 58], 43: 57, 44: [1, 59], 45: 55, 47: [2, 54] }, { 28: 60, 43: 61, 44: [1, 59], 47: [2, 56] }, { 13: 63, 15: [1, 20], 18: [1, 62] }, { 15: [2, 48], 18: [2, 48] }, { 33: [2, 86], 57: 64, 65: [2, 86], 72: [2, 86], 80: [2, 86], 81: [2, 86], 82: [2, 86], 83: [2, 86], 84: [2, 86], 85: [2, 86] }, { 33: [2, 40], 65: [2, 40], 72: [2, 40], 80: [2, 40], 81: [2, 40], 82: [2, 40], 83: [2, 40], 84: [2, 40], 85: [2, 40] }, { 33: [2, 41], 65: [2, 41], 72: [2, 41], 80: [2, 41], 81: [2, 41], 82: [2, 41], 83: [2, 41], 84: [2, 41], 85: [2, 41] }, { 20: 65, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 66, 47: [1, 67] }, { 30: 68, 33: [2, 58], 65: [2, 58], 72: [2, 58], 75: [2, 58], 80: [2, 58], 81: [2, 58], 82: [2, 58], 83: [2, 58], 84: [2, 58], 85: [2, 58] }, { 33: [2, 64], 35: 69, 65: [2, 64], 72: [2, 64], 75: [2, 64], 80: [2, 64], 81: [2, 64], 82: [2, 64], 83: [2, 64], 84: [2, 64], 85: [2, 64] }, { 21: 70, 23: [2, 50], 65: [2, 50], 72: [2, 50], 80: [2, 50], 81: [2, 50], 82: [2, 50], 83: [2, 50], 84: [2, 50], 85: [2, 50] }, { 33: [2, 90], 61: 71, 65: [2, 90], 72: [2, 90], 80: [2, 90], 81: [2, 90], 82: [2, 90], 83: [2, 90], 84: [2, 90], 85: [2, 90] }, { 20: 75, 33: [2, 80], 50: 72, 63: 73, 64: 76, 65: [1, 44], 69: 74, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 72: [1, 80] }, { 23: [2, 42], 33: [2, 42], 54: [2, 42], 65: [2, 42], 68: [2, 42], 72: [2, 42], 75: [2, 42], 80: [2, 42], 81: [2, 42], 82: [2, 42], 83: [2, 42], 84: [2, 42], 85: [2, 42], 87: [1, 51] }, { 20: 75, 53: 81, 54: [2, 84], 63: 82, 64: 76, 65: [1, 44], 69: 83, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 26: 84, 47: [1, 67] }, { 47: [2, 55] }, { 4: 85, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 39: [2, 46], 44: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 47: [2, 20] }, { 20: 86, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 4: 87, 6: 3, 14: [2, 46], 15: [2, 46], 19: [2, 46], 29: [2, 46], 34: [2, 46], 47: [2, 46], 48: [2, 46], 51: [2, 46], 55: [2, 46], 60: [2, 46] }, { 26: 88, 47: [1, 67] }, { 47: [2, 57] }, { 5: [2, 11], 14: [2, 11], 15: [2, 11], 19: [2, 11], 29: [2, 11], 34: [2, 11], 39: [2, 11], 44: [2, 11], 47: [2, 11], 48: [2, 11], 51: [2, 11], 55: [2, 11], 60: [2, 11] }, { 15: [2, 49], 18: [2, 49] }, { 20: 75, 33: [2, 88], 58: 89, 63: 90, 64: 76, 65: [1, 44], 69: 91, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 65: [2, 94], 66: 92, 68: [2, 94], 72: [2, 94], 80: [2, 94], 81: [2, 94], 82: [2, 94], 83: [2, 94], 84: [2, 94], 85: [2, 94] }, { 5: [2, 25], 14: [2, 25], 15: [2, 25], 19: [2, 25], 29: [2, 25], 34: [2, 25], 39: [2, 25], 44: [2, 25], 47: [2, 25], 48: [2, 25], 51: [2, 25], 55: [2, 25], 60: [2, 25] }, { 20: 93, 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 31: 94, 33: [2, 60], 63: 95, 64: 76, 65: [1, 44], 69: 96, 70: 77, 71: 78, 72: [1, 79], 75: [2, 60], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 33: [2, 66], 36: 97, 63: 98, 64: 76, 65: [1, 44], 69: 99, 70: 77, 71: 78, 72: [1, 79], 75: [2, 66], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 22: 100, 23: [2, 52], 63: 101, 64: 76, 65: [1, 44], 69: 102, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 20: 75, 33: [2, 92], 62: 103, 63: 104, 64: 76, 65: [1, 44], 69: 105, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 106] }, { 33: [2, 79], 65: [2, 79], 72: [2, 79], 80: [2, 79], 81: [2, 79], 82: [2, 79], 83: [2, 79], 84: [2, 79], 85: [2, 79] }, { 33: [2, 81] }, { 23: [2, 27], 33: [2, 27], 54: [2, 27], 65: [2, 27], 68: [2, 27], 72: [2, 27], 75: [2, 27], 80: [2, 27], 81: [2, 27], 82: [2, 27], 83: [2, 27], 84: [2, 27], 85: [2, 27] }, { 23: [2, 28], 33: [2, 28], 54: [2, 28], 65: [2, 28], 68: [2, 28], 72: [2, 28], 75: [2, 28], 80: [2, 28], 81: [2, 28], 82: [2, 28], 83: [2, 28], 84: [2, 28], 85: [2, 28] }, { 23: [2, 30], 33: [2, 30], 54: [2, 30], 68: [2, 30], 71: 107, 72: [1, 108], 75: [2, 30] }, { 23: [2, 98], 33: [2, 98], 54: [2, 98], 68: [2, 98], 72: [2, 98], 75: [2, 98] }, { 23: [2, 45], 33: [2, 45], 54: [2, 45], 65: [2, 45], 68: [2, 45], 72: [2, 45], 73: [1, 109], 75: [2, 45], 80: [2, 45], 81: [2, 45], 82: [2, 45], 83: [2, 45], 84: [2, 45], 85: [2, 45], 87: [2, 45] }, { 23: [2, 44], 33: [2, 44], 54: [2, 44], 65: [2, 44], 68: [2, 44], 72: [2, 44], 75: [2, 44], 80: [2, 44], 81: [2, 44], 82: [2, 44], 83: [2, 44], 84: [2, 44], 85: [2, 44], 87: [2, 44] }, { 54: [1, 110] }, { 54: [2, 83], 65: [2, 83], 72: [2, 83], 80: [2, 83], 81: [2, 83], 82: [2, 83], 83: [2, 83], 84: [2, 83], 85: [2, 83] }, { 54: [2, 85] }, { 5: [2, 13], 14: [2, 13], 15: [2, 13], 19: [2, 13], 29: [2, 13], 34: [2, 13], 39: [2, 13], 44: [2, 13], 47: [2, 13], 48: [2, 13], 51: [2, 13], 55: [2, 13], 60: [2, 13] }, { 38: 56, 39: [1, 58], 43: 57, 44: [1, 59], 45: 112, 46: 111, 47: [2, 76] }, { 33: [2, 70], 40: 113, 65: [2, 70], 72: [2, 70], 75: [2, 70], 80: [2, 70], 81: [2, 70], 82: [2, 70], 83: [2, 70], 84: [2, 70], 85: [2, 70] }, { 47: [2, 18] }, { 5: [2, 14], 14: [2, 14], 15: [2, 14], 19: [2, 14], 29: [2, 14], 34: [2, 14], 39: [2, 14], 44: [2, 14], 47: [2, 14], 48: [2, 14], 51: [2, 14], 55: [2, 14], 60: [2, 14] }, { 33: [1, 114] }, { 33: [2, 87], 65: [2, 87], 72: [2, 87], 80: [2, 87], 81: [2, 87], 82: [2, 87], 83: [2, 87], 84: [2, 87], 85: [2, 87] }, { 33: [2, 89] }, { 20: 75, 63: 116, 64: 76, 65: [1, 44], 67: 115, 68: [2, 96], 69: 117, 70: 77, 71: 78, 72: [1, 79], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 33: [1, 118] }, { 32: 119, 33: [2, 62], 74: 120, 75: [1, 121] }, { 33: [2, 59], 65: [2, 59], 72: [2, 59], 75: [2, 59], 80: [2, 59], 81: [2, 59], 82: [2, 59], 83: [2, 59], 84: [2, 59], 85: [2, 59] }, { 33: [2, 61], 75: [2, 61] }, { 33: [2, 68], 37: 122, 74: 123, 75: [1, 121] }, { 33: [2, 65], 65: [2, 65], 72: [2, 65], 75: [2, 65], 80: [2, 65], 81: [2, 65], 82: [2, 65], 83: [2, 65], 84: [2, 65], 85: [2, 65] }, { 33: [2, 67], 75: [2, 67] }, { 23: [1, 124] }, { 23: [2, 51], 65: [2, 51], 72: [2, 51], 80: [2, 51], 81: [2, 51], 82: [2, 51], 83: [2, 51], 84: [2, 51], 85: [2, 51] }, { 23: [2, 53] }, { 33: [1, 125] }, { 33: [2, 91], 65: [2, 91], 72: [2, 91], 80: [2, 91], 81: [2, 91], 82: [2, 91], 83: [2, 91], 84: [2, 91], 85: [2, 91] }, { 33: [2, 93] }, { 5: [2, 22], 14: [2, 22], 15: [2, 22], 19: [2, 22], 29: [2, 22], 34: [2, 22], 39: [2, 22], 44: [2, 22], 47: [2, 22], 48: [2, 22], 51: [2, 22], 55: [2, 22], 60: [2, 22] }, { 23: [2, 99], 33: [2, 99], 54: [2, 99], 68: [2, 99], 72: [2, 99], 75: [2, 99] }, { 73: [1, 109] }, { 20: 75, 63: 126, 64: 76, 65: [1, 44], 72: [1, 35], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 23], 14: [2, 23], 15: [2, 23], 19: [2, 23], 29: [2, 23], 34: [2, 23], 39: [2, 23], 44: [2, 23], 47: [2, 23], 48: [2, 23], 51: [2, 23], 55: [2, 23], 60: [2, 23] }, { 47: [2, 19] }, { 47: [2, 77] }, { 20: 75, 33: [2, 72], 41: 127, 63: 128, 64: 76, 65: [1, 44], 69: 129, 70: 77, 71: 78, 72: [1, 79], 75: [2, 72], 78: 26, 79: 27, 80: [1, 28], 81: [1, 29], 82: [1, 30], 83: [1, 31], 84: [1, 32], 85: [1, 34], 86: 33 }, { 5: [2, 24], 14: [2, 24], 15: [2, 24], 19: [2, 24], 29: [2, 24], 34: [2, 24], 39: [2, 24], 44: [2, 24], 47: [2, 24], 48: [2, 24], 51: [2, 24], 55: [2, 24], 60: [2, 24] }, { 68: [1, 130] }, { 65: [2, 95], 68: [2, 95], 72: [2, 95], 80: [2, 95], 81: [2, 95], 82: [2, 95], 83: [2, 95], 84: [2, 95], 85: [2, 95] }, { 68: [2, 97] }, { 5: [2, 21], 14: [2, 21], 15: [2, 21], 19: [2, 21], 29: [2, 21], 34: [2, 21], 39: [2, 21], 44: [2, 21], 47: [2, 21], 48: [2, 21], 51: [2, 21], 55: [2, 21], 60: [2, 21] }, { 33: [1, 131] }, { 33: [2, 63] }, { 72: [1, 133], 76: 132 }, { 33: [1, 134] }, { 33: [2, 69] }, { 15: [2, 12] }, { 14: [2, 26], 15: [2, 26], 19: [2, 26], 29: [2, 26], 34: [2, 26], 47: [2, 26], 48: [2, 26], 51: [2, 26], 55: [2, 26], 60: [2, 26] }, { 23: [2, 31], 33: [2, 31], 54: [2, 31], 68: [2, 31], 72: [2, 31], 75: [2, 31] }, { 33: [2, 74], 42: 135, 74: 136, 75: [1, 121] }, { 33: [2, 71], 65: [2, 71], 72: [2, 71], 75: [2, 71], 80: [2, 71], 81: [2, 71], 82: [2, 71], 83: [2, 71], 84: [2, 71], 85: [2, 71] }, { 33: [2, 73], 75: [2, 73] }, { 23: [2, 29], 33: [2, 29], 54: [2, 29], 65: [2, 29], 68: [2, 29], 72: [2, 29], 75: [2, 29], 80: [2, 29], 81: [2, 29], 82: [2, 29], 83: [2, 29], 84: [2, 29], 85: [2, 29] }, { 14: [2, 15], 15: [2, 15], 19: [2, 15], 29: [2, 15], 34: [2, 15], 39: [2, 15], 44: [2, 15], 47: [2, 15], 48: [2, 15], 51: [2, 15], 55: [2, 15], 60: [2, 15] }, { 72: [1, 138], 77: [1, 137] }, { 72: [2, 100], 77: [2, 100] }, { 14: [2, 16], 15: [2, 16], 19: [2, 16], 29: [2, 16], 34: [2, 16], 44: [2, 16], 47: [2, 16], 48: [2, 16], 51: [2, 16], 55: [2, 16], 60: [2, 16] }, { 33: [1, 139] }, { 33: [2, 75] }, { 33: [2, 32] }, { 72: [2, 101], 77: [2, 101] }, { 14: [2, 17], 15: [2, 17], 19: [2, 17], 29: [2, 17], 34: [2, 17], 39: [2, 17], 44: [2, 17], 47: [2, 17], 48: [2, 17], 51: [2, 17], 55: [2, 17], 60: [2, 17] }], - defaultActions: { 4: [2, 1], 55: [2, 55], 57: [2, 20], 61: [2, 57], 74: [2, 81], 83: [2, 85], 87: [2, 18], 91: [2, 89], 102: [2, 53], 105: [2, 93], 111: [2, 19], 112: [2, 77], 117: [2, 97], 120: [2, 63], 123: [2, 69], 124: [2, 12], 136: [2, 75], 137: [2, 32] }, - parseError: function parseError(str, hash) { - throw new Error(str); - }, - parse: function parse(input) { - var self = this, - stack = [0], - vstack = [null], - lstack = [], - table = this.table, - yytext = "", - yylineno = 0, - yyleng = 0, - recovering = 0, - TERROR = 2, - EOF = 1; - this.lexer.setInput(input); - this.lexer.yy = this.yy; - this.yy.lexer = this.lexer; - this.yy.parser = this; - if (typeof this.lexer.yylloc == "undefined") this.lexer.yylloc = {}; - var yyloc = this.lexer.yylloc; - lstack.push(yyloc); - var ranges = this.lexer.options && this.lexer.options.ranges; - if (typeof this.yy.parseError === "function") this.parseError = this.yy.parseError; - function popStack(n) { - stack.length = stack.length - 2 * n; - vstack.length = vstack.length - n; - lstack.length = lstack.length - n; - } - function lex() { - var token; - token = self.lexer.lex() || 1; - if (typeof token !== "number") { - token = self.symbols_[token] || token; - } - return token; - } - var symbol, - preErrorSymbol, - state, - action, - a, - r, - yyval = {}, - p, - len, - newState, - expected; - while (true) { - state = stack[stack.length - 1]; - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol === null || typeof symbol == "undefined") { - symbol = lex(); - } - action = table[state] && table[state][symbol]; - } - if (typeof action === "undefined" || !action.length || !action[0]) { - var errStr = ""; - if (!recovering) { - expected = []; - for (p in table[state]) if (this.terminals_[p] && p > 2) { - expected.push("'" + this.terminals_[p] + "'"); - } - if (this.lexer.showPosition) { - errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; - } else { - errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1 ? "end of input" : "'" + (this.terminals_[symbol] || symbol) + "'"); - } - this.parseError(errStr, { text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected }); - } - } - if (action[0] instanceof Array && action.length > 1) { - throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); - } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(this.lexer.yytext); - lstack.push(this.lexer.yylloc); - stack.push(action[1]); - symbol = null; - if (!preErrorSymbol) { - yyleng = this.lexer.yyleng; - yytext = this.lexer.yytext; - yylineno = this.lexer.yylineno; - yyloc = this.lexer.yylloc; - if (recovering > 0) recovering--; - } else { - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = { first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column }; - if (ranges) { - yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; - } - r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); - if (typeof r !== "undefined") { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; - } - } - return true; - } - }; - /* Jison generated lexer */ - var lexer = (function () { - var lexer = { EOF: 1, - parseError: function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, - setInput: function setInput(input) { - this._input = input; - this._more = this._less = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = { first_line: 1, first_column: 0, last_line: 1, last_column: 0 }; - if (this.options.ranges) this.yylloc.range = [0, 0]; - this.offset = 0; - return this; - }, - input: function input() { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; - } else { - this.yylloc.last_column++; - } - if (this.options.ranges) this.yylloc.range[1]++; - - this._input = this._input.slice(1); - return ch; - }, - unput: function unput(ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); - - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length - len - 1); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length - 1); - this.matched = this.matched.substr(0, this.matched.length - 1); - - if (lines.length - 1) this.yylineno -= lines.length - 1; - var r = this.yylloc.range; - - this.yylloc = { first_line: this.yylloc.first_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.first_column, - last_column: lines ? (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length : this.yylloc.first_column - len - }; - - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - return this; - }, - more: function more() { - this._more = true; - return this; - }, - less: function less(n) { - this.unput(this.match.slice(n)); - }, - pastInput: function pastInput() { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...' : '') + past.substr(-20).replace(/\n/g, ""); - }, - upcomingInput: function upcomingInput() { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20 - next.length); - } - return (next.substr(0, 20) + (next.length > 20 ? '...' : '')).replace(/\n/g, ""); - }, - showPosition: function showPosition() { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c + "^"; - }, - next: function next() { - if (this.done) { - return this.EOF; - } - if (!this._input) this.done = true; - - var token, match, tempMatch, index, col, lines; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i = 0; i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (!this.options.flex) break; - } - } - if (match) { - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) this.yylineno += lines.length; - this.yylloc = { first_line: this.yylloc.last_line, - last_line: this.yylineno + 1, - first_column: this.yylloc.last_column, - last_column: lines ? lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length }; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, rules[index], this.conditionStack[this.conditionStack.length - 1]); - if (this.done && this._input) this.done = false; - if (token) return token;else return; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), { text: "", token: null, line: this.yylineno }); - } - }, - lex: function lex() { - var r = this.next(); - if (typeof r !== 'undefined') { - return r; - } else { - return this.lex(); - } - }, - begin: function begin(condition) { - this.conditionStack.push(condition); - }, - popState: function popState() { - return this.conditionStack.pop(); - }, - _currentRules: function _currentRules() { - return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules; - }, - topState: function topState() { - return this.conditionStack[this.conditionStack.length - 2]; - }, - pushState: function begin(condition) { - this.begin(condition); - } }; - lexer.options = {}; - lexer.performAction = function anonymous(yy, yy_, $avoiding_name_collisions, YY_START - /**/) { - - function strip(start, end) { - return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng - end); - } - - var YYSTATE = YY_START; - switch ($avoiding_name_collisions) { - case 0: - if (yy_.yytext.slice(-2) === "\\\\") { - strip(0, 1); - this.begin("mu"); - } else if (yy_.yytext.slice(-1) === "\\") { - strip(0, 1); - this.begin("emu"); - } else { - this.begin("mu"); - } - if (yy_.yytext) return 15; - - break; - case 1: - return 15; - break; - case 2: - this.popState(); - return 15; - - break; - case 3: - this.begin('raw');return 15; - break; - case 4: - this.popState(); - // Should be using `this.topState()` below, but it currently - // returns the second top instead of the first top. Opened an - // issue about it at https://github.com/zaach/jison/issues/291 - if (this.conditionStack[this.conditionStack.length - 1] === 'raw') { - return 15; - } else { - yy_.yytext = yy_.yytext.substr(5, yy_.yyleng - 9); - return 'END_RAW_BLOCK'; - } - - break; - case 5: - return 15; - break; - case 6: - this.popState(); - return 14; - - break; - case 7: - return 65; - break; - case 8: - return 68; - break; - case 9: - return 19; - break; - case 10: - this.popState(); - this.begin('raw'); - return 23; - - break; - case 11: - return 55; - break; - case 12: - return 60; - break; - case 13: - return 29; - break; - case 14: - return 47; - break; - case 15: - this.popState();return 44; - break; - case 16: - this.popState();return 44; - break; - case 17: - return 34; - break; - case 18: - return 39; - break; - case 19: - return 51; - break; - case 20: - return 48; - break; - case 21: - this.unput(yy_.yytext); - this.popState(); - this.begin('com'); - - break; - case 22: - this.popState(); - return 14; - - break; - case 23: - return 48; - break; - case 24: - return 73; - break; - case 25: - return 72; - break; - case 26: - return 72; - break; - case 27: - return 87; - break; - case 28: - // ignore whitespace - break; - case 29: - this.popState();return 54; - break; - case 30: - this.popState();return 33; - break; - case 31: - yy_.yytext = strip(1, 2).replace(/\\"/g, '"');return 80; - break; - case 32: - yy_.yytext = strip(1, 2).replace(/\\'/g, "'");return 80; - break; - case 33: - return 85; - break; - case 34: - return 82; - break; - case 35: - return 82; - break; - case 36: - return 83; - break; - case 37: - return 84; - break; - case 38: - return 81; - break; - case 39: - return 75; - break; - case 40: - return 77; - break; - case 41: - return 72; - break; - case 42: - yy_.yytext = yy_.yytext.replace(/\\([\\\]])/g, '$1');return 72; - break; - case 43: - return 'INVALID'; - break; - case 44: - return 5; - break; - } - }; - lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/, /^(?:\{\{\{\{(?=[^\/]))/, /^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/, /^(?:[^\x00]*?(?=(\{\{\{\{)))/, /^(?:[\s\S]*?--(~)?\}\})/, /^(?:\()/, /^(?:\))/, /^(?:\{\{\{\{)/, /^(?:\}\}\}\})/, /^(?:\{\{(~)?>)/, /^(?:\{\{(~)?#>)/, /^(?:\{\{(~)?#\*?)/, /^(?:\{\{(~)?\/)/, /^(?:\{\{(~)?\^\s*(~)?\}\})/, /^(?:\{\{(~)?\s*else\s*(~)?\}\})/, /^(?:\{\{(~)?\^)/, /^(?:\{\{(~)?\s*else\b)/, /^(?:\{\{(~)?\{)/, /^(?:\{\{(~)?&)/, /^(?:\{\{(~)?!--)/, /^(?:\{\{(~)?![\s\S]*?\}\})/, /^(?:\{\{(~)?\*?)/, /^(?:=)/, /^(?:\.\.)/, /^(?:\.(?=([=~}\s\/.)|])))/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:\}(~)?\}\})/, /^(?:(~)?\}\})/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@)/, /^(?:true(?=([~}\s)])))/, /^(?:false(?=([~}\s)])))/, /^(?:undefined(?=([~}\s)])))/, /^(?:null(?=([~}\s)])))/, /^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/, /^(?:as\s+\|)/, /^(?:\|)/, /^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)|]))))/, /^(?:\[(\\\]|[^\]])*\])/, /^(?:.)/, /^(?:$)/]; - lexer.conditions = { "mu": { "rules": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "inclusive": false }, "emu": { "rules": [2], "inclusive": false }, "com": { "rules": [6], "inclusive": false }, "raw": { "rules": [3, 4, 5], "inclusive": false }, "INITIAL": { "rules": [0, 1, 44], "inclusive": true } }; - return lexer; - })(); - parser.lexer = lexer; - function Parser() { - this.yy = {}; - }Parser.prototype = parser;parser.Parser = Parser; - return new Parser(); - })();exports["default"] = handlebars; - module.exports = exports["default"]; - -/***/ }), -/* 38 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _visitor = __webpack_require__(39); - - var _visitor2 = _interopRequireDefault(_visitor); - - function WhitespaceControl() { - var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; - - this.options = options; - } - WhitespaceControl.prototype = new _visitor2['default'](); - - WhitespaceControl.prototype.Program = function (program) { - var doStandalone = !this.options.ignoreStandalone; - - var isRoot = !this.isRootSeen; - this.isRootSeen = true; - - var body = program.body; - for (var i = 0, l = body.length; i < l; i++) { - var current = body[i], - strip = this.accept(current); - - if (!strip) { - continue; - } - - var _isPrevWhitespace = isPrevWhitespace(body, i, isRoot), - _isNextWhitespace = isNextWhitespace(body, i, isRoot), - openStandalone = strip.openStandalone && _isPrevWhitespace, - closeStandalone = strip.closeStandalone && _isNextWhitespace, - inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace; - - if (strip.close) { - omitRight(body, i, true); - } - if (strip.open) { - omitLeft(body, i, true); - } - - if (doStandalone && inlineStandalone) { - omitRight(body, i); - - if (omitLeft(body, i)) { - // If we are on a standalone node, save the indent info for partials - if (current.type === 'PartialStatement') { - // Pull out the whitespace from the final line - current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1]; - } - } - } - if (doStandalone && openStandalone) { - omitRight((current.program || current.inverse).body); - - // Strip out the previous content node if it's whitespace only - omitLeft(body, i); - } - if (doStandalone && closeStandalone) { - // Always strip the next node - omitRight(body, i); - - omitLeft((current.inverse || current.program).body); - } - } - - return program; - }; - - WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.DecoratorBlock = WhitespaceControl.prototype.PartialBlockStatement = function (block) { - this.accept(block.program); - this.accept(block.inverse); - - // Find the inverse program that is involed with whitespace stripping. - var program = block.program || block.inverse, - inverse = block.program && block.inverse, - firstInverse = inverse, - lastInverse = inverse; - - if (inverse && inverse.chained) { - firstInverse = inverse.body[0].program; - - // Walk the inverse chain to find the last inverse that is actually in the chain. - while (lastInverse.chained) { - lastInverse = lastInverse.body[lastInverse.body.length - 1].program; - } - } - - var strip = { - open: block.openStrip.open, - close: block.closeStrip.close, - - // Determine the standalone candiacy. Basically flag our content as being possibly standalone - // so our parent can determine if we actually are standalone - openStandalone: isNextWhitespace(program.body), - closeStandalone: isPrevWhitespace((firstInverse || program).body) - }; - - if (block.openStrip.close) { - omitRight(program.body, null, true); - } - - if (inverse) { - var inverseStrip = block.inverseStrip; - - if (inverseStrip.open) { - omitLeft(program.body, null, true); - } - - if (inverseStrip.close) { - omitRight(firstInverse.body, null, true); - } - if (block.closeStrip.open) { - omitLeft(lastInverse.body, null, true); - } - - // Find standalone else statments - if (!this.options.ignoreStandalone && isPrevWhitespace(program.body) && isNextWhitespace(firstInverse.body)) { - omitLeft(program.body); - omitRight(firstInverse.body); - } - } else if (block.closeStrip.open) { - omitLeft(program.body, null, true); - } - - return strip; - }; - - WhitespaceControl.prototype.Decorator = WhitespaceControl.prototype.MustacheStatement = function (mustache) { - return mustache.strip; - }; - - WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function (node) { - /* istanbul ignore next */ - var strip = node.strip || {}; - return { - inlineStandalone: true, - open: strip.open, - close: strip.close - }; - }; - - function isPrevWhitespace(body, i, isRoot) { - if (i === undefined) { - i = body.length; - } - - // Nodes that end with newlines are considered whitespace (but are special - // cased for strip operations) - var prev = body[i - 1], - sibling = body[i - 2]; - if (!prev) { - return isRoot; - } - - if (prev.type === 'ContentStatement') { - return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(prev.original); - } - } - function isNextWhitespace(body, i, isRoot) { - if (i === undefined) { - i = -1; - } - - var next = body[i + 1], - sibling = body[i + 2]; - if (!next) { - return isRoot; - } - - if (next.type === 'ContentStatement') { - return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(next.original); - } - } - - // Marks the node to the right of the position as omitted. - // I.e. {{foo}}' ' will mark the ' ' node as omitted. - // - // If i is undefined, then the first child will be marked as such. - // - // If mulitple is truthy then all whitespace will be stripped out until non-whitespace - // content is met. - function omitRight(body, i, multiple) { - var current = body[i == null ? 0 : i + 1]; - if (!current || current.type !== 'ContentStatement' || !multiple && current.rightStripped) { - return; - } - - var original = current.value; - current.value = current.value.replace(multiple ? /^\s+/ : /^[ \t]*\r?\n?/, ''); - current.rightStripped = current.value !== original; - } - - // Marks the node to the left of the position as omitted. - // I.e. ' '{{foo}} will mark the ' ' node as omitted. - // - // If i is undefined then the last child will be marked as such. - // - // If mulitple is truthy then all whitespace will be stripped out until non-whitespace - // content is met. - function omitLeft(body, i, multiple) { - var current = body[i == null ? body.length - 1 : i - 1]; - if (!current || current.type !== 'ContentStatement' || !multiple && current.leftStripped) { - return; - } - - // We omit the last node if it's whitespace only and not preceeded by a non-content node. - var original = current.value; - current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, ''); - current.leftStripped = current.value !== original; - return current.leftStripped; - } - - exports['default'] = WhitespaceControl; - module.exports = exports['default']; - -/***/ }), -/* 39 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - function Visitor() { - this.parents = []; - } - - Visitor.prototype = { - constructor: Visitor, - mutating: false, - - // Visits a given value. If mutating, will replace the value if necessary. - acceptKey: function acceptKey(node, name) { - var value = this.accept(node[name]); - if (this.mutating) { - // Hacky sanity check: This may have a few false positives for type for the helper - // methods but will generally do the right thing without a lot of overhead. - if (value && !Visitor.prototype[value.type]) { - throw new _exception2['default']('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type); - } - node[name] = value; - } - }, - - // Performs an accept operation with added sanity check to ensure - // required keys are not removed. - acceptRequired: function acceptRequired(node, name) { - this.acceptKey(node, name); - - if (!node[name]) { - throw new _exception2['default'](node.type + ' requires ' + name); - } - }, - - // Traverses a given array. If mutating, empty respnses will be removed - // for child elements. - acceptArray: function acceptArray(array) { - for (var i = 0, l = array.length; i < l; i++) { - this.acceptKey(array, i); - - if (!array[i]) { - array.splice(i, 1); - i--; - l--; - } - } - }, - - accept: function accept(object) { - if (!object) { - return; - } - - /* istanbul ignore next: Sanity code */ - if (!this[object.type]) { - throw new _exception2['default']('Unknown type: ' + object.type, object); - } - - if (this.current) { - this.parents.unshift(this.current); - } - this.current = object; - - var ret = this[object.type](object); - - this.current = this.parents.shift(); - - if (!this.mutating || ret) { - return ret; - } else if (ret !== false) { - return object; - } - }, - - Program: function Program(program) { - this.acceptArray(program.body); - }, - - MustacheStatement: visitSubExpression, - Decorator: visitSubExpression, - - BlockStatement: visitBlock, - DecoratorBlock: visitBlock, - - PartialStatement: visitPartial, - PartialBlockStatement: function PartialBlockStatement(partial) { - visitPartial.call(this, partial); - - this.acceptKey(partial, 'program'); - }, - - ContentStatement: function ContentStatement() /* content */{}, - CommentStatement: function CommentStatement() /* comment */{}, - - SubExpression: visitSubExpression, - - PathExpression: function PathExpression() /* path */{}, - - StringLiteral: function StringLiteral() /* string */{}, - NumberLiteral: function NumberLiteral() /* number */{}, - BooleanLiteral: function BooleanLiteral() /* bool */{}, - UndefinedLiteral: function UndefinedLiteral() /* literal */{}, - NullLiteral: function NullLiteral() /* literal */{}, - - Hash: function Hash(hash) { - this.acceptArray(hash.pairs); - }, - HashPair: function HashPair(pair) { - this.acceptRequired(pair, 'value'); - } - }; - - function visitSubExpression(mustache) { - this.acceptRequired(mustache, 'path'); - this.acceptArray(mustache.params); - this.acceptKey(mustache, 'hash'); - } - function visitBlock(block) { - visitSubExpression.call(this, block); - - this.acceptKey(block, 'program'); - this.acceptKey(block, 'inverse'); - } - function visitPartial(partial) { - this.acceptRequired(partial, 'name'); - this.acceptArray(partial.params); - this.acceptKey(partial, 'hash'); - } - - exports['default'] = Visitor; - module.exports = exports['default']; - -/***/ }), -/* 40 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.SourceLocation = SourceLocation; - exports.id = id; - exports.stripFlags = stripFlags; - exports.stripComment = stripComment; - exports.preparePath = preparePath; - exports.prepareMustache = prepareMustache; - exports.prepareRawBlock = prepareRawBlock; - exports.prepareBlock = prepareBlock; - exports.prepareProgram = prepareProgram; - exports.preparePartialBlock = preparePartialBlock; - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - function validateClose(open, close) { - close = close.path ? close.path.original : close; - - if (open.path.original !== close) { - var errorNode = { loc: open.path.loc }; - - throw new _exception2['default'](open.path.original + " doesn't match " + close, errorNode); - } - } - - function SourceLocation(source, locInfo) { - this.source = source; - this.start = { - line: locInfo.first_line, - column: locInfo.first_column - }; - this.end = { - line: locInfo.last_line, - column: locInfo.last_column - }; - } - - function id(token) { - if (/^\[.*\]$/.test(token)) { - return token.substr(1, token.length - 2); - } else { - return token; - } - } - - function stripFlags(open, close) { - return { - open: open.charAt(2) === '~', - close: close.charAt(close.length - 3) === '~' - }; - } - - function stripComment(comment) { - return comment.replace(/^\{\{~?\!-?-?/, '').replace(/-?-?~?\}\}$/, ''); - } - - function preparePath(data, parts, loc) { - loc = this.locInfo(loc); - - var original = data ? '@' : '', - dig = [], - depth = 0, - depthString = ''; - - for (var i = 0, l = parts.length; i < l; i++) { - var part = parts[i].part, - - // If we have [] syntax then we do not treat path references as operators, - // i.e. foo.[this] resolves to approximately context.foo['this'] - isLiteral = parts[i].original !== part; - original += (parts[i].separator || '') + part; - - if (!isLiteral && (part === '..' || part === '.' || part === 'this')) { - if (dig.length > 0) { - throw new _exception2['default']('Invalid path: ' + original, { loc: loc }); - } else if (part === '..') { - depth++; - depthString += '../'; - } - } else { - dig.push(part); - } - } - - return { - type: 'PathExpression', - data: data, - depth: depth, - parts: dig, - original: original, - loc: loc - }; - } - - function prepareMustache(path, params, hash, open, strip, locInfo) { - // Must use charAt to support IE pre-10 - var escapeFlag = open.charAt(3) || open.charAt(2), - escaped = escapeFlag !== '{' && escapeFlag !== '&'; - - var decorator = /\*/.test(open); - return { - type: decorator ? 'Decorator' : 'MustacheStatement', - path: path, - params: params, - hash: hash, - escaped: escaped, - strip: strip, - loc: this.locInfo(locInfo) - }; - } - - function prepareRawBlock(openRawBlock, contents, close, locInfo) { - validateClose(openRawBlock, close); - - locInfo = this.locInfo(locInfo); - var program = { - type: 'Program', - body: contents, - strip: {}, - loc: locInfo - }; - - return { - type: 'BlockStatement', - path: openRawBlock.path, - params: openRawBlock.params, - hash: openRawBlock.hash, - program: program, - openStrip: {}, - inverseStrip: {}, - closeStrip: {}, - loc: locInfo - }; - } - - function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) { - if (close && close.path) { - validateClose(openBlock, close); - } - - var decorator = /\*/.test(openBlock.open); - - program.blockParams = openBlock.blockParams; - - var inverse = undefined, - inverseStrip = undefined; - - if (inverseAndProgram) { - if (decorator) { - throw new _exception2['default']('Unexpected inverse block on decorator', inverseAndProgram); - } - - if (inverseAndProgram.chain) { - inverseAndProgram.program.body[0].closeStrip = close.strip; - } - - inverseStrip = inverseAndProgram.strip; - inverse = inverseAndProgram.program; - } - - if (inverted) { - inverted = inverse; - inverse = program; - program = inverted; - } - - return { - type: decorator ? 'DecoratorBlock' : 'BlockStatement', - path: openBlock.path, - params: openBlock.params, - hash: openBlock.hash, - program: program, - inverse: inverse, - openStrip: openBlock.strip, - inverseStrip: inverseStrip, - closeStrip: close && close.strip, - loc: this.locInfo(locInfo) - }; - } - - function prepareProgram(statements, loc) { - if (!loc && statements.length) { - var firstLoc = statements[0].loc, - lastLoc = statements[statements.length - 1].loc; - - /* istanbul ignore else */ - if (firstLoc && lastLoc) { - loc = { - source: firstLoc.source, - start: { - line: firstLoc.start.line, - column: firstLoc.start.column - }, - end: { - line: lastLoc.end.line, - column: lastLoc.end.column - } - }; - } - } - - return { - type: 'Program', - body: statements, - strip: {}, - loc: loc - }; - } - - function preparePartialBlock(open, program, close, locInfo) { - validateClose(open, close); - - return { - type: 'PartialBlockStatement', - name: open.path, - params: open.params, - hash: open.hash, - program: program, - openStrip: open.strip, - closeStrip: close && close.strip, - loc: this.locInfo(locInfo) - }; - } - -/***/ }), -/* 41 */ -/***/ (function(module, exports, __webpack_require__) { - - /* eslint-disable new-cap */ - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - exports.Compiler = Compiler; - exports.precompile = precompile; - exports.compile = compile; - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - var _utils = __webpack_require__(5); - - var _ast = __webpack_require__(35); - - var _ast2 = _interopRequireDefault(_ast); - - var slice = [].slice; - - function Compiler() {} - - // the foundHelper register will disambiguate helper lookup from finding a - // function in a context. This is necessary for mustache compatibility, which - // requires that context functions in blocks are evaluated by blockHelperMissing, - // and then proceed as if the resulting value was provided to blockHelperMissing. - - Compiler.prototype = { - compiler: Compiler, - - equals: function equals(other) { - var len = this.opcodes.length; - if (other.opcodes.length !== len) { - return false; - } - - for (var i = 0; i < len; i++) { - var opcode = this.opcodes[i], - otherOpcode = other.opcodes[i]; - if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) { - return false; - } - } - - // We know that length is the same between the two arrays because they are directly tied - // to the opcode behavior above. - len = this.children.length; - for (var i = 0; i < len; i++) { - if (!this.children[i].equals(other.children[i])) { - return false; - } - } - - return true; - }, - - guid: 0, - - compile: function compile(program, options) { - this.sourceNode = []; - this.opcodes = []; - this.children = []; - this.options = options; - this.stringParams = options.stringParams; - this.trackIds = options.trackIds; - - options.blockParams = options.blockParams || []; - - // These changes will propagate to the other compiler components - var knownHelpers = options.knownHelpers; - options.knownHelpers = { - 'helperMissing': true, - 'blockHelperMissing': true, - 'each': true, - 'if': true, - 'unless': true, - 'with': true, - 'log': true, - 'lookup': true - }; - if (knownHelpers) { - for (var _name in knownHelpers) { - /* istanbul ignore else */ - if (_name in knownHelpers) { - this.options.knownHelpers[_name] = knownHelpers[_name]; - } - } - } - - return this.accept(program); - }, - - compileProgram: function compileProgram(program) { - var childCompiler = new this.compiler(), - // eslint-disable-line new-cap - result = childCompiler.compile(program, this.options), - guid = this.guid++; - - this.usePartial = this.usePartial || result.usePartial; - - this.children[guid] = result; - this.useDepths = this.useDepths || result.useDepths; - - return guid; - }, - - accept: function accept(node) { - /* istanbul ignore next: Sanity code */ - if (!this[node.type]) { - throw new _exception2['default']('Unknown type: ' + node.type, node); - } - - this.sourceNode.unshift(node); - var ret = this[node.type](node); - this.sourceNode.shift(); - return ret; - }, - - Program: function Program(program) { - this.options.blockParams.unshift(program.blockParams); - - var body = program.body, - bodyLength = body.length; - for (var i = 0; i < bodyLength; i++) { - this.accept(body[i]); - } - - this.options.blockParams.shift(); - - this.isSimple = bodyLength === 1; - this.blockParams = program.blockParams ? program.blockParams.length : 0; - - return this; - }, - - BlockStatement: function BlockStatement(block) { - transformLiteralToPath(block); - - var program = block.program, - inverse = block.inverse; - - program = program && this.compileProgram(program); - inverse = inverse && this.compileProgram(inverse); - - var type = this.classifySexpr(block); - - if (type === 'helper') { - this.helperSexpr(block, program, inverse); - } else if (type === 'simple') { - this.simpleSexpr(block); - - // now that the simple mustache is resolved, we need to - // evaluate it by executing `blockHelperMissing` - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - this.opcode('emptyHash'); - this.opcode('blockValue', block.path.original); - } else { - this.ambiguousSexpr(block, program, inverse); - - // now that the simple mustache is resolved, we need to - // evaluate it by executing `blockHelperMissing` - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - this.opcode('emptyHash'); - this.opcode('ambiguousBlockValue'); - } - - this.opcode('append'); - }, - - DecoratorBlock: function DecoratorBlock(decorator) { - var program = decorator.program && this.compileProgram(decorator.program); - var params = this.setupFullMustacheParams(decorator, program, undefined), - path = decorator.path; - - this.useDecorators = true; - this.opcode('registerDecorator', params.length, path.original); - }, - - PartialStatement: function PartialStatement(partial) { - this.usePartial = true; - - var program = partial.program; - if (program) { - program = this.compileProgram(partial.program); - } - - var params = partial.params; - if (params.length > 1) { - throw new _exception2['default']('Unsupported number of partial arguments: ' + params.length, partial); - } else if (!params.length) { - if (this.options.explicitPartialContext) { - this.opcode('pushLiteral', 'undefined'); - } else { - params.push({ type: 'PathExpression', parts: [], depth: 0 }); - } - } - - var partialName = partial.name.original, - isDynamic = partial.name.type === 'SubExpression'; - if (isDynamic) { - this.accept(partial.name); - } - - this.setupFullMustacheParams(partial, program, undefined, true); - - var indent = partial.indent || ''; - if (this.options.preventIndent && indent) { - this.opcode('appendContent', indent); - indent = ''; - } - - this.opcode('invokePartial', isDynamic, partialName, indent); - this.opcode('append'); - }, - PartialBlockStatement: function PartialBlockStatement(partialBlock) { - this.PartialStatement(partialBlock); - }, - - MustacheStatement: function MustacheStatement(mustache) { - this.SubExpression(mustache); - - if (mustache.escaped && !this.options.noEscape) { - this.opcode('appendEscaped'); - } else { - this.opcode('append'); - } - }, - Decorator: function Decorator(decorator) { - this.DecoratorBlock(decorator); - }, - - ContentStatement: function ContentStatement(content) { - if (content.value) { - this.opcode('appendContent', content.value); - } - }, - - CommentStatement: function CommentStatement() {}, - - SubExpression: function SubExpression(sexpr) { - transformLiteralToPath(sexpr); - var type = this.classifySexpr(sexpr); - - if (type === 'simple') { - this.simpleSexpr(sexpr); - } else if (type === 'helper') { - this.helperSexpr(sexpr); - } else { - this.ambiguousSexpr(sexpr); - } - }, - ambiguousSexpr: function ambiguousSexpr(sexpr, program, inverse) { - var path = sexpr.path, - name = path.parts[0], - isBlock = program != null || inverse != null; - - this.opcode('getContext', path.depth); - - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - - path.strict = true; - this.accept(path); - - this.opcode('invokeAmbiguous', name, isBlock); - }, - - simpleSexpr: function simpleSexpr(sexpr) { - var path = sexpr.path; - path.strict = true; - this.accept(path); - this.opcode('resolvePossibleLambda'); - }, - - helperSexpr: function helperSexpr(sexpr, program, inverse) { - var params = this.setupFullMustacheParams(sexpr, program, inverse), - path = sexpr.path, - name = path.parts[0]; - - if (this.options.knownHelpers[name]) { - this.opcode('invokeKnownHelper', params.length, name); - } else if (this.options.knownHelpersOnly) { - throw new _exception2['default']('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr); - } else { - path.strict = true; - path.falsy = true; - - this.accept(path); - this.opcode('invokeHelper', params.length, path.original, _ast2['default'].helpers.simpleId(path)); - } - }, - - PathExpression: function PathExpression(path) { - this.addDepth(path.depth); - this.opcode('getContext', path.depth); - - var name = path.parts[0], - scoped = _ast2['default'].helpers.scopedId(path), - blockParamId = !path.depth && !scoped && this.blockParamIndex(name); - - if (blockParamId) { - this.opcode('lookupBlockParam', blockParamId, path.parts); - } else if (!name) { - // Context reference, i.e. `{{foo .}}` or `{{foo ..}}` - this.opcode('pushContext'); - } else if (path.data) { - this.options.data = true; - this.opcode('lookupData', path.depth, path.parts, path.strict); - } else { - this.opcode('lookupOnContext', path.parts, path.falsy, path.strict, scoped); - } - }, - - StringLiteral: function StringLiteral(string) { - this.opcode('pushString', string.value); - }, - - NumberLiteral: function NumberLiteral(number) { - this.opcode('pushLiteral', number.value); - }, - - BooleanLiteral: function BooleanLiteral(bool) { - this.opcode('pushLiteral', bool.value); - }, - - UndefinedLiteral: function UndefinedLiteral() { - this.opcode('pushLiteral', 'undefined'); - }, - - NullLiteral: function NullLiteral() { - this.opcode('pushLiteral', 'null'); - }, - - Hash: function Hash(hash) { - var pairs = hash.pairs, - i = 0, - l = pairs.length; - - this.opcode('pushHash'); - - for (; i < l; i++) { - this.pushParam(pairs[i].value); - } - while (i--) { - this.opcode('assignToHash', pairs[i].key); - } - this.opcode('popHash'); - }, - - // HELPERS - opcode: function opcode(name) { - this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), loc: this.sourceNode[0].loc }); - }, - - addDepth: function addDepth(depth) { - if (!depth) { - return; - } - - this.useDepths = true; - }, - - classifySexpr: function classifySexpr(sexpr) { - var isSimple = _ast2['default'].helpers.simpleId(sexpr.path); - - var isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]); - - // a mustache is an eligible helper if: - // * its id is simple (a single part, not `this` or `..`) - var isHelper = !isBlockParam && _ast2['default'].helpers.helperExpression(sexpr); - - // if a mustache is an eligible helper but not a definite - // helper, it is ambiguous, and will be resolved in a later - // pass or at runtime. - var isEligible = !isBlockParam && (isHelper || isSimple); - - // if ambiguous, we can possibly resolve the ambiguity now - // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc. - if (isEligible && !isHelper) { - var _name2 = sexpr.path.parts[0], - options = this.options; - - if (options.knownHelpers[_name2]) { - isHelper = true; - } else if (options.knownHelpersOnly) { - isEligible = false; - } - } - - if (isHelper) { - return 'helper'; - } else if (isEligible) { - return 'ambiguous'; - } else { - return 'simple'; - } - }, - - pushParams: function pushParams(params) { - for (var i = 0, l = params.length; i < l; i++) { - this.pushParam(params[i]); - } - }, - - pushParam: function pushParam(val) { - var value = val.value != null ? val.value : val.original || ''; - - if (this.stringParams) { - if (value.replace) { - value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.'); - } - - if (val.depth) { - this.addDepth(val.depth); - } - this.opcode('getContext', val.depth || 0); - this.opcode('pushStringParam', value, val.type); - - if (val.type === 'SubExpression') { - // SubExpressions get evaluated and passed in - // in string params mode. - this.accept(val); - } - } else { - if (this.trackIds) { - var blockParamIndex = undefined; - if (val.parts && !_ast2['default'].helpers.scopedId(val) && !val.depth) { - blockParamIndex = this.blockParamIndex(val.parts[0]); - } - if (blockParamIndex) { - var blockParamChild = val.parts.slice(1).join('.'); - this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild); - } else { - value = val.original || value; - if (value.replace) { - value = value.replace(/^this(?:\.|$)/, '').replace(/^\.\//, '').replace(/^\.$/, ''); - } - - this.opcode('pushId', val.type, value); - } - } - this.accept(val); - } - }, - - setupFullMustacheParams: function setupFullMustacheParams(sexpr, program, inverse, omitEmpty) { - var params = sexpr.params; - this.pushParams(params); - - this.opcode('pushProgram', program); - this.opcode('pushProgram', inverse); - - if (sexpr.hash) { - this.accept(sexpr.hash); - } else { - this.opcode('emptyHash', omitEmpty); - } - - return params; - }, - - blockParamIndex: function blockParamIndex(name) { - for (var depth = 0, len = this.options.blockParams.length; depth < len; depth++) { - var blockParams = this.options.blockParams[depth], - param = blockParams && _utils.indexOf(blockParams, name); - if (blockParams && param >= 0) { - return [depth, param]; - } - } - } - }; - - function precompile(input, options, env) { - if (input == null || typeof input !== 'string' && input.type !== 'Program') { - throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input); - } - - options = options || {}; - if (!('data' in options)) { - options.data = true; - } - if (options.compat) { - options.useDepths = true; - } - - var ast = env.parse(input, options), - environment = new env.Compiler().compile(ast, options); - return new env.JavaScriptCompiler().compile(environment, options); - } - - function compile(input, options, env) { - if (options === undefined) options = {}; - - if (input == null || typeof input !== 'string' && input.type !== 'Program') { - throw new _exception2['default']('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input); - } - - options = _utils.extend({}, options); - if (!('data' in options)) { - options.data = true; - } - if (options.compat) { - options.useDepths = true; - } - - var compiled = undefined; - - function compileInput() { - var ast = env.parse(input, options), - environment = new env.Compiler().compile(ast, options), - templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); - return env.template(templateSpec); - } - - // Template is only compiled on first use and cached after that point. - function ret(context, execOptions) { - if (!compiled) { - compiled = compileInput(); - } - return compiled.call(this, context, execOptions); - } - ret._setup = function (setupOptions) { - if (!compiled) { - compiled = compileInput(); - } - return compiled._setup(setupOptions); - }; - ret._child = function (i, data, blockParams, depths) { - if (!compiled) { - compiled = compileInput(); - } - return compiled._child(i, data, blockParams, depths); - }; - return ret; - } - - function argEquals(a, b) { - if (a === b) { - return true; - } - - if (_utils.isArray(a) && _utils.isArray(b) && a.length === b.length) { - for (var i = 0; i < a.length; i++) { - if (!argEquals(a[i], b[i])) { - return false; - } - } - return true; - } - } - - function transformLiteralToPath(sexpr) { - if (!sexpr.path.parts) { - var literal = sexpr.path; - // Casting to string here to make false and 0 literal values play nicely with the rest - // of the system. - sexpr.path = { - type: 'PathExpression', - data: false, - depth: 0, - parts: [literal.original + ''], - original: literal.original + '', - loc: literal.loc - }; - } - } - -/***/ }), -/* 42 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - var _interopRequireDefault = __webpack_require__(1)['default']; - - exports.__esModule = true; - - var _base = __webpack_require__(4); - - var _exception = __webpack_require__(6); - - var _exception2 = _interopRequireDefault(_exception); - - var _utils = __webpack_require__(5); - - var _codeGen = __webpack_require__(43); - - var _codeGen2 = _interopRequireDefault(_codeGen); - - function Literal(value) { - this.value = value; - } - - function JavaScriptCompiler() {} - - JavaScriptCompiler.prototype = { - // PUBLIC API: You can override these methods in a subclass to provide - // alternative compiled forms for name lookup and buffering semantics - nameLookup: function nameLookup(parent, name /* , type*/) { - if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { - return [parent, '.', name]; - } else { - return [parent, '[', JSON.stringify(name), ']']; - } - }, - depthedLookup: function depthedLookup(name) { - return [this.aliasable('container.lookup'), '(depths, "', name, '")']; - }, - - compilerInfo: function compilerInfo() { - var revision = _base.COMPILER_REVISION, - versions = _base.REVISION_CHANGES[revision]; - return [revision, versions]; - }, - - appendToBuffer: function appendToBuffer(source, location, explicit) { - // Force a source as this simplifies the merge logic. - if (!_utils.isArray(source)) { - source = [source]; - } - source = this.source.wrap(source, location); - - if (this.environment.isSimple) { - return ['return ', source, ';']; - } else if (explicit) { - // This is a case where the buffer operation occurs as a child of another - // construct, generally braces. We have to explicitly output these buffer - // operations to ensure that the emitted code goes in the correct location. - return ['buffer += ', source, ';']; - } else { - source.appendToBuffer = true; - return source; - } - }, - - initializeBuffer: function initializeBuffer() { - return this.quotedString(''); - }, - // END PUBLIC API - - compile: function compile(environment, options, context, asObject) { - this.environment = environment; - this.options = options; - this.stringParams = this.options.stringParams; - this.trackIds = this.options.trackIds; - this.precompile = !asObject; - - this.name = this.environment.name; - this.isChild = !!context; - this.context = context || { - decorators: [], - programs: [], - environments: [] - }; - - this.preamble(); - - this.stackSlot = 0; - this.stackVars = []; - this.aliases = {}; - this.registers = { list: [] }; - this.hashes = []; - this.compileStack = []; - this.inlineStack = []; - this.blockParams = []; - - this.compileChildren(environment, options); - - this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat; - this.useBlockParams = this.useBlockParams || environment.useBlockParams; - - var opcodes = environment.opcodes, - opcode = undefined, - firstLoc = undefined, - i = undefined, - l = undefined; - - for (i = 0, l = opcodes.length; i < l; i++) { - opcode = opcodes[i]; - - this.source.currentLocation = opcode.loc; - firstLoc = firstLoc || opcode.loc; - this[opcode.opcode].apply(this, opcode.args); - } - - // Flush any trailing content that might be pending. - this.source.currentLocation = firstLoc; - this.pushSource(''); - - /* istanbul ignore next */ - if (this.stackSlot || this.inlineStack.length || this.compileStack.length) { - throw new _exception2['default']('Compile completed with content left on stack'); - } - - if (!this.decorators.isEmpty()) { - this.useDecorators = true; - - this.decorators.prepend('var decorators = container.decorators;\n'); - this.decorators.push('return fn;'); - - if (asObject) { - this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]); - } else { - this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n'); - this.decorators.push('}\n'); - this.decorators = this.decorators.merge(); - } - } else { - this.decorators = undefined; - } - - var fn = this.createFunctionContext(asObject); - if (!this.isChild) { - var ret = { - compiler: this.compilerInfo(), - main: fn - }; - - if (this.decorators) { - ret.main_d = this.decorators; // eslint-disable-line camelcase - ret.useDecorators = true; - } - - var _context = this.context; - var programs = _context.programs; - var decorators = _context.decorators; - - for (i = 0, l = programs.length; i < l; i++) { - if (programs[i]) { - ret[i] = programs[i]; - if (decorators[i]) { - ret[i + '_d'] = decorators[i]; - ret.useDecorators = true; - } - } - } - - if (this.environment.usePartial) { - ret.usePartial = true; - } - if (this.options.data) { - ret.useData = true; - } - if (this.useDepths) { - ret.useDepths = true; - } - if (this.useBlockParams) { - ret.useBlockParams = true; - } - if (this.options.compat) { - ret.compat = true; - } - - if (!asObject) { - ret.compiler = JSON.stringify(ret.compiler); - - this.source.currentLocation = { start: { line: 1, column: 0 } }; - ret = this.objectLiteral(ret); - - if (options.srcName) { - ret = ret.toStringWithSourceMap({ file: options.destName }); - ret.map = ret.map && ret.map.toString(); - } else { - ret = ret.toString(); - } - } else { - ret.compilerOptions = this.options; - } - - return ret; - } else { - return fn; - } - }, - - preamble: function preamble() { - // track the last context pushed into place to allow skipping the - // getContext opcode when it would be a noop - this.lastContext = 0; - this.source = new _codeGen2['default'](this.options.srcName); - this.decorators = new _codeGen2['default'](this.options.srcName); - }, - - createFunctionContext: function createFunctionContext(asObject) { - var varDeclarations = ''; - - var locals = this.stackVars.concat(this.registers.list); - if (locals.length > 0) { - varDeclarations += ', ' + locals.join(', '); - } - - // Generate minimizer alias mappings - // - // When using true SourceNodes, this will update all references to the given alias - // as the source nodes are reused in situ. For the non-source node compilation mode, - // aliases will not be used, but this case is already being run on the client and - // we aren't concern about minimizing the template size. - var aliasCount = 0; - for (var alias in this.aliases) { - // eslint-disable-line guard-for-in - var node = this.aliases[alias]; - - if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) { - varDeclarations += ', alias' + ++aliasCount + '=' + alias; - node.children[0] = 'alias' + aliasCount; - } - } - - var params = ['container', 'depth0', 'helpers', 'partials', 'data']; - - if (this.useBlockParams || this.useDepths) { - params.push('blockParams'); - } - if (this.useDepths) { - params.push('depths'); - } - - // Perform a second pass over the output to merge content when possible - var source = this.mergeSource(varDeclarations); - - if (asObject) { - params.push(source); - - return Function.apply(this, params); - } else { - return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']); - } - }, - mergeSource: function mergeSource(varDeclarations) { - var isSimple = this.environment.isSimple, - appendOnly = !this.forceBuffer, - appendFirst = undefined, - sourceSeen = undefined, - bufferStart = undefined, - bufferEnd = undefined; - this.source.each(function (line) { - if (line.appendToBuffer) { - if (bufferStart) { - line.prepend(' + '); - } else { - bufferStart = line; - } - bufferEnd = line; - } else { - if (bufferStart) { - if (!sourceSeen) { - appendFirst = true; - } else { - bufferStart.prepend('buffer += '); - } - bufferEnd.add(';'); - bufferStart = bufferEnd = undefined; - } - - sourceSeen = true; - if (!isSimple) { - appendOnly = false; - } - } - }); - - if (appendOnly) { - if (bufferStart) { - bufferStart.prepend('return '); - bufferEnd.add(';'); - } else if (!sourceSeen) { - this.source.push('return "";'); - } - } else { - varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer()); - - if (bufferStart) { - bufferStart.prepend('return buffer + '); - bufferEnd.add(';'); - } else { - this.source.push('return buffer;'); - } - } - - if (varDeclarations) { - this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')); - } - - return this.source.merge(); - }, - - // [blockValue] - // - // On stack, before: hash, inverse, program, value - // On stack, after: return value of blockHelperMissing - // - // The purpose of this opcode is to take a block of the form - // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and - // replace it on the stack with the result of properly - // invoking blockHelperMissing. - blockValue: function blockValue(name) { - var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), - params = [this.contextName(0)]; - this.setupHelperArgs(name, 0, params); - - var blockName = this.popStack(); - params.splice(1, 0, blockName); - - this.push(this.source.functionCall(blockHelperMissing, 'call', params)); - }, - - // [ambiguousBlockValue] - // - // On stack, before: hash, inverse, program, value - // Compiler value, before: lastHelper=value of last found helper, if any - // On stack, after, if no lastHelper: same as [blockValue] - // On stack, after, if lastHelper: value - ambiguousBlockValue: function ambiguousBlockValue() { - // We're being a bit cheeky and reusing the options value from the prior exec - var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), - params = [this.contextName(0)]; - this.setupHelperArgs('', 0, params, true); - - this.flushInline(); - - var current = this.topStack(); - params.splice(1, 0, current); - - this.pushSource(['if (!', this.lastHelper, ') { ', current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), '}']); - }, - - // [appendContent] - // - // On stack, before: ... - // On stack, after: ... - // - // Appends the string value of `content` to the current buffer - appendContent: function appendContent(content) { - if (this.pendingContent) { - content = this.pendingContent + content; - } else { - this.pendingLocation = this.source.currentLocation; - } - - this.pendingContent = content; - }, - - // [append] - // - // On stack, before: value, ... - // On stack, after: ... - // - // Coerces `value` to a String and appends it to the current buffer. - // - // If `value` is truthy, or 0, it is coerced into a string and appended - // Otherwise, the empty string is appended - append: function append() { - if (this.isInline()) { - this.replaceStack(function (current) { - return [' != null ? ', current, ' : ""']; - }); - - this.pushSource(this.appendToBuffer(this.popStack())); - } else { - var local = this.popStack(); - this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']); - if (this.environment.isSimple) { - this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']); - } - } - }, - - // [appendEscaped] - // - // On stack, before: value, ... - // On stack, after: ... - // - // Escape `value` and append it to the buffer - appendEscaped: function appendEscaped() { - this.pushSource(this.appendToBuffer([this.aliasable('container.escapeExpression'), '(', this.popStack(), ')'])); - }, - - // [getContext] - // - // On stack, before: ... - // On stack, after: ... - // Compiler value, after: lastContext=depth - // - // Set the value of the `lastContext` compiler value to the depth - getContext: function getContext(depth) { - this.lastContext = depth; - }, - - // [pushContext] - // - // On stack, before: ... - // On stack, after: currentContext, ... - // - // Pushes the value of the current context onto the stack. - pushContext: function pushContext() { - this.pushStackLiteral(this.contextName(this.lastContext)); - }, - - // [lookupOnContext] - // - // On stack, before: ... - // On stack, after: currentContext[name], ... - // - // Looks up the value of `name` on the current context and pushes - // it onto the stack. - lookupOnContext: function lookupOnContext(parts, falsy, strict, scoped) { - var i = 0; - - if (!scoped && this.options.compat && !this.lastContext) { - // The depthed query is expected to handle the undefined logic for the root level that - // is implemented below, so we evaluate that directly in compat mode - this.push(this.depthedLookup(parts[i++])); - } else { - this.pushContext(); - } - - this.resolvePath('context', parts, i, falsy, strict); - }, - - // [lookupBlockParam] - // - // On stack, before: ... - // On stack, after: blockParam[name], ... - // - // Looks up the value of `parts` on the given block param and pushes - // it onto the stack. - lookupBlockParam: function lookupBlockParam(blockParamId, parts) { - this.useBlockParams = true; - - this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); - this.resolvePath('context', parts, 1); - }, - - // [lookupData] - // - // On stack, before: ... - // On stack, after: data, ... - // - // Push the data lookup operator - lookupData: function lookupData(depth, parts, strict) { - if (!depth) { - this.pushStackLiteral('data'); - } else { - this.pushStackLiteral('container.data(data, ' + depth + ')'); - } - - this.resolvePath('data', parts, 0, true, strict); - }, - - resolvePath: function resolvePath(type, parts, i, falsy, strict) { - // istanbul ignore next - - var _this = this; - - if (this.options.strict || this.options.assumeObjects) { - this.push(strictLookup(this.options.strict && strict, this, parts, type)); - return; - } - - var len = parts.length; - for (; i < len; i++) { - /* eslint-disable no-loop-func */ - this.replaceStack(function (current) { - var lookup = _this.nameLookup(current, parts[i], type); - // We want to ensure that zero and false are handled properly if the context (falsy flag) - // needs to have the special handling for these values. - if (!falsy) { - return [' != null ? ', lookup, ' : ', current]; - } else { - // Otherwise we can use generic falsy handling - return [' && ', lookup]; - } - }); - /* eslint-enable no-loop-func */ - } - }, - - // [resolvePossibleLambda] - // - // On stack, before: value, ... - // On stack, after: resolved value, ... - // - // If the `value` is a lambda, replace it on the stack by - // the return value of the lambda - resolvePossibleLambda: function resolvePossibleLambda() { - this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']); - }, - - // [pushStringParam] - // - // On stack, before: ... - // On stack, after: string, currentContext, ... - // - // This opcode is designed for use in string mode, which - // provides the string value of a parameter along with its - // depth rather than resolving it immediately. - pushStringParam: function pushStringParam(string, type) { - this.pushContext(); - this.pushString(type); - - // If it's a subexpression, the string result - // will be pushed after this opcode. - if (type !== 'SubExpression') { - if (typeof string === 'string') { - this.pushString(string); - } else { - this.pushStackLiteral(string); - } - } - }, - - emptyHash: function emptyHash(omitEmpty) { - if (this.trackIds) { - this.push('{}'); // hashIds - } - if (this.stringParams) { - this.push('{}'); // hashContexts - this.push('{}'); // hashTypes - } - this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); - }, - pushHash: function pushHash() { - if (this.hash) { - this.hashes.push(this.hash); - } - this.hash = { values: [], types: [], contexts: [], ids: [] }; - }, - popHash: function popHash() { - var hash = this.hash; - this.hash = this.hashes.pop(); - - if (this.trackIds) { - this.push(this.objectLiteral(hash.ids)); - } - if (this.stringParams) { - this.push(this.objectLiteral(hash.contexts)); - this.push(this.objectLiteral(hash.types)); - } - - this.push(this.objectLiteral(hash.values)); - }, - - // [pushString] - // - // On stack, before: ... - // On stack, after: quotedString(string), ... - // - // Push a quoted version of `string` onto the stack - pushString: function pushString(string) { - this.pushStackLiteral(this.quotedString(string)); - }, - - // [pushLiteral] - // - // On stack, before: ... - // On stack, after: value, ... - // - // Pushes a value onto the stack. This operation prevents - // the compiler from creating a temporary variable to hold - // it. - pushLiteral: function pushLiteral(value) { - this.pushStackLiteral(value); - }, - - // [pushProgram] - // - // On stack, before: ... - // On stack, after: program(guid), ... - // - // Push a program expression onto the stack. This takes - // a compile-time guid and converts it into a runtime-accessible - // expression. - pushProgram: function pushProgram(guid) { - if (guid != null) { - this.pushStackLiteral(this.programExpression(guid)); - } else { - this.pushStackLiteral(null); - } - }, - - // [registerDecorator] - // - // On stack, before: hash, program, params..., ... - // On stack, after: ... - // - // Pops off the decorator's parameters, invokes the decorator, - // and inserts the decorator into the decorators list. - registerDecorator: function registerDecorator(paramSize, name) { - var foundDecorator = this.nameLookup('decorators', name, 'decorator'), - options = this.setupHelperArgs(name, paramSize); - - this.decorators.push(['fn = ', this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]), ' || fn;']); - }, - - // [invokeHelper] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of helper invocation - // - // Pops off the helper's parameters, invokes the helper, - // and pushes the helper's return value onto the stack. - // - // If the helper is not found, `helperMissing` is called. - invokeHelper: function invokeHelper(paramSize, name, isSimple) { - var nonHelper = this.popStack(), - helper = this.setupHelper(paramSize, name), - simple = isSimple ? [helper.name, ' || '] : ''; - - var lookup = ['('].concat(simple, nonHelper); - if (!this.options.strict) { - lookup.push(' || ', this.aliasable('helpers.helperMissing')); - } - lookup.push(')'); - - this.push(this.source.functionCall(lookup, 'call', helper.callParams)); - }, - - // [invokeKnownHelper] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of helper invocation - // - // This operation is used when the helper is known to exist, - // so a `helperMissing` fallback is not required. - invokeKnownHelper: function invokeKnownHelper(paramSize, name) { - var helper = this.setupHelper(paramSize, name); - this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); - }, - - // [invokeAmbiguous] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of disambiguation - // - // This operation is used when an expression like `{{foo}}` - // is provided, but we don't know at compile-time whether it - // is a helper or a path. - // - // This operation emits more code than the other options, - // and can be avoided by passing the `knownHelpers` and - // `knownHelpersOnly` flags at compile-time. - invokeAmbiguous: function invokeAmbiguous(name, helperCall) { - this.useRegister('helper'); - - var nonHelper = this.popStack(); - - this.emptyHash(); - var helper = this.setupHelper(0, name, helperCall); - - var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); - - var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')']; - if (!this.options.strict) { - lookup[0] = '(helper = '; - lookup.push(' != null ? helper : ', this.aliasable('helpers.helperMissing')); - } - - this.push(['(', lookup, helper.paramsInit ? ['),(', helper.paramsInit] : [], '),', '(typeof helper === ', this.aliasable('"function"'), ' ? ', this.source.functionCall('helper', 'call', helper.callParams), ' : helper))']); - }, - - // [invokePartial] - // - // On stack, before: context, ... - // On stack after: result of partial invocation - // - // This operation pops off a context, invokes a partial with that context, - // and pushes the result of the invocation back. - invokePartial: function invokePartial(isDynamic, name, indent) { - var params = [], - options = this.setupParams(name, 1, params); - - if (isDynamic) { - name = this.popStack(); - delete options.name; - } - - if (indent) { - options.indent = JSON.stringify(indent); - } - options.helpers = 'helpers'; - options.partials = 'partials'; - options.decorators = 'container.decorators'; - - if (!isDynamic) { - params.unshift(this.nameLookup('partials', name, 'partial')); - } else { - params.unshift(name); - } - - if (this.options.compat) { - options.depths = 'depths'; - } - options = this.objectLiteral(options); - params.push(options); - - this.push(this.source.functionCall('container.invokePartial', '', params)); - }, - - // [assignToHash] - // - // On stack, before: value, ..., hash, ... - // On stack, after: ..., hash, ... - // - // Pops a value off the stack and assigns it to the current hash - assignToHash: function assignToHash(key) { - var value = this.popStack(), - context = undefined, - type = undefined, - id = undefined; - - if (this.trackIds) { - id = this.popStack(); - } - if (this.stringParams) { - type = this.popStack(); - context = this.popStack(); - } - - var hash = this.hash; - if (context) { - hash.contexts[key] = context; - } - if (type) { - hash.types[key] = type; - } - if (id) { - hash.ids[key] = id; - } - hash.values[key] = value; - }, - - pushId: function pushId(type, name, child) { - if (type === 'BlockParam') { - this.pushStackLiteral('blockParams[' + name[0] + '].path[' + name[1] + ']' + (child ? ' + ' + JSON.stringify('.' + child) : '')); - } else if (type === 'PathExpression') { - this.pushString(name); - } else if (type === 'SubExpression') { - this.pushStackLiteral('true'); - } else { - this.pushStackLiteral('null'); - } - }, - - // HELPERS - - compiler: JavaScriptCompiler, - - compileChildren: function compileChildren(environment, options) { - var children = environment.children, - child = undefined, - compiler = undefined; - - for (var i = 0, l = children.length; i < l; i++) { - child = children[i]; - compiler = new this.compiler(); // eslint-disable-line new-cap - - var existing = this.matchExistingProgram(child); - - if (existing == null) { - this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children - var index = this.context.programs.length; - child.index = index; - child.name = 'program' + index; - this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); - this.context.decorators[index] = compiler.decorators; - this.context.environments[index] = child; - - this.useDepths = this.useDepths || compiler.useDepths; - this.useBlockParams = this.useBlockParams || compiler.useBlockParams; - child.useDepths = this.useDepths; - child.useBlockParams = this.useBlockParams; - } else { - child.index = existing.index; - child.name = 'program' + existing.index; - - this.useDepths = this.useDepths || existing.useDepths; - this.useBlockParams = this.useBlockParams || existing.useBlockParams; - } - } - }, - matchExistingProgram: function matchExistingProgram(child) { - for (var i = 0, len = this.context.environments.length; i < len; i++) { - var environment = this.context.environments[i]; - if (environment && environment.equals(child)) { - return environment; - } - } - }, - - programExpression: function programExpression(guid) { - var child = this.environment.children[guid], - programParams = [child.index, 'data', child.blockParams]; - - if (this.useBlockParams || this.useDepths) { - programParams.push('blockParams'); - } - if (this.useDepths) { - programParams.push('depths'); - } - - return 'container.program(' + programParams.join(', ') + ')'; - }, - - useRegister: function useRegister(name) { - if (!this.registers[name]) { - this.registers[name] = true; - this.registers.list.push(name); - } - }, - - push: function push(expr) { - if (!(expr instanceof Literal)) { - expr = this.source.wrap(expr); - } - - this.inlineStack.push(expr); - return expr; - }, - - pushStackLiteral: function pushStackLiteral(item) { - this.push(new Literal(item)); - }, - - pushSource: function pushSource(source) { - if (this.pendingContent) { - this.source.push(this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation)); - this.pendingContent = undefined; - } - - if (source) { - this.source.push(source); - } - }, - - replaceStack: function replaceStack(callback) { - var prefix = ['('], - stack = undefined, - createdStack = undefined, - usedLiteral = undefined; - - /* istanbul ignore next */ - if (!this.isInline()) { - throw new _exception2['default']('replaceStack on non-inline'); - } - - // We want to merge the inline statement into the replacement statement via ',' - var top = this.popStack(true); - - if (top instanceof Literal) { - // Literals do not need to be inlined - stack = [top.value]; - prefix = ['(', stack]; - usedLiteral = true; - } else { - // Get or create the current stack name for use by the inline - createdStack = true; - var _name = this.incrStack(); - - prefix = ['((', this.push(_name), ' = ', top, ')']; - stack = this.topStack(); - } - - var item = callback.call(this, stack); - - if (!usedLiteral) { - this.popStack(); - } - if (createdStack) { - this.stackSlot--; - } - this.push(prefix.concat(item, ')')); - }, - - incrStack: function incrStack() { - this.stackSlot++; - if (this.stackSlot > this.stackVars.length) { - this.stackVars.push('stack' + this.stackSlot); - } - return this.topStackName(); - }, - topStackName: function topStackName() { - return 'stack' + this.stackSlot; - }, - flushInline: function flushInline() { - var inlineStack = this.inlineStack; - this.inlineStack = []; - for (var i = 0, len = inlineStack.length; i < len; i++) { - var entry = inlineStack[i]; - /* istanbul ignore if */ - if (entry instanceof Literal) { - this.compileStack.push(entry); - } else { - var stack = this.incrStack(); - this.pushSource([stack, ' = ', entry, ';']); - this.compileStack.push(stack); - } - } - }, - isInline: function isInline() { - return this.inlineStack.length; - }, - - popStack: function popStack(wrapped) { - var inline = this.isInline(), - item = (inline ? this.inlineStack : this.compileStack).pop(); - - if (!wrapped && item instanceof Literal) { - return item.value; - } else { - if (!inline) { - /* istanbul ignore next */ - if (!this.stackSlot) { - throw new _exception2['default']('Invalid stack pop'); - } - this.stackSlot--; - } - return item; - } - }, - - topStack: function topStack() { - var stack = this.isInline() ? this.inlineStack : this.compileStack, - item = stack[stack.length - 1]; - - /* istanbul ignore if */ - if (item instanceof Literal) { - return item.value; - } else { - return item; - } - }, - - contextName: function contextName(context) { - if (this.useDepths && context) { - return 'depths[' + context + ']'; - } else { - return 'depth' + context; - } - }, - - quotedString: function quotedString(str) { - return this.source.quotedString(str); - }, - - objectLiteral: function objectLiteral(obj) { - return this.source.objectLiteral(obj); - }, - - aliasable: function aliasable(name) { - var ret = this.aliases[name]; - if (ret) { - ret.referenceCount++; - return ret; - } - - ret = this.aliases[name] = this.source.wrap(name); - ret.aliasable = true; - ret.referenceCount = 1; - - return ret; - }, - - setupHelper: function setupHelper(paramSize, name, blockHelper) { - var params = [], - paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); - var foundHelper = this.nameLookup('helpers', name, 'helper'), - callContext = this.aliasable(this.contextName(0) + ' != null ? ' + this.contextName(0) + ' : (container.nullContext || {})'); - - return { - params: params, - paramsInit: paramsInit, - name: foundHelper, - callParams: [callContext].concat(params) - }; - }, - - setupParams: function setupParams(helper, paramSize, params) { - var options = {}, - contexts = [], - types = [], - ids = [], - objectArgs = !params, - param = undefined; - - if (objectArgs) { - params = []; - } - - options.name = this.quotedString(helper); - options.hash = this.popStack(); - - if (this.trackIds) { - options.hashIds = this.popStack(); - } - if (this.stringParams) { - options.hashTypes = this.popStack(); - options.hashContexts = this.popStack(); - } - - var inverse = this.popStack(), - program = this.popStack(); - - // Avoid setting fn and inverse if neither are set. This allows - // helpers to do a check for `if (options.fn)` - if (program || inverse) { - options.fn = program || 'container.noop'; - options.inverse = inverse || 'container.noop'; - } - - // The parameters go on to the stack in order (making sure that they are evaluated in order) - // so we need to pop them off the stack in reverse order - var i = paramSize; - while (i--) { - param = this.popStack(); - params[i] = param; - - if (this.trackIds) { - ids[i] = this.popStack(); - } - if (this.stringParams) { - types[i] = this.popStack(); - contexts[i] = this.popStack(); - } - } - - if (objectArgs) { - options.args = this.source.generateArray(params); - } - - if (this.trackIds) { - options.ids = this.source.generateArray(ids); - } - if (this.stringParams) { - options.types = this.source.generateArray(types); - options.contexts = this.source.generateArray(contexts); - } - - if (this.options.data) { - options.data = 'data'; - } - if (this.useBlockParams) { - options.blockParams = 'blockParams'; - } - return options; - }, - - setupHelperArgs: function setupHelperArgs(helper, paramSize, params, useRegister) { - var options = this.setupParams(helper, paramSize, params); - options = this.objectLiteral(options); - if (useRegister) { - this.useRegister('options'); - params.push('options'); - return ['options=', options]; - } else if (params) { - params.push(options); - return ''; - } else { - return options; - } - } - }; - - (function () { - var reservedWords = ('break else new var' + ' case finally return void' + ' catch for switch while' + ' continue function this with' + ' default if throw' + ' delete in try' + ' do instanceof typeof' + ' abstract enum int short' + ' boolean export interface static' + ' byte extends long super' + ' char final native synchronized' + ' class float package throws' + ' const goto private transient' + ' debugger implements protected volatile' + ' double import public let yield await' + ' null true false').split(' '); - - var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; - - for (var i = 0, l = reservedWords.length; i < l; i++) { - compilerWords[reservedWords[i]] = true; - } - })(); - - JavaScriptCompiler.isValidJavaScriptVariableName = function (name) { - return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name); - }; - - function strictLookup(requireTerminal, compiler, parts, type) { - var stack = compiler.popStack(), - i = 0, - len = parts.length; - if (requireTerminal) { - len--; - } - - for (; i < len; i++) { - stack = compiler.nameLookup(stack, parts[i], type); - } - - if (requireTerminal) { - return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')']; - } else { - return stack; - } - } - - exports['default'] = JavaScriptCompiler; - module.exports = exports['default']; - -/***/ }), -/* 43 */ -/***/ (function(module, exports, __webpack_require__) { - - /* global define */ - 'use strict'; - - exports.__esModule = true; - - var _utils = __webpack_require__(5); - - var SourceNode = undefined; - - try { - /* istanbul ignore next */ - if (false) { - // We don't support this in AMD environments. For these environments, we asusme that - // they are running on the browser and thus have no need for the source-map library. - var SourceMap = require('source-map'); - SourceNode = SourceMap.SourceNode; - } - } catch (err) {} - /* NOP */ - - /* istanbul ignore if: tested but not covered in istanbul due to dist build */ - if (!SourceNode) { - SourceNode = function (line, column, srcFile, chunks) { - this.src = ''; - if (chunks) { - this.add(chunks); - } - }; - /* istanbul ignore next */ - SourceNode.prototype = { - add: function add(chunks) { - if (_utils.isArray(chunks)) { - chunks = chunks.join(''); - } - this.src += chunks; - }, - prepend: function prepend(chunks) { - if (_utils.isArray(chunks)) { - chunks = chunks.join(''); - } - this.src = chunks + this.src; - }, - toStringWithSourceMap: function toStringWithSourceMap() { - return { code: this.toString() }; - }, - toString: function toString() { - return this.src; - } - }; - } - - function castChunk(chunk, codeGen, loc) { - if (_utils.isArray(chunk)) { - var ret = []; - - for (var i = 0, len = chunk.length; i < len; i++) { - ret.push(codeGen.wrap(chunk[i], loc)); - } - return ret; - } else if (typeof chunk === 'boolean' || typeof chunk === 'number') { - // Handle primitives that the SourceNode will throw up on - return chunk + ''; - } - return chunk; - } - - function CodeGen(srcFile) { - this.srcFile = srcFile; - this.source = []; - } - - CodeGen.prototype = { - isEmpty: function isEmpty() { - return !this.source.length; - }, - prepend: function prepend(source, loc) { - this.source.unshift(this.wrap(source, loc)); - }, - push: function push(source, loc) { - this.source.push(this.wrap(source, loc)); - }, - - merge: function merge() { - var source = this.empty(); - this.each(function (line) { - source.add([' ', line, '\n']); - }); - return source; - }, - - each: function each(iter) { - for (var i = 0, len = this.source.length; i < len; i++) { - iter(this.source[i]); - } - }, - - empty: function empty() { - var loc = this.currentLocation || { start: {} }; - return new SourceNode(loc.start.line, loc.start.column, this.srcFile); - }, - wrap: function wrap(chunk) { - var loc = arguments.length <= 1 || arguments[1] === undefined ? this.currentLocation || { start: {} } : arguments[1]; - - if (chunk instanceof SourceNode) { - return chunk; - } - - chunk = castChunk(chunk, this, loc); - - return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk); - }, - - functionCall: function functionCall(fn, type, params) { - params = this.generateList(params); - return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']); - }, - - quotedString: function quotedString(str) { - return '"' + (str + '').replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 - .replace(/\u2029/g, '\\u2029') + '"'; - }, - - objectLiteral: function objectLiteral(obj) { - var pairs = []; - - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - var value = castChunk(obj[key], this); - if (value !== 'undefined') { - pairs.push([this.quotedString(key), ':', value]); - } - } - } - - var ret = this.generateList(pairs); - ret.prepend('{'); - ret.add('}'); - return ret; - }, - - generateList: function generateList(entries) { - var ret = this.empty(); - - for (var i = 0, len = entries.length; i < len; i++) { - if (i) { - ret.add(','); - } - - ret.add(castChunk(entries[i], this)); - } - - return ret; - }, - - generateArray: function generateArray(entries) { - var ret = this.generateList(entries); - ret.prepend('['); - ret.add(']'); - - return ret; - } - }; - - exports['default'] = CodeGen; - module.exports = exports['default']; - -/***/ }) -/******/ ]) -}); -; \ No newline at end of file diff --git a/content/js/jquery-resizeable.js b/content/js/jquery-resizeable.js deleted file mode 100644 index 621ef51..0000000 --- a/content/js/jquery-resizeable.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -!function(e,t){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e,t){e.fn.resizable||(e.fn.resizable=function(t){var n={handleSelector:null,resizeWidth:!0,resizeHeight:!0,resizeWidthFrom:"right",resizeHeightFrom:"bottom",onDragStart:null,onDragEnd:null,onDrag:null,touchActionNone:!0,instanceId:null};return"object"==typeof t&&(n=e.extend(n,t)),this.each(function(){function o(e){e.stopPropagation(),e.preventDefault()}function i(t){t.preventDefault&&t.preventDefault(),d=c(t),d.width=parseInt(f.width(),10),d.height=parseInt(f.height(),10),h=f.css("transition"),f.css("transition","none"),u.onDragStart&&u.onDragStart(t,f,u)===!1||(e(document).on("mousemove."+u.instanceId,r),e(document).on("mouseup."+u.instanceId,a),(window.Touch||navigator.maxTouchPoints)&&(e(document).on("touchmove."+u.instanceId,r),e(document).on("touchend."+u.instanceId,a)),e(document).on("selectstart."+u.instanceId,o))}function r(e){var t,n,o=c(e);t="left"===u.resizeWidthFrom?d.width-o.x+d.x:d.width+o.x-d.x,n="top"===u.resizeHeightFrom?d.height-o.y+d.y:d.height+o.y-d.y,u.onDrag&&u.onDrag(e,f,t,n,u)===!1||(u.resizeHeight&&f.height(n),u.resizeWidth&&f.width(t))}function a(t){return t.stopPropagation(),t.preventDefault(),e(document).off("mousemove."+u.instanceId),e(document).off("mouseup."+u.instanceId),(window.Touch||navigator.maxTouchPoints)&&(e(document).off("touchmove."+u.instanceId),e(document).off("touchend."+u.instanceId)),e(document).off("selectstart."+u.instanceId,o),f.css("transition",h),u.onDragEnd&&u.onDragEnd(t,f,u),!1}function c(e){var t={x:0,y:0,width:0,height:0};if("number"==typeof e.clientX)t.x=e.clientX,t.y=e.clientY;else{if(!e.originalEvent.touches)return null;t.x=e.originalEvent.touches[0].clientX,t.y=e.originalEvent.touches[0].clientY}return t}function s(e,t){return e&&">"===e.trim()[0]?(e=e.trim().replace(/^>\s*/,""),t.find(e)):e?t.parent().find(e):t}var u=e.extend({},n);u.instanceId||(u.instanceId="rsz_"+(new Date).getTime());var d,h,l,f=e(this);if("destroy"===t){if(u=f.data("resizable"),!u)return;return l=s(u.handleSelector,f),l.off("mousedown."+u.instanceId+" touchstart."+u.instanceId),u.touchActionNone&&l.css("touch-action",""),void f.removeClass("resizable")}f.data("resizable",u),l=s(u.handleSelector,f),u.touchActionNone&&l.css("touch-action","none"),f.addClass("resizable"),l.on("mousedown."+u.instanceId+" touchstart."+u.instanceId,i)})})}); \ No newline at end of file diff --git a/content/js/keep-in-touch-days.js b/content/js/keep-in-touch-days.js deleted file mode 100644 index 7966a10..0000000 --- a/content/js/keep-in-touch-days.js +++ /dev/null @@ -1,45 +0,0 @@ -$(function() { - bindListOfKeepInTouchDays(); - - $("#add-keep-in-touch-day").on("click", function() { - var $container = $("#keep-in-touch-days-container"); - var obj = { Date: "" }; - var content = Templates["keepInTouchDayTemplate"](obj); - - $container.append(content); - }); - - $(document).on("click", ".remove-keep-in-touch-day", function () { - var $keepInTouchDay = $(this).closest(".keep-in-touch-day"); - - $keepInTouchDay.remove(); - - updateKeepInTouchDaysHiddenField(); - }); - - $(document).on("change", "input[type=date].keep-in-touch-day", function () { - updateKeepInTouchDaysHiddenField(); - }); -}); - -function bindListOfKeepInTouchDays() { - var $hiddenField = $("input[type=hidden]#KeepInTouchDays"); - var values = $hiddenField.val().split("|"); - var $container = $("#keep-in-touch-days-container"); - - for (var i = 0; i < values.length; i++) { - var value = values[i]; - var obj = { Date: value }; - var content = Templates["keepInTouchDayTemplate"](obj); - - $container.append(content); - } -} - -function updateKeepInTouchDaysHiddenField() { - var $hiddenField = $("input[type=hidden]#KeepInTouchDays"); - - var values = $("input[type=date].keep-in-touch-day").toArray().map(el => $(el).val()); - - $hiddenField.val(values.join("|")); -} \ No newline at end of file diff --git a/content/js/p45-pay-instruction.js b/content/js/p45-pay-instruction.js deleted file mode 100644 index ea1d072..0000000 --- a/content/js/p45-pay-instruction.js +++ /dev/null @@ -1,38 +0,0 @@ -$(function() { - $("#add-p45-pay-instruction").on("click", function() { - var $self = $(this); - var $container = $("#p45-pay-instruction-container"); - - $self.closest(".row").hide(); - $container.removeClass("display-none").addClass("display-block"); - }); - - $("#delete-p45-pay-instruction").on("click", function() { - var $self = $(this); - var id = $self.attr("data-id"); - var employeeId = $self.attr("data-employee-id"); - var employerId = $self.attr("data-employer-id"); - - bootbox.confirm({ - title: "Are you sure?", - message: "Are you sure you want to delete this pay instruction?", - callback: function(result) { - if (result) { - var postUrl = `/employer/${employerId}/employee/${employeeId}/payInstruction/${id}/delete`; - - $.post(postUrl).done(function(data) { - if (data.errors) { - showValidationErrors(data.errors); - return; - } - - $("#add-p45-pay-instruction-container").removeClass("display-none").addClass("display-block"); - $("#p45-pay-instruction-container").removeClass("display-block").addClass("display-none"); - - showStatus("Instruction successfully deleted", "success"); - }); - } - } - }); - }); -}); \ No newline at end of file diff --git a/content/js/parsley.min.js b/content/js/parsley.min.js deleted file mode 100644 index 3ba3bbb..0000000 --- a/content/js/parsley.min.js +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable */ -/*! -* Parsley.js -* Version 2.8.1 - built Sat, Feb 3rd 2018, 2:27 pm -* http://parsleyjs.org -* Guillaume Potier - -* Marc-Andre Lafortune - -* MIT Licensed -*/ -function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t - * @license MIT - */ -function n(){var t=this,i=window||global;_extends(this,{isNativeEvent:function(e){return e.originalEvent&&e.originalEvent.isTrusted!==!1},fakeInputEvent:function(i){t.isNativeEvent(i)&&e(i.target).trigger("input")},misbehaves:function(i){t.isNativeEvent(i)&&(t.behavesOk(i),e(document).on("change.inputevent",i.data.selector,t.fakeInputEvent),t.fakeInputEvent(i))},behavesOk:function(i){t.isNativeEvent(i)&&e(document).off("input.inputevent",i.data.selector,t.behavesOk).off("change.inputevent",i.data.selector,t.misbehaves)},install:function(){if(!i.inputEventPatched){i.inputEventPatched="0.0.3";for(var n=["select",'input[type="checkbox"]','input[type="radio"]','input[type="file"]'],r=0;r1)throw Error("Second argument not supported");if("object"!=typeof t)throw TypeError("Argument must be an object");e.prototype=t;var i=new e;return e.prototype=null,i}}(),_SubmitSelector:'input[type="submit"], button:submit'},o={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset], input[type=hidden]",priorityEnabled:!0,multiple:null,group:null,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,triggerAfterFailure:"input",errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(e){},errorsContainer:function(e){},errorsWrapper:'
      ',errorTemplate:"
    • "},l=function(){this.__id__=a.generateID()};l.prototype={asyncSupport:!0,_pipeAccordingToValidationResult:function(){var t=this,i=function(){var i=e.Deferred();return!0!==t.validationResult&&i.reject(),i.resolve().promise()};return[i,i]},actualizeOptions:function(){return a.attr(this.element,this.options.namespace,this.domOptions),this.parent&&this.parent.actualizeOptions&&this.parent.actualizeOptions(),this},_resetOptions:function(e){this.domOptions=a.objectCreate(this.parent.options),this.options=a.objectCreate(this.domOptions);for(var t in e)e.hasOwnProperty(t)&&(this.options[t]=e[t]);this.actualizeOptions()},_listeners:null,on:function(e,t){this._listeners=this._listeners||{};var i=this._listeners[e]=this._listeners[e]||[];return i.push(t),this},subscribe:function(t,i){e.listenTo(this,t.toLowerCase(),i)},off:function(e,t){var i=this._listeners&&this._listeners[e];if(i)if(t)for(var n=i.length;n--;)i[n]===t&&i.splice(n,1);else delete this._listeners[e];return this},unsubscribe:function(t,i){e.unsubscribeTo(this,t.toLowerCase())},trigger:function(e,t,i){t=t||this;var n,r=this._listeners&&this._listeners[e];if(r)for(var s=r.length;s--;)if(n=r[s].call(t,t,i),n===!1)return n;return!this.parent||this.parent.trigger(e,t,i)},asyncIsValid:function(e,t){return a.warnOnce("asyncIsValid is deprecated; please use whenValid instead"),this.whenValid({group:e,force:t})},_findRelated:function(){return this.options.multiple?e(this.parent.element.querySelectorAll("["+this.options.namespace+'multiple="'+this.options.multiple+'"]')):this.$element}};var u=function(e,t){var i=e.match(/^\s*\[(.*)\]\s*$/);if(!i)throw'Requirement is not an array: "'+e+'"';var n=i[1].split(",").map(a.trimString);if(n.length!==t)throw"Requirement has "+n.length+" values when "+t+" are needed";return n},d=function(e,t,i){var n=null,r={};for(var s in e)if(s){var o=i(s);"string"==typeof o&&(o=a.parseRequirement(e[s],o)),r[s]=o}else n=a.parseRequirement(e[s],t);return[n,r]},h=function(t){e.extend(!0,this,t)};h.prototype={validate:function(e,t){if(this.fn)return arguments.length>3&&(t=[].slice.call(arguments,1,-1)),this.fn(e,t);if(Array.isArray(e)){if(!this.validateMultiple)throw"Validator `"+this.name+"` does not handle multiple values";return this.validateMultiple.apply(this,arguments)}var i=arguments[arguments.length-1];if(this.validateDate&&i._isDateInput())return arguments[0]=a.parse.date(arguments[0]),null!==arguments[0]&&this.validateDate.apply(this,arguments);if(this.validateNumber)return!isNaN(e)&&(arguments[0]=parseFloat(arguments[0]),this.validateNumber.apply(this,arguments));if(this.validateString)return this.validateString.apply(this,arguments);throw"Validator `"+this.name+"` only handles multiple values"},parseRequirements:function(t,i){if("string"!=typeof t)return Array.isArray(t)?t:[t];var n=this.requirementType;if(Array.isArray(n)){for(var r=u(t,n.length),s=0;s1?n-1:0),s=1;s0},validateString:function(e){return/\S/.test(e)},priority:512},type:{validateString:function(e,t){var i=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],n=i.step,r=void 0===n?"any":n,s=i.base,a=void 0===s?0:s,o=c[t];if(!o)throw new Error("validator type `"+t+"` is not supported");if(!o.test(e))return!1;if("number"===t&&!/^any$/i.test(r||"")){var l=Number(e),u=Math.max(f(r),f(a));if(f(l)>u)return!1;var d=function(e){return Math.round(e*Math.pow(10,u))};if((d(l)-d(a))%d(r)!=0)return!1}return!0},requirementType:{"":"string",step:"string",base:"number"},priority:256},pattern:{validateString:function(e,t){return t.test(e)},requirementType:"regexp",priority:64},minlength:{validateString:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxlength:{validateString:function(e,t){return e.length<=t},requirementType:"integer",priority:30},length:{validateString:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},mincheck:{validateMultiple:function(e,t){return e.length>=t},requirementType:"integer",priority:30},maxcheck:{validateMultiple:function(e,t){return e.length<=t},requirementType:"integer",priority:30},check:{validateMultiple:function(e,t,i){return e.length>=t&&e.length<=i},requirementType:["integer","integer"],priority:30},min:v(function(e,t){return e>=t}),max:v(function(e,t){return e<=t}),range:v(function(e,t,i){return e>=t&&e<=i}),equalto:{validateString:function(t,i){var n=e(i);return n.length?t===n.val():t===i},priority:256}}};var y={},_=function k(e,t,i){for(var n=[],r=[],s=0;s0&&"undefined"==typeof t.options.noFocus&&(this._focusedField=t.$element,"first"===this.options.focus))break}return null===this._focusedField?null:this._focusedField.focus()},_destroyUI:function(){this.$element.off(".Parsley")}},y.Field={_reflowUI:function(){if(this._buildUI(),this._ui){var e=_(this.validationResult,this._ui.lastValidationResult);this._ui.lastValidationResult=this.validationResult,this._manageStatusClass(),this._manageErrorsMessages(e),this._actualizeTriggers(),!e.kept.length&&!e.added.length||this._failedOnce||(this._failedOnce=!0,this._actualizeTriggers())}},getErrorsMessages:function(){if(!0===this.validationResult)return[];for(var e=[],t=0;t0?this._errorClass():this._resetClass()},_manageErrorsMessages:function(t){if("undefined"==typeof this.options.errorsMessagesDisabled){if("undefined"!=typeof this.options.errorMessage)return t.added.length||t.kept.length?(this._insertErrorWrapper(),0===this._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&this._ui.$errorsWrapper.append(e(this.options.errorTemplate).addClass("parsley-custom-error-message")),this._ui.$errorsWrapper.addClass("filled").find(".parsley-custom-error-message").html(this.options.errorMessage)):this._ui.$errorsWrapper.removeClass("filled").find(".parsley-custom-error-message").remove();for(var i=0;i').appendTo(this.$element)),i.attr({name:t.getAttribute("name"),value:t.getAttribute("value")})}this.$element.trigger(_extends(e.Event("submit"),{parsley:!0}))}},validate:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling validate on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1],s=i[2];t={group:n,force:r,event:s}}return b[this.whenValidate(t).state()]},whenValidate:function(){var t,i=this,n=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],r=n.group,s=n.force,o=n.event;this.submitEvent=o,o&&(this.submitEvent=_extends({},o,{preventDefault:function(){a.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`"),i.validationResult=!1}})),this.validationResult=!0,this._trigger("validate"),this._refreshFields();var l=this._withoutReactualizingFormOptions(function(){return e.map(i.fields,function(e){return e.whenValidate({force:s,group:r})})});return(t=a.all(l).done(function(){i._trigger("success")}).fail(function(){i.validationResult=!1,i.focus(),i._trigger("error")}).always(function(){i._trigger("validated")})).pipe.apply(t,_toConsumableArray(this._pipeAccordingToValidationResult()))},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley form without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={group:n,force:r}}return b[this.whenValid(t).state()]},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.group,r=i.force;this._refreshFields();var s=this._withoutReactualizingFormOptions(function(){return e.map(t.fields,function(e){return e.whenValid({group:n,force:r})})});return a.all(s)},refresh:function(){return this._refreshFields(),this},reset:function(){for(var e=0;e=1&&!e.isPlainObject(t)&&(a.warnOnce("Calling validate on a parsley field without passing arguments as an object is deprecated."),t={options:t});var i=this.whenValidate(t);if(!i)return!0;switch(i.state()){case"pending":return null;case"resolved":return!0;case"rejected":return this.validationResult}},whenValidate:function(){var e,t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.force,r=i.group;if(this.refresh(),!r||this._isInGroup(r))return this.value=this.getValue(),this._trigger("validate"),(e=this.whenValid({force:n,value:this.value,_refreshed:!0}).always(function(){t._reflowUI()}).done(function(){t._trigger("success")}).fail(function(){t._trigger("error")}).always(function(){t._trigger("validated")})).pipe.apply(e,_toConsumableArray(this._pipeAccordingToValidationResult()))},hasConstraints:function(){return 0!==this.constraints.length},needsValidation:function(e){return"undefined"==typeof e&&(e=this.getValue()),!(!e.length&&!this._isRequired()&&"undefined"==typeof this.options.validateIfEmpty)},_isInGroup:function(t){return Array.isArray(this.options.group)?-1!==e.inArray(t,this.options.group):this.options.group===t},isValid:function(t){if(arguments.length>=1&&!e.isPlainObject(t)){a.warnOnce("Calling isValid on a parsley field without passing arguments as an object is deprecated.");var i=_slice.call(arguments),n=i[0],r=i[1];t={force:n,value:r}}var s=this.whenValid(t);return!s||E[s.state()]},whenValid:function(){var t=this,i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=i.force,r=void 0!==n&&n,s=i.value,o=i.group,l=i._refreshed;if(l||this.refresh(),!o||this._isInGroup(o)){if(this.validationResult=!0,!this.hasConstraints())return e.when();if("undefined"!=typeof s&&null!==s||(s=this.getValue()),!this.needsValidation(s)&&!0!==r)return e.when();var u=this._getGroupedConstraints(),d=[];return e.each(u,function(i,n){var r=a.all(e.map(n,function(e){return t._validateConstraint(s,e)}));if(d.push(r),"rejected"===r.state())return!1}),a.all(d)}},_validateConstraint:function(t,i){var n=this,r=i.validate(t,this);return!1===r&&(r=e.Deferred().reject()),a.all([r]).fail(function(e){n.validationResult instanceof Array||(n.validationResult=[]),n.validationResult.push({assert:i,errorMessage:"string"==typeof e&&e})})},getValue:function(){var e;return e="function"==typeof this.options.value?this.options.value(this):"undefined"!=typeof this.options.value?this.options.value:this.$element.val(),"undefined"==typeof e||null===e?"":this._handleWhitespace(e)},reset:function(){return this._resetUI(),this._trigger("reset")},destroy:function(){this._destroyUI(),this.$element.removeData("Parsley"),this.$element.removeData("FieldMultiple"),this._trigger("destroy")},refresh:function(){return this._refreshConstraints(),this},_refreshConstraints:function(){return this.actualizeOptions()._bindConstraints()},refreshConstraints:function(){return a.warnOnce("Parsley's refreshConstraints is deprecated. Please use refresh"),this.refresh()},addConstraint:function(e,t,i,n){if(window.Parsley._validatorRegistry.validators[e]){var r=new F(this,e,t,i,n);"undefined"!==this.constraintsByName[r.name]&&this.removeConstraint(r.name),this.constraints.push(r),this.constraintsByName[r.name]=r}return this},removeConstraint:function(e){for(var t=0;t1){var i=[];return this.each(function(){i.push(e(this).parsley(t))}),i}if(0!=this.length)return new P(this[0],t)},"undefined"==typeof window.ParsleyExtend&&(window.ParsleyExtend={}),T.options=_extends(a.objectCreate(o),window.ParsleyConfig),window.ParsleyConfig=T.options,window.Parsley=window.psly=T,T.Utils=a,window.ParsleyUtils={},e.each(a,function(e,t){"function"==typeof t&&(window.ParsleyUtils[e]=function(){return a.warnOnce("Accessing `window.ParsleyUtils` is deprecated. Use `window.Parsley.Utils` instead."),a[e].apply(a,arguments)})});var O=window.Parsley._validatorRegistry=new p(window.ParsleyConfig.validators,window.ParsleyConfig.i18n);window.ParsleyValidator={},e.each("setLocale addCatalog addMessage addMessages getErrorMessage formatMessage addValidator updateValidator removeValidator hasValidator".split(" "),function(e,t){window.Parsley[t]=function(){return O[t].apply(O,arguments)},window.ParsleyValidator[t]=function(){var e;return a.warnOnce("Accessing the method '"+t+"' through Validator is deprecated. Simply call 'window.Parsley."+t+"(...)'"),(e=window.Parsley)[t].apply(e,arguments)}}),window.Parsley.UI=y,window.ParsleyUI={removeError:function(e,t,i){var n=!0!==i;return a.warnOnce("Accessing UI is deprecated. Call 'removeError' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e.removeError(t,{updateClass:n})},getErrorsMessages:function(e){return a.warnOnce("Accessing UI is deprecated. Call 'getErrorsMessages' on the instance directly."),e.getErrorsMessages()}},e.each("addError updateError".split(" "),function(e,t){window.ParsleyUI[t]=function(e,i,n,r,s){var o=!0!==s;return a.warnOnce("Accessing UI is deprecated. Call '"+t+"' on the instance directly. Please comment in issue 1073 as to your need to call this method."),e[t](i,{message:n,assert:r,updateClass:o})}}),!1!==window.ParsleyConfig.autoBind&&e(function(){e("[data-parsley-validate]").length&&e("[data-parsley-validate]").parsley()});var M=e({}),R=function(){a.warnOnce("Parsley's pubsub module is deprecated; use the 'on' and 'off' methods on parsley instances or window.Parsley")},D="parsley:";e.listen=function(e,n){var r;if(R(),"object"==typeof arguments[1]&&"function"==typeof arguments[2]&&(r=arguments[1],n=arguments[2]),"function"!=typeof n)throw new Error("Wrong parameters");window.Parsley.on(i(e),t(n,r))},e.listenTo=function(e,n,r){if(R(),!(e instanceof x||e instanceof w))throw new Error("Must give Parsley instance");if("string"!=typeof n||"function"!=typeof r)throw new Error("Wrong parameters");e.on(i(n),t(r))},e.unsubscribe=function(e,t){if(R(),"string"!=typeof e||"function"!=typeof t)throw new Error("Wrong arguments");window.Parsley.off(i(e),t.parsleyAdaptedCallback)},e.unsubscribeTo=function(e,t){if(R(),!(e instanceof x||e instanceof w))throw new Error("Must give Parsley instance");e.off(i(t))},e.unsubscribeAll=function(t){R(),window.Parsley.off(i(t)),e("form,input,textarea,select").each(function(){var n=e(this).data("Parsley");n&&n.off(i(t))})},e.emit=function(e,t){var n;R();var r=t instanceof x||t instanceof w,s=Array.prototype.slice.call(arguments,r?2:1);s.unshift(i(e)),r||(t=window.Parsley),(n=t).trigger.apply(n,_toConsumableArray(s))};e.extend(!0,T,{asyncValidators:{"default":{fn:function(e){return e.status>=200&&e.status<300},url:!1},reverse:{fn:function(e){return e.status<200||e.status>=300},url:!1}},addAsyncValidator:function(e,t,i,n){return T.asyncValidators[e]={fn:t,url:i||!1,options:n||{}},this}}),T.addValidator("remote",{requirementType:{"":"string",validator:"string",reverse:"boolean",options:"object"},validateString:function(t,i,n,r){var s,a,o={},l=n.validator||(!0===n.reverse?"reverse":"default");if("undefined"==typeof T.asyncValidators[l])throw new Error("Calling an undefined async validator: `"+l+"`");i=T.asyncValidators[l].url||i,i.indexOf("{value}")>-1?i=i.replace("{value}",encodeURIComponent(t)):o[r.element.getAttribute("name")||r.element.getAttribute("id")]=t;var u=e.extend(!0,n.options||{},T.asyncValidators[l].options);s=e.extend(!0,{},{url:i,data:o,type:"GET"},u),r.trigger("field:ajaxoptions",r,s),a=e.param(s),"undefined"==typeof T._remoteCache&&(T._remoteCache={});var d=T._remoteCache[a]=T._remoteCache[a]||e.ajax(s),h=function(){var t=T.asyncValidators[l].fn.call(r,d,i,n);return t||(t=e.Deferred().reject()),e.when(t)};return d.then(h,h)},priority:-1}),T.on("form:submit",function(){T._remoteCache={}}),l.prototype.addAsyncValidator=function(){return a.warnOnce("Accessing the method `addAsyncValidator` through an instance is deprecated. Simply call `Parsley.addAsyncValidator(...)`"),T.addAsyncValidator.apply(T,arguments)},T.addMessages("en",{defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",number:"This value should be a valid number.",integer:"This value should be a valid integer.",digits:"This value should be digits.",alphanum:"This value should be alphanumeric."},notblank:"This value should not be blank.",required:"This field is required.",pattern:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or fewer.",length:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or fewer.",check:"You must select between %s and %s choices.",equalto:"This value should be the same."}),T.setLocale("en");var I=new n;I.install();var q=T;return q}); -//# sourceMappingURL=parsley.min.js.map \ No newline at end of file diff --git a/content/js/pay-instruction.js b/content/js/pay-instruction.js deleted file mode 100644 index cb2ef67..0000000 --- a/content/js/pay-instruction.js +++ /dev/null @@ -1,2 +0,0 @@ -$(function() { -}); \ No newline at end of file diff --git a/content/js/templates.htm b/content/js/templates.htm deleted file mode 100644 index 7424f50..0000000 --- a/content/js/templates.htm +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/content/js/templates.js b/content/js/templates.js deleted file mode 100644 index c43e6da..0000000 --- a/content/js/templates.js +++ /dev/null @@ -1,41 +0,0 @@ -Templates = {}; - -$(function() { - $.ajax({ - url: "/js/templates.htm", - cache: true, - success: function(data) { - $("body").append(data); - - templatesLoaded(); - } - }); - - Templates.onLoaded = function() {}; - Templates.loaded = false; -}); - -function templatesLoaded() { - var $items = $("script[type='text/x-handlebars-template']"); - var index = 0; - - $items.each(function(){ - var $self = $(this); - var name = $self.attr("name"); - var src = $self.html(); - var partialName = $self.attr("partial-name"); - - if (partialName) { - Handlebars.registerPartial(partialName, src); - } - - Templates[name] = Handlebars.compile(src); - - index++; - - if (index === $items.length) { - Templates.loaded = true; - Templates.onLoaded(); - } - }); -} \ No newline at end of file diff --git a/content/scss/lib/_nprogress.scss b/content/scss/lib/_nprogress.scss new file mode 100644 index 0000000..7cea74f --- /dev/null +++ b/content/scss/lib/_nprogress.scss @@ -0,0 +1,76 @@ +$primary-color: #00b100; + +/* Make clicks pass-through */ +#nprogress { + pointer-events: none; + + .bar { + background: $primary-color; + + position: fixed; + z-index: 1031; + top: 0; + left: 0; + + width: 100%; + height: 2px; + } + + /* Fancy blur effect */ + .peg { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px $primary-color, 0 0 5px $primary-color; + opacity: 1.0; + + -webkit-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); + } + + /* Remove these to get rid of the spinner */ + .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 15px; + right: 15px; + } + + .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + + border: solid 2px transparent; + border-top-color: $primary-color; + border-left-color: $primary-color; + border-radius: 50%; + + -webkit-animation: nprogress-spinner 400ms linear infinite; + animation: nprogress-spinner 400ms linear infinite; + } +} + +.nprogress-custom-parent { + overflow: hidden; + position: relative; +} + +.nprogress-custom-parent #nprogress .spinner, +.nprogress-custom-parent #nprogress .bar { + position: absolute; +} + +@-webkit-keyframes nprogress-spinner { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} +@keyframes nprogress-spinner { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + \ No newline at end of file diff --git a/content/scss/main.scss b/content/scss/main.scss index f897d03..29a8c32 100644 --- a/content/scss/main.scss +++ b/content/scss/main.scss @@ -9,13 +9,18 @@ @import "partials/tables"; @import "partials/progress-bar"; @import "partials/utilities"; +@import "partials/splash"; @import "screens/api-calls"; -@import "screens/job-info"; -@import "screens/pay-run-info"; @import "screens/coming-soon"; +@import "screens/job-info"; @import "screens/keep-in-touch-days"; +@import "screens/pay-code-modal"; +@import "screens/pay-instruction-modal"; +@import "screens/pay-run-info"; +@import "screens/pension-modal"; @import "screens/setup"; +@import "lib/nprogress"; @import "lib/parsley"; @import "lib/resizeable"; \ No newline at end of file diff --git a/content/scss/partials/_buttons.scss b/content/scss/partials/_buttons.scss index 91dd26d..0b21553 100644 --- a/content/scss/partials/_buttons.scss +++ b/content/scss/partials/_buttons.scss @@ -27,4 +27,11 @@ a.btn-default { display: block; margin-bottom: 10px; } +} + +.status { + .btn-outline-secondary { + float: right; + margin-top: -2px; + } } \ No newline at end of file diff --git a/content/scss/partials/_modal.scss b/content/scss/partials/_modal.scss index 36a6aec..67d1ae9 100644 --- a/content/scss/partials/_modal.scss +++ b/content/scss/partials/_modal.scss @@ -1,3 +1,8 @@ -.bootbox-close-button { - display: none; +ux-dialog-overlay.active { + background-color: black; + opacity: 0.75 !important; +} + +ux-dialog { + min-width: 700px !important; } \ No newline at end of file diff --git a/content/scss/partials/_splash.scss b/content/scss/partials/_splash.scss new file mode 100644 index 0000000..56718b5 --- /dev/null +++ b/content/scss/partials/_splash.scss @@ -0,0 +1,6 @@ +.splash { + font-size: 100px; + position: absolute; + top: calc(50% - 50px); + left: calc(50% - 50px); +} \ No newline at end of file diff --git a/content/scss/screens/_api-calls.scss b/content/scss/screens/_api-calls.scss index b9b05a1..10b9550 100644 --- a/content/scss/screens/_api-calls.scss +++ b/content/scss/screens/_api-calls.scss @@ -1,5 +1,4 @@ .api-calls { - display: none; height: 300px; position: fixed; bottom: 0; diff --git a/content/scss/screens/_pay-code-modal.scss b/content/scss/screens/_pay-code-modal.scss new file mode 100644 index 0000000..9bb4822 --- /dev/null +++ b/content/scss/screens/_pay-code-modal.scss @@ -0,0 +1,3 @@ +.pension-modal-container { + width: 1000px; +} \ No newline at end of file diff --git a/content/scss/screens/_pay-instruction-modal.scss b/content/scss/screens/_pay-instruction-modal.scss new file mode 100644 index 0000000..fa59067 --- /dev/null +++ b/content/scss/screens/_pay-instruction-modal.scss @@ -0,0 +1,3 @@ +.pay-instruction-modal-container { + width: 1000px; +} \ No newline at end of file diff --git a/content/scss/screens/_pension-modal.scss b/content/scss/screens/_pension-modal.scss new file mode 100644 index 0000000..1a583f0 --- /dev/null +++ b/content/scss/screens/_pension-modal.scss @@ -0,0 +1,3 @@ +.pay-code-modal-container { + width: 1000px; +} \ No newline at end of file diff --git a/controllers/api-logger-controller.js b/controllers/api-logger-controller.js deleted file mode 100644 index c81bf49..0000000 --- a/controllers/api-logger-controller.js +++ /dev/null @@ -1,34 +0,0 @@ -const BaseController = require("./base-controller"); - -module.exports = class APILoggerController extends BaseController { - async getView(ctx) { - await ctx.render("api-logs", await this.getExtendedViewModel(ctx, { title: "API calls", HideAPICallsLink: true })); - } - - async getData(ctx) { - let data = ctx.session.apiCalls; - - if (!data) { - ctx.body = data; - return; - } - - let filteredData = data.filter(x => !x.uri.trim().toLowerCase().endsWith("/healthcheck")); - - let reversed = filteredData.reverse(); - - ctx.body = reversed; - } - - async postAPICallsOpenStatus(ctx) { - let body = ctx.request.body; - - ctx.session.openAPICalls = body.open === "true"; - } - - async postAPICallsPanelSize(ctx) { - let body = ctx.request.body; - - ctx.session.apiCallsHeight = body.size; - } -}; \ No newline at end of file diff --git a/controllers/base-controller.js b/controllers/base-controller.js deleted file mode 100644 index 49eb4f7..0000000 --- a/controllers/base-controller.js +++ /dev/null @@ -1,30 +0,0 @@ -const PackageJson = require("../package.json"); -const ApiWrapper = require("../services/api-wrapper"); - -const apiWrapper = new ApiWrapper(); - -module.exports = class BaseController { - async getExtendedViewModel(ctx, vm) { - if (!ctx.cookies.get("setupCookieKey")) { - return vm; - } - - let healthCheckResponse = await apiWrapper.get(ctx, "/Healthcheck"); - - let body = ctx.session.body || {}; - - if (!vm.errors) { - vm.errors = ctx.session.errors || []; - } - - vm.version = PackageJson.version; - vm.apiVersion = healthCheckResponse.HealthCheck.Version; - vm.openAPICalls = ctx.session.openAPICalls; - vm.apiCallsHeight = ctx.session.apiCallsHeight || 300; - - ctx.session.body = null; - ctx.session.errors = null; - - return Object.assign(body, vm); - } -}; \ No newline at end of file diff --git a/controllers/employee-controller.js b/controllers/employee-controller.js deleted file mode 100644 index ab52349..0000000 --- a/controllers/employee-controller.js +++ /dev/null @@ -1,200 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); -const EmployerService = require("../services/employer-service"); -const ValidationParser = require("../services/validation-parser"); -const EmployeeUtils = require("../services/employee-utils"); -const StatusUtils = require("../services/status-utils"); -const AppState = require("../app-state"); -const _ = require("lodash"); - -let apiWrapper = new ApiWrapper(); -let employerService = new EmployerService(); - -module.exports = class EmployeeController extends BaseController { - async requestNewEmployee(ctx) { - let employerId = ctx.params.employerId; - let paySchedules = await employerService.getPaySchedules(ctx, employerId); - - await ctx.render("employee", await this.getExtendedViewModel(ctx, { - title: "Add a new Employee", - EmployerId: employerId, - PaySchedules: paySchedules.PaySchedulesTable.PaySchedule, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: AppState.currentEmployer.Name, Url: `/employer/${employerId}` }, - { Name: "Add a new Employee" } - ] - })); - } - - async addNewEmployee(ctx) { - let employerId = ctx.params.employerId; - let body = EmployeeUtils.parse(ctx.request.body, employerId); - let response = await apiWrapper.post(ctx, `Employer/${employerId}/Employees`, { Employee: body }); - - if (ValidationParser.containsErrors(response)) { - let paySchedules = await employerService.getPaySchedules(ctx, employerId); - - await ctx.render("employee", await this.getExtendedViewModel(ctx, Object.assign(body, { - title: "Add a new Employee", - EmployerId: employerId, - PaySchedules: paySchedules.PaySchedulesTable.PaySchedule, - errors: ValidationParser.extractErrors(response), - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: AppState.currentEmployer.Name, Url: `/employer/${employerId}` }, - { Name: "Add a new Employee" } - ] - }))); - return; - } - - await ctx.redirect(response.Link["@href"] + "?status=Employee details saved&statusType=success"); - } - - async getEmployeeDetails(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let apiRoute = `/Employer/${employerId}/Employee/${employeeId}`; - let response = await apiWrapper.get(ctx, apiRoute); - let payInstructions = await apiWrapper.getAndExtractLinks(ctx, `/Employer/${employerId}/Employee/${employeeId}/PayInstructions`); - - let filteredPayInstructions = payInstructions.filter(pi => { - return pi.ObjectType !== "P45PayInstruction"; - }); - - let canAddANewPayInstruction = filteredPayInstructions.filter(pi => pi.EndDate).length === filteredPayInstructions.length; - let paySchedules = await employerService.getPaySchedules(ctx, employerId); - let employee = EmployeeUtils.parseFromApi(response.Employee); - - let body = Object.assign(employee, { - Id: employeeId, - title: employee.Code, - EmployerId: employerId, - PaySchedules: paySchedules.PaySchedulesTable.PaySchedule, - PayInstructions: filteredPayInstructions, - GroupedPayInstructions: this.getNormalGroupedPayInstructions(filteredPayInstructions), - GroupedYTDPayInstructions: this.getYTDGroupedPayInstructions(filteredPayInstructions), - CanAddANewPayInstruction: filteredPayInstructions.length === 0 || canAddANewPayInstruction, - P45PayInstruction: this.getP45PayInstruction(payInstructions), - ShowTabs: true, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: employee.Code } - ], - Status: StatusUtils.extract(ctx) - }); - - await ctx.render("employee", await this.getExtendedViewModel(ctx, body)); - } - - async saveEmployeeDetails(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let body = ctx.request.body; - let cleanBody = EmployeeUtils.parse(body, employerId); - let response = await apiWrapper.put(ctx, `/Employer/${employerId}/Employee/${employeeId}`, { Employee: cleanBody }); - - if (ValidationParser.containsErrors(response)) { - let paySchedules = await employerService.getPaySchedules(ctx, employerId); - - let extendedBody = Object.assign(body, { - Id: employeeId, - title: body.Code, - EmployerId: employerId, - PaySchedules: paySchedules.PaySchedulesTable.PaySchedule, - errors: ValidationParser.extractErrors(response), - ShowTabs: true, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: body.Code } - ] - }); - - await ctx.render("employee", await this.getExtendedViewModel(ctx, extendedBody)); - return; - } - - await ctx.redirect(`/Employer/${employerId}/Employee/${employeeId}?status=Employee details saved&statusType=success`); - } - - async request60(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let apiRoute = `/Employer/${employerId}/Employee/${employeeId}`; - let response = await apiWrapper.get(ctx, apiRoute); - - let body = { - title: "Download P60", - EmployeeId: employeeId, - EmployerId: employerId, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: response.Employee.Code, Url: `/employer/${employerId}/employee/${employeeId}` }, - { Name: "Download P60" } - ] - }; - - await ctx.render("download-p60", await this.getExtendedViewModel(ctx, body)); - } - - async downloadP60(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let body = ctx.request.body; - let year = body.Year; - let apiRoute = `/Report/P60/run?EmployerKey=${employerId}&EmployeeKey=${employeeId}&TaxYear=${year}&TransformDefinitionKey=P60-${year}-Pdf`; - - let response = await apiWrapper.getFile(ctx, apiRoute); - - ctx.set("Content-disposition", "attachment; filename=p60.pdf"); - ctx.set("Content-type", "application/pdf"); - ctx.body = response.body; - } - - getP45PayInstruction(instructions) { - let p45Instruction = instructions.find(pi => { - return pi.ObjectType === "P45PayInstruction"; - }); - - return p45Instruction; - } - - getNormalGroupedPayInstructions(instructions) { - let filtered = instructions.filter(i => i.ObjectType.toLowerCase().indexOf("ytd") === -1); - let grouped = this.getGroupedPayInstructions(filtered); - - return this.getProjectedPayInstructions(grouped); - } - - getYTDGroupedPayInstructions(instructions) { - let filtered = instructions.filter(i => i.ObjectType.toLowerCase().indexOf("ytd") !== -1); - let grouped = this.getGroupedPayInstructions(filtered); - - return this.getProjectedPayInstructions(grouped); - } - - getGroupedPayInstructions(instructions) { - let groupedPayInstructions = _.groupBy(instructions, (pi) => { - return pi.ObjectType; - }); - - return groupedPayInstructions; - } - - getProjectedPayInstructions(groupedPayInstructions) { - let projectedPayInstructions = Object.keys(groupedPayInstructions).map(key => { - let instructions = groupedPayInstructions[key]; - - return { - InstructionType: key, - Instructions: instructions - }; - }); - - return projectedPayInstructions; - } -}; \ No newline at end of file diff --git a/controllers/employer-controller.js b/controllers/employer-controller.js deleted file mode 100644 index caa7da4..0000000 --- a/controllers/employer-controller.js +++ /dev/null @@ -1,128 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); -const EmployerService = require("../services/employer-service"); -const ValidationParser = require("../services/validation-parser"); -const EmployerUtils = require("../services/employer-utils"); -const StatusUtils = require("../services/status-utils"); -const AppState = require("../app-state"); -const EmployerQuery = require("../queries/employer-query"); -const EmployerRevisionsQuery = require("../queries/employer-revisions-query"); - -let apiWrapper = new ApiWrapper(); -let employerService = new EmployerService(); - -module.exports = class EmployerController extends BaseController { - async getEmployers(ctx) { - let employers = await apiWrapper.query(ctx, EmployerQuery); - - await ctx.render("employers", await this.getExtendedViewModel(ctx, { - title: "Employers", - employers: employers - })); - } - - async requestNewEmployer(ctx) { - await ctx.render("employer", await this.getExtendedViewModel(ctx, { - title: "Add a new Employer", - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Add a new Employer" } - ] - })); - } - - async addNewEmployer(ctx) { - let body = EmployerUtils.parse(ctx.request.body); - let response = await apiWrapper.post(ctx, "Employers", { Employer: body }); - - if (ValidationParser.containsErrors(response)) { - await ctx.render("employer", await this.getExtendedViewModel(ctx, Object.assign(body, { - title: "Add a new Employer", - errors: ValidationParser.extractErrors(response), - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Add a new Employer" } - ] - }))); - return; - } - - await ctx.redirect(response.Link["@href"] + "?status=Employer details saved&statusType=success"); - } - - async getEmployerDetails(ctx) { - let id = ctx.params.id; - let response = await apiWrapper.get(ctx, `Employer/${id}`); - let employer = response.Employer; - let employees = await apiWrapper.getAndExtractLinks(ctx, `Employer/${id}/Employees`); - let pensions = await apiWrapper.getAndExtractLinks(ctx, `Employer/${id}/Pensions`); - let extendedPensions = pensions.map(pension => { - if (employer.AutoEnrolment && employer.AutoEnrolment.Pension) { - pension.UseForAutoEnrolment = employer.AutoEnrolment.Pension["@href"].endsWith(pension.Id); - } - else { - pension.UseForAutoEnrolment = false; - } - - return pension; - }); - let paySchedules = await employerService.getPaySchedules(ctx, id); - let rtiTransactions = await apiWrapper.getAndExtractLinks(ctx, `Employer/${id}/RtiTransactions`); - - let queryStr = JSON.stringify(EmployerRevisionsQuery).replace("$$EmployerKey$$", id); - let query = JSON.parse(queryStr); - let revisions = await apiWrapper.query(ctx, query); - - let payRunCount = 0; - - if (paySchedules.PaySchedulesTable.PaySchedule) { - paySchedules.PaySchedulesTable.PaySchedule.forEach(ps => { - if (ps.PayRuns) { - payRunCount = payRunCount + ps.PayRuns.length; - } - }); - } - - let body = Object.assign(employer, { - Id: id, - ShowTabs: true, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: employer.Name } - ], - Employees: employees, - Pensions: extendedPensions, - PaySchedules: paySchedules, - PayRuns: payRunCount > 0, - RTITransactions: rtiTransactions, - Revisions: revisions, - title: employer.Name, - Status: StatusUtils.extract(ctx) - }); - - // todo: refactor this into session. - AppState.currentEmployer = employer; - - await ctx.render("employer", await this.getExtendedViewModel(ctx, body)); - } - - async saveEmployerDetails(ctx) { - let id = ctx.params.id; - let body = EmployerUtils.parse(ctx.request.body); - let response = await apiWrapper.put(ctx, `Employer/${id}`, { Employer: body }); - - if (ValidationParser.containsErrors(response)) { - await ctx.render("employer", await this.getExtendedViewModel(ctx, Object.assign(body, { - Id: id, - errors: ValidationParser.extractErrors(response), - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: body.Name } - ] - }))); - return; - } - - await ctx.redirect(`/employer/${id}?status=Employer details saved&statusType=success`); - } -}; \ No newline at end of file diff --git a/controllers/job-controller.js b/controllers/job-controller.js deleted file mode 100644 index 7f91a0c..0000000 --- a/controllers/job-controller.js +++ /dev/null @@ -1,40 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); - -let apiWrapper = new ApiWrapper(); - -module.exports = class JobController extends BaseController { - async getJobDetails(ctx) { - let employerId = ctx.params.employerId; - let jobId = ctx.params.jobId; - let type = ctx.params.type.trim().toLowerCase(); - - let apiRoute = type === "payrun" ? `/Jobs/PayRuns/${jobId}/Info` : `/Jobs/RTI/${jobId}/Info`; - - let response = await apiWrapper.get(ctx, apiRoute); - - if (response.JobInfo) { - let body = response.JobInfo; - - if (ctx.headers["x-requested-with"] === "XMLHttpRequest") { - ctx.body = { - Progress: parseFloat(body.Progress) * 100, - Errors: body.Errors && body.Errors.Error.length > 0 ? body.Errors.Error : null - }; - } - else { - body.title = type === "payrun" ? "Pay Run Info" : "RTI Full Payment Submission"; - body.Breadcrumbs = [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: body.title } - ]; - - await ctx.render("job-details", await this.getExtendedViewModel(ctx, body)); - } - } - else { - await ctx.render("job-details", await this.getExtendedViewModel(ctx, {})); - } - } -}; \ No newline at end of file diff --git a/controllers/p45-instruction-controller.js b/controllers/p45-instruction-controller.js deleted file mode 100644 index e4f3d6d..0000000 --- a/controllers/p45-instruction-controller.js +++ /dev/null @@ -1,37 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); -const ValidationParser = require("../services/validation-parser"); -let apiWrapper = new ApiWrapper(); - -module.exports = class P45InstructionController extends BaseController { - async postNewInstruction(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let body = ctx.request.body; - let apiRoute = `Employer/${employerId}/Employee/${employeeId}/PayInstructions`; - - let response = await apiWrapper.post(ctx, apiRoute, { P45PayInstruction: body }); - - if (ValidationParser.containsErrors(response)) { - return; - } - - await ctx.redirect(`/employer/${employerId}/employee/${employeeId}?status=P45 instruction saved&statusType=success#p45-instruction`); - } - - async postExistingInstruction(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let id = ctx.params.id; - let body = ctx.request.body; - let apiRoute = `Employer/${employerId}/Employee/${employeeId}/PayInstruction/${id}`; - - let response = await apiWrapper.put(ctx, apiRoute, { P45PayInstruction: body }); - - if (ValidationParser.containsErrors(response)) { - return; - } - - await ctx.redirect(`/employer/${employerId}/employee/${employeeId}?status=P45 instruction saved&statusType=success#p45-instruction`); - } -}; \ No newline at end of file diff --git a/controllers/pay-instruction-controller.js b/controllers/pay-instruction-controller.js deleted file mode 100644 index c1db3f4..0000000 --- a/controllers/pay-instruction-controller.js +++ /dev/null @@ -1,199 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); -const ValidationParser = require("../services/validation-parser"); - -let apiWrapper = new ApiWrapper(); - -module.exports = class PayInstructionController extends BaseController { - async requestNewInstruction(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let instructionType = ctx.query.type || (ctx.session.body ? ctx.session.body.InstructionType : undefined); - - if (!instructionType) { - await ctx.redirect(`/employer/${employerId}/employee/${employeeId}#instructions`); - return; - } - - let body = { - title: "Pay instruction", - EmployeeId: employeeId, - EmployerId: employerId, - InstructionType: instructionType, - EnableForm: true, - MinStartDate: null, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: "Employee", Url: `/employer/${employerId}/employee/${employeeId}#instructions` }, - { Name: "Pay instruction" } - ], - layout: "modal" - }; - - if (ctx.query && ctx.query.type) { - body.InstructionType = ctx.query.type; - } - - let instructionTypeInstance = this.getInstructionInstance(instructionType); - let extendedViewModel = await this.getExtendedViewModel(ctx, body); - let instructionTypeExtendedViewModel = await instructionTypeInstance.extendViewModel(ctx, extendedViewModel); - - await ctx.render("pay-instruction", instructionTypeExtendedViewModel); - } - - async addNewInstruction(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstructions`; - let body = ctx.request.body; - let instructionType = body.InstructionType; - let cleanBody = this.getInstructionInstance(instructionType).parseForApi(body); - let request = {}; - - request[instructionType] = cleanBody; - - console.log(cleanBody); - - let response = await apiWrapper.post(ctx, apiRoute, request); - - if (ctx.headers["x-requested-with"] === "XMLHttpRequest") { - ctx.body = { - Errors: ValidationParser.extractErrors(response) - }; - return; - } - - if (ValidationParser.containsErrors(response)) { - ctx.session.body = body; - ctx.session.errors = ValidationParser.extractErrors(response); - - ctx.redirect("/payInstruction/new"); - return; - } - - await this.redirectWithStatus(ctx, employerId, employeeId, instructionType); - } - - async getInstruction(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let id = ctx.params.payInstructionId; - - let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstruction/${id}`; - - let response = await apiWrapper.get(ctx, apiRoute); - let instructionType = Object.keys(response)[0]; - - let body = Object.assign(response[instructionType], { - title: "Pay instruction", - Id: id, - EnableForm: true, - EmployeeId: employeeId, - EmployerId: employerId, - InstructionType: instructionType, - MinStartDate: null, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: "Employee", Url: `/employer/${employerId}/employee/${employeeId}#instructions` }, - { Name: "Pay instruction" } - ], - layout: "modal" - }); - - let instructionTypeInstance = this.getInstructionInstance(instructionType); - let extendedViewModel = await this.getExtendedViewModel(ctx, body); - let instructionTypeExtendedViewModel = await instructionTypeInstance.extendViewModel(ctx, extendedViewModel); - - await ctx.render("pay-instruction", instructionTypeExtendedViewModel); - } - - async saveInstruction(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let id = ctx.params.payInstructionId; - let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstruction/${id}`; - let body = ctx.request.body; - let instructionType = body.InstructionType; - let cleanBody = this.getInstructionInstance(instructionType).parseForApi(body); - let request = {}; - - request[instructionType] = cleanBody; - - let response = await apiWrapper.put(ctx, apiRoute, request); - - if (ctx.headers["x-requested-with"] === "XMLHttpRequest") { - ctx.body = { - Errors: ValidationParser.extractErrors(response) - }; - return; - } - - if (ValidationParser.containsErrors(response)) { - ctx.session.body = body; - ctx.session.errors = ValidationParser.extractErrors(response); - - ctx.redirect(apiRoute); - return; - } - - await this.redirectWithStatus(ctx, employerId, employeeId, instructionType); - } - - async deleteInstruction(ctx) { - let employerId = ctx.params.employerId; - let employeeId = ctx.params.employeeId; - let payInstructionId = ctx.params.payInstructionId; - - let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstruction/${payInstructionId}`; - - let response = await apiWrapper.delete(ctx, apiRoute); - - if (ValidationParser.containsErrors(response)) { - ctx.body = { - errors: ValidationParser.extractErrors(response) - }; - } - else { - ctx.body = {}; - } - } - - async redirectWithStatus(ctx, employerId, employeeId, instructionType) { - let employeeRoute = `/employer/${employerId}/employee/${employeeId}`; - let hash = instructionType.toLowerCase().indexOf("ytd") !== -1 ? "#year-to-date-instructions" : "#instructions"; - - await ctx.redirect(`${employeeRoute}?status=Pay instruction saved&statusType=success${hash}`); - } - - async canInstructionBeAdded({ employerId, employeeId, type }) { - let instruction = this.getInstructionInstance(type); - - return instruction.canNewInstructionBeAdded(employerId, employeeId); - } - - async getMinStartDateForNewInstruction({ ctx, employerId, employeeId, payInstructionId, type }) { - let instruction = this.getInstructionInstance(type); - - return instruction.getMinStartDateForNewInstruction({ - ctx: ctx, - employerId: employerId, - employeeId: employeeId, - payInstructionId: payInstructionId - }); - } - - getInstructionInstance(type) { - let Instruction; - - if (type.toLowerCase().indexOf("ytd") !== -1) { - Instruction = require(`../services/payInstructions/yearToDate/${type}`); - } - else { - Instruction = require(`../services/payInstructions/${type}`); - } - - return new Instruction(); - } -}; \ No newline at end of file diff --git a/controllers/pay-run-controller.js b/controllers/pay-run-controller.js deleted file mode 100644 index 4f63a51..0000000 --- a/controllers/pay-run-controller.js +++ /dev/null @@ -1,188 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); -const ValidationParser = require("../services/validation-parser"); -const EmployerService = require("../services/employer-service"); -const PayRunUtils = require("../services/pay-run-utils"); -const PayRunG2NQuery = require("../queries/payrun-g2n-query"); -const NextPayRunDatesQuery = require("../queries/next-payrun-dates-query"); - -let apiWrapper = new ApiWrapper(); -let employerService = new EmployerService(); - -module.exports = class PayRunController extends BaseController { - async getPayRunInfo(ctx) { - let employerId = ctx.params.employerId; - let payScheduleId = ctx.params.payScheduleId; - let payRunId = ctx.params.payRunId; - - let payRunRoute = `/Employer/${employerId}/PaySchedule/${payScheduleId}/PayRun/${payRunId}`; - - let queryStr = JSON.stringify(PayRunG2NQuery) - .replace("$$EmployerKey$$", employerId) - .replace("$$PayScheduleKey$$", payScheduleId) - .replace("$$PayRunKey$$", payRunId); - - let query = JSON.parse(queryStr); - let queryResult = await apiWrapper.query(ctx, query); - let employees = queryResult.PayrunG2N.PaySchedule.PayRun.Employees; - - let commentaries = await apiWrapper.get(ctx, payRunRoute + "/Commentaries"); - - let mappedEmployees = []; - - if (employees) { - mappedEmployees = employees.map(employee => { - if (commentaries && commentaries.LinkCollection.Links) { - let commentaryLink = commentaries.LinkCollection.Links.Link.find(commentary => { - return commentary["@href"].split("/")[4] === employee.Key; - }); - - employee.Commentary = commentaryLink; - } - - return employee; - }); - } - - let body = Object.assign(queryResult.PayrunG2N.PaySchedule.PayRun, { - title: "Pay Run", - Employees: mappedEmployees, - EmployerId: employerId, - PaySchedule: queryResult.PayrunG2N.PaySchedule, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: "Pay Run" } - ] - }); - - await ctx.render("pay-run", await this.getExtendedViewModel(ctx, body)); - } - - async requestNewRun(ctx) { - let employerId = ctx.params.employerId; - let payScheduleId = ctx.query.paySchedule; - let paySchedules = await employerService.getPaySchedules(ctx, employerId); - - let nextPaymentDate; - let nextPeriodStart; - let nextPeriodEnd; - - // query next PayRun dates - if (payScheduleId) { - let queryStr = JSON.stringify(NextPayRunDatesQuery) - .replace("$$EmployerKey$$", employerId) - .replace("$$PayScheduleKey$$", payScheduleId); - - let query = JSON.parse(queryStr); - let queryResult = await apiWrapper.query(ctx, query); - - nextPaymentDate = queryResult.NextPayRunDates.NextPayDay; - nextPeriodStart = queryResult.NextPayRunDates.NextPeriodStart; - nextPeriodEnd = queryResult.NextPayRunDates.NextPeriodEnd; - } - - let message = ""; - - let body = await this.getExtendedViewModel(ctx, { - Status: message, - EmployerId: employerId, - PayScheduleId: payScheduleId, - PaySchedules: paySchedules.PaySchedulesTable.PaySchedule, - PaymentDate: nextPaymentDate, - StartDate: nextPeriodStart, - EndDate: nextPeriodEnd - }); - - let model = Object.assign(body, { layout: "modal" }); - await ctx.render("pay-run-creation", model); - } - - async requestReRun(ctx) { - let employerId = ctx.params.employerId; - let payScheduleId = ctx.query.paySchedule; - let payRunId = ctx.query.payRunId; - - let nextPaymentDate; - let nextPeriodStart; - let nextPeriodEnd; - - // query next rerun dates - if (payRunId) { - let result = await apiWrapper.get(ctx, `Employer/${employerId}/PaySchedule/${payScheduleId}/PayRun/${payRunId}`); - - nextPaymentDate = result.PayRun.PaymentDate; - nextPeriodStart = result.PayRun.PeriodStart; - nextPeriodEnd = result.PayRun.PeriodEnd; - } - - let body = await this.getExtendedViewModel(ctx, { - Status: "Re-running will delete the previous run.", - EmployerId: employerId, - PayScheduleId: payScheduleId, - PaymentDate: nextPaymentDate, - StartDate: nextPeriodStart, - EndDate: nextPeriodEnd - }); - - let model = Object.assign(body, { layout: "modal" }); - await ctx.render("pay-run-creation", model); - } - - async startNewRun(ctx) { - let employerId = ctx.params.employerId; - let body = ctx.request.body; - let cleanBody = PayRunUtils.parse(body, employerId); - - let response = await apiWrapper.post(ctx, "jobs/payruns", { PayRunJobInstruction: cleanBody }); - - if (ValidationParser.containsErrors(response)) { - let paySchedules = await employerService.getPaySchedules(ctx, employerId); - - let extendedBody = await this.getExtendedViewModel(ctx, Object.assign(body, { - title: "Start a pay run", - EmployerId: employerId, - PaySchedules: paySchedules.PaySchedulesTable.PaySchedule, - errors: ValidationParser.extractErrors(response), - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: "Start a pay run" } - ] - })); - - await ctx.render("pay-run-creation", extendedBody); - return; - } - - let jobId = response.Link["@href"].split("/")[3]; - let route = `/employer/${employerId}?jobId=${jobId}#runs`; - - await ctx.redirect(route); - } - - async deletePayRun(ctx) { - let employerId = ctx.params.employerId; - let payScheduleId = ctx.params.payScheduleId; - let payRunId = ctx.params.payRunId; - - let apiRoute = `/Employer/${employerId}/PaySchedule/${payScheduleId}/PayRun/${payRunId}`; - - await apiWrapper.delete(ctx, apiRoute); - - // todo: handle error from API - - let route = `/employer/${employerId}#runs`; - await ctx.redirect(route); - } - - /*async rerunPayRun(ctx) { - let employerId = ctx.params.employerId; - let scheduleId = ctx.params.payScheduleId; - let payRunId = ctx.params.payRunId; - - // todo: enqueue re-run job - - return true; - }*/ -}; \ No newline at end of file diff --git a/controllers/pay-schedule-controller.js b/controllers/pay-schedule-controller.js deleted file mode 100644 index 3518365..0000000 --- a/controllers/pay-schedule-controller.js +++ /dev/null @@ -1,106 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); -const ValidationParser = require("../services/validation-parser"); -const AppState = require("../app-state"); - -const apiWrapper = new ApiWrapper(); - -module.exports = class PayScheduleController extends BaseController { - async requestNewSchedule(ctx) { - let employerId = ctx.params.employerId; - - let body = await this.getExtendedViewModel(ctx, { - title: "Add a new Pay Schedule", - EmployerId: employerId - }); - - let model = Object.assign(body, { layout: "modal" }); - await ctx.render("pay-schedule", model); - } - - async addNewSchedule(ctx) { - let body = ctx.request.body; - let apiRoute = `Employer/${ctx.params.employerId}/paySchedules`; - let response = await apiWrapper.post(ctx, apiRoute, { PaySchedule: body }); - - let employerRoute = `/employer/${ctx.params.employerId}`; - - if (ValidationParser.containsErrors(response)) { - let model = await this.getExtendedViewModel(ctx, Object.assign(body, { - title: "Add a new Pay Schedule", - EmployerId: ctx.params.employerId, - errors: ValidationParser.extractErrors(response) - })); - - await ctx.render("pay-schedule", model); - - return; - } - - await ctx.redirect(employerRoute + "?status=Pay schedule saved&statusType=success#schedules"); - } - - async getScheduleDetails(ctx) { - let employerId = ctx.params.employerId; - let payScheduleId = ctx.params.payScheduleId; - let apiRoute = `/Employer/${employerId}/PaySchedule/${payScheduleId}`; - let response = await apiWrapper.get(ctx, apiRoute); - - let body = Object.assign(response.PaySchedule, { - Id: payScheduleId, - EmployerId: employerId, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: AppState.currentEmployer.Name, Url: `/employer/${employerId}` }, - { Name: response.PaySchedule.Name } - ], - title: response.PaySchedule.Name - }); - - await ctx.render("pay-schedule", await this.getExtendedViewModel(ctx, body)); - } - - async saveScheduleDetails(ctx) { - let employerId = ctx.params.employerId; - let payScheduleId = ctx.params.payScheduleId; - let body = ctx.request.body; - let apiRoute = `Employer/${employerId}/paySchedule/${payScheduleId}`; - let response = await apiWrapper.put(ctx, apiRoute, { PaySchedule: body }); - - let employerRoute = `/employer/${employerId}`; - - if (ValidationParser.containsErrors(response)) { - await ctx.render("pay-schedule", await this.getExtendedViewModel(ctx, Object.assign(body, { - title: body.Name, - EmployerId: employerId, - errors: ValidationParser.extractErrors(response), - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: AppState.currentEmployer.Name, Url: employerRoute }, - { Name: body.Name } - ] - }))); - return; - } - - await ctx.redirect(employerRoute + "?status=Pay schedule saved&statusType=success#schedules"); - } - - async deleteSchedule(ctx) { - let employerId = ctx.params.employerId; - let payScheduleId = ctx.params.payScheduleId; - - let apiRoute = `/Employer/${employerId}/PaySchedule/${payScheduleId}`; - - let response = await apiWrapper.delete(ctx, apiRoute); - - if (ValidationParser.containsErrors(response)) { - ctx.body = { - errors: ValidationParser.extractErrors(response) - }; - } - else { - ctx.body = {}; - } - } -}; \ No newline at end of file diff --git a/controllers/pension-controller.js b/controllers/pension-controller.js deleted file mode 100644 index 678af47..0000000 --- a/controllers/pension-controller.js +++ /dev/null @@ -1,113 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); -const ValidationParser = require("../services/validation-parser"); -const PensionUtils = require("../services/pension-utils"); - -let apiWrapper = new ApiWrapper(); - -module.exports = class PensionController extends BaseController { - async getNewPension(ctx) { - let employerId = ctx.params.employerId; - - await ctx.render("pension", await this.getExtendedViewModel(ctx, { - title: "Add a new Pension", - EmployerId: employerId, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: "Add a new Pension" } - ] - })); - } - - async postNewPension(ctx) { - let employerId = ctx.params.employerId; - let body = ctx.request.body; - let parsedBody = PensionUtils.parse(body); - let response = await apiWrapper.post(ctx, `Employer/${employerId}/Pensions`, { Pension: parsedBody }); - - if (ValidationParser.containsErrors(response)) { - ctx.session.body = body; - ctx.session.errors = ValidationParser.extractErrors(response); - - ctx.redirect(`/employer/${employerId}/pension`); - return; - } - - await ctx.redirect(`/employer/${employerId}?status=Pension added&statusType=success#pensions`); - } - - async getExistingPension(ctx) { - let employerId = ctx.params.employerId; - let pensionId = ctx.params.id; - let apiRoute = `/Employer/${employerId}/Pension/${pensionId}`; - let response = await apiWrapper.get(ctx, apiRoute); - let pension = response.Pension; - - let body = Object.assign(pension, { - Id: pensionId, - title: pensionId, - EmployerId: employerId, - Breadcrumbs: [ - { Name: "Employers", Url: "/employer" }, - { Name: "Employer", Url: `/employer/${employerId}` }, - { Name: pensionId } - ] - }); - - await ctx.render("pension", await this.getExtendedViewModel(ctx, body)); - } - - async postExistingPension(ctx) { - let id = ctx.params.id; - let employerId = ctx.params.employerId; - let body = ctx.request.body; - let parsedBody = PensionUtils.parse(body); - let response = await apiWrapper.put(ctx, `Employer/${employerId}/Pension/${id}`, { Pension: parsedBody }); - - if (ValidationParser.containsErrors(response)) { - ctx.session.body = body; - ctx.session.errors = ValidationParser.extractErrors(response); - - ctx.redirect(`/employer/${employerId}/pension/${id}`); - return; - } - - await ctx.redirect(`/employer/${employerId}?status=Pension updated&statusType=success#pensions`); - } - - async postDeletePension(ctx) { - let employerId = ctx.params.employerId; - let id = ctx.params.id; - - let apiRoute = `/Employer/${employerId}/Pension/${id}`; - - let response = await apiWrapper.delete(ctx, apiRoute); - - if (ValidationParser.containsErrors(response)) { - ctx.body = { - errors: ValidationParser.extractErrors(response) - }; - } - else { - ctx.body = {}; - } - } - - async postAEDefault(ctx) { - let id = ctx.params.id; - let employerId = ctx.params.employerId; - - await apiWrapper.patch(ctx, `/Employer/${employerId}`, { - Employer: { - AutoEnrolment: { - Pension: { - "@href": `/Employer/${employerId}/Pension/${id}` - } - } - } - }); - - return true; - } -}; \ No newline at end of file diff --git a/controllers/root-controller.js b/controllers/root-controller.js deleted file mode 100644 index 1750cad..0000000 --- a/controllers/root-controller.js +++ /dev/null @@ -1,14 +0,0 @@ -const BaseController = require("./base-controller"); -const SetupController = require("./setup-controller"); - -module.exports = class RootController extends BaseController { - async getRootView(ctx) { - let cookie = ctx.cookies.get(SetupController.cookieKey); - let hasBeenSetup = cookie !== undefined && cookie !== null; - - await ctx.render("index", await this.getExtendedViewModel(ctx, { - title: "Get started", - hasBeenSetup: hasBeenSetup - })); - } -}; \ No newline at end of file diff --git a/controllers/rti-controller.js b/controllers/rti-controller.js deleted file mode 100644 index def3c71..0000000 --- a/controllers/rti-controller.js +++ /dev/null @@ -1,96 +0,0 @@ -const BaseController = require("./base-controller"); -const ApiWrapper = require("../services/api-wrapper"); -const ValidationParser = require("../services/validation-parser"); -const PayRunsQuery = require("../queries/payruns-query"); -const moment = require("moment"); - -let apiWrapper = new ApiWrapper(); - -module.exports = class RtiController extends BaseController { - - async getNewRtiInstruction(ctx) { - let employerId = ctx.params.employerId; - - let queryStr = JSON.stringify(PayRunsQuery).replace("$$EmployerKey$$", employerId); - - let query = JSON.parse(queryStr); - - let paymentDates = await apiWrapper.query(ctx, query); - - let body = { - Status: "", - EmployerId: employerId, - PayRuns: paymentDates.PayRunsQuery.PayRuns, - layout: "modal" - }; - - let extendedBody = await this.getExtendedViewModel(ctx, body); - - return ctx.render("rti-instruction", extendedBody); - } - - async postNewRtiInstruction(ctx) { - let employerId = ctx.params.employerId; - let formValues = ctx.request.body; - - let apiRoute = `/Employer/${employerId}/${formValues.PayRun}`; - let payRun = await apiWrapper.get(ctx, apiRoute); - - let fpsBody = { - RtiType: "FPS", - Generate: true, - Transmit: true, - Employer: { - "@href": `/Employer/${employerId}` - }, - PaySchedule: payRun.PayRun.PaySchedule, - TaxYear: payRun.PayRun.TaxYear, - TaxMonth: payRun.PayRun.TaxPeriod, - PaymentDate: payRun.PayRun.PaymentDate, - Timestamp: moment().format("YYYY-MM-DDTHH:mm:ss"), - HoldingDate: null, - LateReason: null - }; - - let response = await apiWrapper.post(ctx, "/Jobs/rti", { RtiJobInstruction: fpsBody }); - - if (ValidationParser.containsErrors(response)) { - ctx.session.body = formValues; - - let queryStr = JSON.stringify(PayRunsQuery) - .replace("$$EmployerKey$$", employerId); - - let query = JSON.parse(queryStr); - let paymentDates = await apiWrapper.query(ctx, query); - - let body = { - Status: "", - EmployerId: employerId, - PayRuns: paymentDates.PayRunsQuery.PayRuns, - //layout: "modal" - }; - - await ctx.render("rti-instruction", await this.getExtendedViewModel(ctx, Object.assign(body, { - errors: ValidationParser.extractErrors(response) - }))); - - return; - } - - let jobId = response.Link["@href"].split("/")[3]; - let route = `/employer/${employerId}/job/${jobId}/rti`; - - await ctx.redirect(route); - } - - async getTransactionResults(ctx) { - let employerId = ctx.params.employerId; - let rtiTransactionId = ctx.params.rtiTransactionId; - - let apiRoute = `/Employer/${employerId}/RtiTransaction/${rtiTransactionId}`; - let response = await apiWrapper.get(ctx, apiRoute); - - ctx.type = "text/plain; charset=utf-8"; - ctx.body = JSON.stringify(response.RtiFpsTransaction, null, 4); - } -}; \ No newline at end of file diff --git a/docs/PayInstructions.md b/docs/PayInstructions.md deleted file mode 100644 index e69de29..0000000 diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..5b60c1b --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,46 @@ +const gulp = require("gulp"); +const sass = require("gulp-sass"); +const nodemon = require("gulp-nodemon"); +const start = require("gulp-start-process"); +const eslint = require("gulp-eslint"); + +gulp.task("lint", () => { + let src = ["**/*.js"]; + + return gulp.src(src) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +}); + +gulp.task("sass", function() { + return gulp.src("content/scss/main.scss") + .pipe(sass()) + .pipe(gulp.dest("content/css/")); +}); + +gulp.task("server", () => { + return nodemon({ + script: "app.js", + watch: [ + "app.js", + "api/**/*.js" + ] + }); +}); + +gulp.task("au-run", (cb) => { + start("au run", {}, cb); +}); + +gulp.task("au-build", (cb) => { + start("au build", {}, cb); +}); + +gulp.task("watch-sass", () => { + gulp.watch("content/scss/**/*.scss", gulp.series("sass")); +}); + +gulp.task("build", gulp.parallel("sass", "au-build")); + +gulp.task("default", gulp.parallel("server", "sass", "watch-sass", "au-run")); \ No newline at end of file diff --git a/helpers/address.js b/helpers/address.js deleted file mode 100644 index b4a7e6e..0000000 --- a/helpers/address.js +++ /dev/null @@ -1,18 +0,0 @@ -const Handlebars = require("handlebars"); - -module.exports = (address) => { - if (address) { - let parts = [ - address.Address1, - address.Address2, - address.Address3, - address.Address4, - address.Country, - address.Postcode - ].filter(part => part !== null && part !== undefined && part.trim().length > 0); - - return new Handlebars.SafeString(parts.join("
      ")); - } - - return ""; -}; \ No newline at end of file diff --git a/helpers/bankAccount.js b/helpers/bankAccount.js deleted file mode 100644 index cf82a0c..0000000 --- a/helpers/bankAccount.js +++ /dev/null @@ -1,15 +0,0 @@ -const Handlebars = require("handlebars"); - -module.exports = (account) => { - if (account) { - let parts = [ - account.AccountName, - account.AccountNumber, - account.SortCode - ].filter(part => part !== null && part !== undefined && part.trim().length > 0); - - return new Handlebars.SafeString(parts.join("
      ")); - } - - return ""; -}; \ No newline at end of file diff --git a/helpers/canAddPayRun.js b/helpers/canAddPayRun.js deleted file mode 100644 index d784938..0000000 --- a/helpers/canAddPayRun.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = (context, options) => { - if (context.Employees.length > 0 - && context.PaySchedules.PaySchedulesTable.PaySchedule - && context.PaySchedules.PaySchedulesTable.PaySchedule.length > 0) { - return options.fn(context); - } - - return options.inverse(context); -}; \ No newline at end of file diff --git a/helpers/checkedIf.js b/helpers/checkedIf.js deleted file mode 100644 index d926497..0000000 --- a/helpers/checkedIf.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (condition) => { - return condition === true || (condition && condition.toString().toLowerCase() === "true") ? "checked" : ""; -}; \ No newline at end of file diff --git a/helpers/defaultCountry.js b/helpers/defaultCountry.js deleted file mode 100644 index 609ca2e..0000000 --- a/helpers/defaultCountry.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (country) => { - return country || "United Kingdom"; -}; \ No newline at end of file diff --git a/helpers/defaultHours.js b/helpers/defaultHours.js deleted file mode 100644 index 15e4bb9..0000000 --- a/helpers/defaultHours.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (hoursPerWeek) => { - return hoursPerWeek || 40; -}; \ No newline at end of file diff --git a/helpers/employeeName.js b/helpers/employeeName.js deleted file mode 100644 index 485a175..0000000 --- a/helpers/employeeName.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = (employee) => { - let firstname = employee.FirstName || employee.Initials; - - let parts = [ - employee.Title, - firstname, - employee.MiddleName, - employee.LastName - ].filter(part => part !== undefined && part !== null && part.trim().length > 0); - - return parts.join(" "); -}; \ No newline at end of file diff --git a/helpers/extractHref.js b/helpers/extractHref.js deleted file mode 100644 index eae195c..0000000 --- a/helpers/extractHref.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (obj) => { - return obj["@href"]; -}; \ No newline at end of file diff --git a/helpers/extractIdFromLink.js b/helpers/extractIdFromLink.js deleted file mode 100644 index d4aaf62..0000000 --- a/helpers/extractIdFromLink.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = (obj) => { - let href = obj["@href"]; - let parts = href.split("/"); - - return parts[parts.length - 1]; -}; \ No newline at end of file diff --git a/helpers/fixedDecimal.js b/helpers/fixedDecimal.js deleted file mode 100644 index 2231095..0000000 --- a/helpers/fixedDecimal.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = (input, noOfDecimalPoints) => { - if (input) { - return parseFloat(input).toFixed(noOfDecimalPoints); - } - - return ""; -}; \ No newline at end of file diff --git a/helpers/formatDate.js b/helpers/formatDate.js deleted file mode 100644 index 2ea5436..0000000 --- a/helpers/formatDate.js +++ /dev/null @@ -1,11 +0,0 @@ -const moment = require("moment"); - -module.exports = (date) => { - if (date) { - let parsedDate = moment(date); - - return parsedDate.format("YYYY-MM-DD"); - } - - return ""; -}; \ No newline at end of file diff --git a/helpers/formatSalary.js b/helpers/formatSalary.js deleted file mode 100644 index 1ab7526..0000000 --- a/helpers/formatSalary.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = (salary) => { - if (salary) { - return parseFloat(salary).toFixed(2); - } - - return ""; -}; \ No newline at end of file diff --git a/helpers/ifCond.js b/helpers/ifCond.js deleted file mode 100644 index 10f8bb2..0000000 --- a/helpers/ifCond.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = (v1, v2, context, options) => { - if (v1 === v2) { - return options.fn(context); - } - - return options.inverse(context); -}; \ No newline at end of file diff --git a/helpers/invertedVisibleIf.js b/helpers/invertedVisibleIf.js deleted file mode 100644 index 954d374..0000000 --- a/helpers/invertedVisibleIf.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (condition) => { - return condition? "display-none" : "display-block"; -}; \ No newline at end of file diff --git a/helpers/listOfPayInstructionsToAdd.js b/helpers/listOfPayInstructionsToAdd.js deleted file mode 100644 index edeaa52..0000000 --- a/helpers/listOfPayInstructionsToAdd.js +++ /dev/null @@ -1,36 +0,0 @@ -const path = require("path"); -const fs = require("fs"); -const Handlebars = require("handlebars"); - -module.exports = (ctx, ytd) => { - const excludedFiles = [ - "AbsencePayInstruction.js", - "BaseInstruction.js", - "BaseYtdPayInstruction.js", - "BaseAbsenceYtdPayInstruction.js", - "yearToDate" - ]; - - let folder = path.join(__dirname, "..", "services", "payInstructions"); - - if (ytd) { - folder = path.join(folder, "yearToDate"); - } - - let cssClass = "dropdown-item launch-modal"; - - let html = fs.readdirSync(folder).map(file => { - if (excludedFiles.includes(file)) { - return ""; - } - - let pi = require(path.join(folder, file)); - let instance = new pi(); - let name = instance.name; - let type = file.replace(".js", ""); - - return `${name}`; - }).join(""); - - return new Handlebars.SafeString(html); -}; \ No newline at end of file diff --git a/helpers/longDateTime.js b/helpers/longDateTime.js deleted file mode 100644 index 1fe9da2..0000000 --- a/helpers/longDateTime.js +++ /dev/null @@ -1,11 +0,0 @@ -const moment = require("moment"); - -module.exports = (date) => { - if (date) { - let parsedDate = moment(date); - - return parsedDate.format("YYYY-MM-DD HH:mm:ss"); - } - - return ""; -}; \ No newline at end of file diff --git a/helpers/minStartDate.js b/helpers/minStartDate.js deleted file mode 100644 index 6131e33..0000000 --- a/helpers/minStartDate.js +++ /dev/null @@ -1,12 +0,0 @@ -const Handlebars = require("handlebars"); -const moment = require("moment"); - -module.exports = (minStartDate) => { - if (minStartDate) { - let date = moment(minStartDate); - - return new Handlebars.SafeString(`min="${date.format("YYYY-MM-DD")}"`); - } - - return ""; -}; \ No newline at end of file diff --git a/helpers/multipleSelect.js b/helpers/multipleSelect.js deleted file mode 100644 index be8f2d2..0000000 --- a/helpers/multipleSelect.js +++ /dev/null @@ -1,17 +0,0 @@ -const $ = require("cheerio"); - -module.exports = (value, options) => { - let $el = $("").html(options.fn(this)); - - $el.find(`[value="${value}"]`).attr({ - "selected": "selected" - }); - - return $el.html(); -}; \ No newline at end of file diff --git a/helpers/selectedIf.js b/helpers/selectedIf.js deleted file mode 100644 index bfaa2e5..0000000 --- a/helpers/selectedIf.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (condition) => { - return condition === true || (condition && condition.toString().toLowerCase() === "true") ? "selected" : ""; -}; \ No newline at end of file diff --git a/helpers/taxYears.js b/helpers/taxYears.js deleted file mode 100644 index c020b5f..0000000 --- a/helpers/taxYears.js +++ /dev/null @@ -1,24 +0,0 @@ -const Handlebars = require("handlebars"); -const moment = require("moment"); - -module.exports = () => { - let startYear = moment().month() < 3 ? moment().year() - 1: moment().year(); - let years = []; - - for (let i = 0; i < 2; i++) { - let year = startYear - i; - - years.push({ - value: year - 1, - text: `${year - 1} / ${year}` - }); - } - - let html = ""; - - for (let year of years) { - html += ``; - } - - return new Handlebars.SafeString(html); -}; \ No newline at end of file diff --git a/helpers/visibleIf.js b/helpers/visibleIf.js deleted file mode 100644 index ed68225..0000000 --- a/helpers/visibleIf.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (condition) => { - return condition? "display-block" : "display-none"; -}; \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..90fbfaf --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "experimentalDecorators": true + } +} \ No newline at end of file diff --git a/package.json b/package.json index 41d3b49..378a847 100644 --- a/package.json +++ b/package.json @@ -7,14 +7,6 @@ "node": ">=9.6" }, "engineStrict": true, - "scripts": { - "build-css": "./bin/build-css", - "lint": "./node_modules/.bin/eslint ./", - "test": "./node_modules/.bin/jasmine-node spec", - "watch": "concurrently --kill-others \"npm run watch-css\" \"npm run watch-hbs\"", - "watch-css": "./bin/watch-css", - "watch-hbs": "./bin/watch-hbs" - }, "repository": { "type": "git", "url": "git+https://github.com/X-API/PayRunIO.Demo.UI.git" @@ -27,33 +19,61 @@ "homepage": "https://github.com/X-API/PayRunIO.Demo.UI#readme", "dependencies": { "array-flatten": "^2.1.1", + "aurelia-dialog": "^2.0.0-rc.3", + "aurelia-http-client": "^1.3.0", + "aurelia-validation": "^1.2.2", "cheerio": "^1.0.0-rc.2", - "colors": "^1.2.1", - "concurrently": "^3.5.1", - "crypto": "^1.0.1", - "jasmine-node": "^1.14.5", + "gulp-sass": "^4.0.1", "koa": "^2.5.0", "koa-bodyparser": "^4.2.0", - "koa-compress": "^2.0.0", "koa-hbs-renderer": "^1.2.0", "koa-helmet": "^3.3.0", - "koa-redis": "^3.1.2", + "koa-mount": "^3.0.0", "koa-router": "^7.4.0", "koa-session": "^5.8.1", "koa-session-memory": "^1.0.2", "koa-static": "^4.0.2", "lodash": "^4.17.10", "minimist": "^1.2.0", - "moment": "^2.22.0", - "node-sass": "^4.7.2", - "nodemon": "^1.17.2", + "moment": "^2.22.2", + "nprogress": "^0.2.0", "oauth-1.0a": "^2.2.4", "raven": "^2.5.0", "request": "^2.85.0", "request-debug": "^0.2.0", - "request-promise": "^4.2.2" + "request-promise": "^4.2.2", + "requirejs": "^2.3.6" }, "devDependencies": { - "eslint": "^5.2.0" + "aurelia-bootstrapper": "^2.3.0", + "aurelia-cli": "^0.34.0", + "aurelia-testing": "^1.0.0-beta.4.0.0", + "aurelia-tools": "^2.0.0", + "babel-eslint": "^8.2.2", + "babel-plugin-syntax-flow": "^6.18.0", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", + "babel-plugin-transform-flow-strip-types": "^6.22.0", + "babel-polyfill": "^6.26.0", + "babel-preset-es2015": "^6.24.1", + "babel-preset-stage-1": "^6.24.1", + "babel-register": "^6.26.0", + "connect-history-api-fallback": "^1.5.0", + "debounce": "^1.1.0", + "eslint": "^5.2.0", + "gulp": "^4.0.0", + "gulp-babel": "^7.0.1", + "gulp-changed-in-place": "^2.3.0", + "gulp-eslint": "^4.0.2", + "gulp-nodemon": "^2.2.1", + "gulp-notify": "^3.2.0", + "gulp-plumber": "^1.2.0", + "gulp-rename": "^1.2.2", + "gulp-sourcemaps": "^2.6.4", + "gulp-start-process": "^1.1.1", + "gulp-watch": "^5.0.0", + "minimatch": "^3.0.4", + "text": "github:requirejs/text#latest" } } diff --git a/routes.js b/routes.js deleted file mode 100644 index 4766a9a..0000000 --- a/routes.js +++ /dev/null @@ -1,114 +0,0 @@ -const router = require("koa-router")(); -const RootController = require("./controllers/root-controller"); -const EmployerController = require("./controllers/employer-controller"); -const EmployeeController = require("./controllers/employee-controller"); -const PayScheduleController = require("./controllers/pay-schedule-controller"); -const PayInstructionController = require("./controllers/pay-instruction-controller"); -const PayRunController = require("./controllers/pay-run-controller"); -const CommentaryController = require("./controllers/commentary-controller"); -const PaySlipController = require("./controllers/pay-slip-controller"); -const JobController = require("./controllers/job-controller"); -const RTIController = require("./controllers/rti-controller"); -const APILoggerController = require("./controllers/api-logger-controller"); -const PensionController = require("./controllers/pension-controller"); -const P45InstructionController = require("./controllers/p45-instruction-controller"); -const SetupController = require("./controllers/setup-controller"); - -let rootController = new RootController(); -let employerController = new EmployerController(); -let employeeController = new EmployeeController(); -let payScheduleController = new PayScheduleController(); -let payInstructionController = new PayInstructionController(); -let payRunController = new PayRunController(); -let commentaryController = new CommentaryController(); -let paySlipController = new PaySlipController(); -let jobController = new JobController(); -let rtiController = new RTIController(); -let apiLoggerController = new APILoggerController(); -let pensionController = new PensionController(); -let p45InstructionController = new P45InstructionController(); -let setupController = new SetupController(); - -router - // root/get started - .get("/", async ctx => await rootController.getRootView(ctx)) - - // api calls - .get("/api-calls", async ctx => await apiLoggerController.getView(ctx)) - .get("/api-calls/data", async ctx => await apiLoggerController.getData(ctx)) - .post("/api-calls/is-open", async ctx => await apiLoggerController.postAPICallsOpenStatus(ctx)) - .post("/api-calls/size", async ctx => await apiLoggerController.postAPICallsPanelSize(ctx)) - - // employer - .get("/employer", async ctx => await employerController.getEmployers(ctx)) - .post("/employer", async ctx => await employerController.addNewEmployer(ctx)) - .get("/employer/new", async ctx => await employerController.requestNewEmployer(ctx)) - .get("/employer/:id", async ctx => await employerController.getEmployerDetails(ctx)) - .post("/employer/:id", async ctx => await employerController.saveEmployerDetails(ctx)) - //.post("/employer/:id/delete", async ctx => { }) - - // pay schedule - .get("/employer/:employerId/paySchedule/new", async ctx => await payScheduleController.requestNewSchedule(ctx)) - .post("/employer/:employerId/paySchedule", async ctx => await payScheduleController.addNewSchedule(ctx)) - .get("/employer/:employerId/paySchedule/:payScheduleId", async ctx => await payScheduleController.getScheduleDetails(ctx)) - .post("/employer/:employerId/paySchedule/:payScheduleId", async ctx => await payScheduleController.saveScheduleDetails(ctx)) - .post("/employer/:employerId/paySchedule/:payScheduleId/delete", async ctx => await payScheduleController.deleteSchedule(ctx)) - - // employee - .get("/employer/:employerId/employee/new", async ctx => await employeeController.requestNewEmployee(ctx)) - .post("/employer/:employerId/employee", async ctx => await employeeController.addNewEmployee(ctx)) - .get("/employer/:employerId/employee/:employeeId", async ctx => await employeeController.getEmployeeDetails(ctx)) - .post("/employer/:employerId/employee/:employeeId", async ctx => await employeeController.saveEmployeeDetails(ctx)) - //.get("/employer/:employerId/employee/:employeeId/leaver-details", async ctx => { }) - //.get("/employer/:employerId/employee/:employeeId/p45", async ctx => { }) - .get("/employer/:employerId/employee/:employeeId/p60", async ctx => await employeeController.request60(ctx)) - .post("/employer/:employerId/employee/:employeeId/p60", async ctx => await employeeController.downloadP60(ctx)) - //.post("/employer/:employerId/employee/:employeeId/delete", async ctx => { }) - - // pay instruction - .get("/employer/:employerId/employee/:employeeId/payInstruction/new", async ctx => await payInstructionController.requestNewInstruction(ctx)) - .post("/employer/:employerId/employee/:employeeId/payInstruction", async ctx => payInstructionController.addNewInstruction(ctx)) - .get("/employer/:employerId/employee/:employeeId/payInstruction/:payInstructionId", async ctx => payInstructionController.getInstruction(ctx)) - .post("/employer/:employerId/employee/:employeeId/payInstruction/:payInstructionId", async ctx => payInstructionController.saveInstruction(ctx)) - .post("/employer/:employerId/employee/:employeeId/payInstruction/:payInstructionId/delete", async ctx => payInstructionController.deleteInstruction(ctx)) - - // pay run - .get("/employer/:employerId/payRun", async ctx => await payRunController.requestNewRun(ctx)) - .get("/employer/:employerId/reRun", async ctx => await payRunController.requestReRun(ctx)) - .post("/employer/:employerId/payRun", async ctx => await payRunController.startNewRun(ctx)) - .get("/employer/:employerId/paySchedule/:payScheduleId/payRun/:payRunId", async ctx => await payRunController.getPayRunInfo(ctx)) - .post("/employer/:employerId/paySchedule/:payScheduleId/payRun/:payRunId/delete", async ctx => await payRunController.deletePayRun(ctx)) - .post("/employer/:employerId/paySchedule/:payScheduleId/payRun/:payRunId/rerun", async ctx => await payRunController.rerunPayRun(ctx)) - - // comentary - .get("/employer/:employerId/employee/:employeeId/commentary/:commentaryId", async ctx => await commentaryController.getCommentary(ctx)) - - // pay slip - .get("/employer/:employerId/employee/:employeeId/paySlipData/:code/:taxPeriod/:taxYear", async ctx => await paySlipController.getPaySlipData(ctx)) - - // rti transaction - .get("/employer/:employerId/rtiTransaction", async ctx => await rtiController.getNewRtiInstruction(ctx)) - .post("/employer/:employerId/rtiTransaction", async ctx => await rtiController.postNewRtiInstruction(ctx)) - .get("/employer/:employerId/rtiTransaction/:rtiTransactionId", async ctx => await rtiController.getTransactionResults(ctx)) - - // job - .get("/employer/:employerId/job/:jobId/:type", async ctx => await jobController.getJobDetails(ctx)) - - // pension - .get("/employer/:employerId/pension", async ctx => await pensionController.getNewPension(ctx)) - .post("/employer/:employerId/pension", async ctx => await pensionController.postNewPension(ctx)) - .get("/employer/:employerId/pension/:id", async ctx => await pensionController.getExistingPension(ctx)) - .post("/employer/:employerId/pension/:id", async ctx => await pensionController.postExistingPension(ctx)) - .post("/employer/:employerId/pension/:id/delete", async ctx => await pensionController.postDeletePension(ctx)) - .post("/employer/:employerId/pension/:id/ae-default", async ctx => await pensionController.postAEDefault(ctx)) - - // p45 pay instruction - .post("/employer/:employerId/Employee/:employeeId/P45Instruction", async ctx => await p45InstructionController.postNewInstruction(ctx)) - .post("/employer/:employerId/Employee/:employeeId/P45Instruction/:id", async ctx => await p45InstructionController.postExistingInstruction(ctx)) - - // setup - .get("/setup", async ctx => await setupController.get(ctx)) - .post("/setup", async ctx => await setupController.post(ctx)) -; - -module.exports = router.routes(); \ No newline at end of file diff --git a/services/employer-service.js b/services/employer-service.js deleted file mode 100644 index 8c508ca..0000000 --- a/services/employer-service.js +++ /dev/null @@ -1,28 +0,0 @@ -const ApiWrapper = require("./api-wrapper"); -const Flatten = require("array-flatten"); -const PaySchedulesQuery = require("../queries/pay-schedules-query"); - -const apiWrapper = new ApiWrapper(); - -module.exports = class EmployerService { - async getPaySchedules(ctx, employerId) { - let queryStr = JSON.stringify(PaySchedulesQuery).replace("$$EmployerKey$$", employerId); - let query = JSON.parse(queryStr); - return await apiWrapper.query(ctx, query); - } - - async getPayRuns(ctx, employerId, schedules) { - let items = await Promise.all(schedules.PaySchedulesTable.PaySchedule.map(async schedule => { - let runs = await apiWrapper.getAndExtractLinks(ctx, `Employer/${employerId}/PaySchedule/${schedule.Key}/PayRuns`); - - return runs.map(run => { - return Object.assign(run, { - ScheduleId: schedule.Key, - ScheduleName: schedule.Name - }); - }); - })); - - return Flatten(items); - } -}; \ No newline at end of file diff --git a/services/pay-instruction-utils.js b/services/pay-instruction-utils.js deleted file mode 100644 index 5ec3659..0000000 --- a/services/pay-instruction-utils.js +++ /dev/null @@ -1,2 +0,0 @@ -module.exports = class PayInstructionUtils { -}; \ No newline at end of file diff --git a/services/payInstructions/AbsencePayInstruction.js b/services/payInstructions/AbsencePayInstruction.js deleted file mode 100644 index fa4e63f..0000000 --- a/services/payInstructions/AbsencePayInstruction.js +++ /dev/null @@ -1,20 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class AbsencePayInstruction extends BaseInstruction { - get canInstructionsOverlap() { - return true; - } - - parseForApi(body) { - let cleanBody = super.parseForApi(body); - - if (cleanBody.StatutoryOffset && cleanBody.StatutoryOffset.toLowerCase() === "on") { - cleanBody.StatutoryOffset = true; - } - else { - cleanBody.StatutoryOffset = false; - } - - return cleanBody; - } -}; \ No newline at end of file diff --git a/services/payInstructions/AoePayInstruction.js b/services/payInstructions/AoePayInstruction.js deleted file mode 100644 index 00bfc8d..0000000 --- a/services/payInstructions/AoePayInstruction.js +++ /dev/null @@ -1,24 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class AoePayInstruction extends BaseInstruction { - get name() { - return "Attachment of Earnings"; - } - - get canInstructionsOverlap() { - return true; - } - - parseForApi(body) { - let cleanBody = super.parseForApi(body); - - if (cleanBody.ClaimAdminFee && cleanBody.ClaimAdminFee.toLowerCase() === "on") { - cleanBody.ClaimAdminFee = true; - } - else { - cleanBody.ClaimAdminFee = false; - } - - return cleanBody; - } -}; \ No newline at end of file diff --git a/services/payInstructions/BaseInstruction.js b/services/payInstructions/BaseInstruction.js deleted file mode 100644 index 4d55528..0000000 --- a/services/payInstructions/BaseInstruction.js +++ /dev/null @@ -1,82 +0,0 @@ -const ApiWrapper = require("../api-wrapper"); -const moment = require("moment"); -const PayInstructionType = require("../../models/PayInstructionType"); - -let apiWrapper = new ApiWrapper(); - -module.exports = class BaseInstruction { - get type() { - return PayInstructionType.normal; - } - - get name() { - throw Error("get name() needs implementing against each instruction"); - } - - get canInstructionsOverlap() { - // This property has to be implemented for each new instruction. - return true; - } - - async extendViewModel(ctx, vm) { - // override this to extend the passed in view model with instruction type specific properties. - return vm; - } - - parseForApi(body) { - let copy = JSON.parse(JSON.stringify(body)); - - // clear out utility properties as otherwise the api will return an error as they are unexpected. - copy.MinStartDate = null; - copy.InstructionType = null; - copy.EmployerId = null; - - // reorder properties so we always have the StartDate, EndDate and Description at the beginning of the - // list, as required by the api. - return Object.assign({ - StartDate: copy.StartDate, - EndDate: copy.EndDate, - Description: copy.Description - }, copy); - } - - async canNewInstructionBeAdded(employerId, employeeId) { - if (this.canInstructionsOverlap) { - return true; - } - - let payInstructions = await this.getInstructions(employerId, employeeId); - - return !payInstructions.includes(pi => !pi.EndDate); - } - - async getMinStartDateForNewInstruction({ ctx, employerId, employeeId, payInstructionId }) { - if (this.canInstructionsOverlap) { - return null; - } - - let payInstructions = await this.getInstructions(ctx, employerId, employeeId); - let filteredPayInstructions = payInstructions.filter(pi => pi.EndDate && pi.Id !== payInstructionId); - - if (filteredPayInstructions.length === 0) { - return null; - } - - let orderedPayInstructions = filteredPayInstructions.sort((a, b) => new Date(b.EndDate) - new Date(a.EndDate)); - let endDate = moment(orderedPayInstructions[0].EndDate); - - return endDate.add(1, "day").format("YYYY-MM-DD"); - } - - async getInstructions(ctx, employerId, employeeId) { - let apiRoute = `/Employer/${employerId}/Employee/${employeeId}/PayInstructions`; - let instructionType = this.constructor.name; - let links = await apiWrapper.getLinks(ctx, apiRoute); - - let filteredLinks = links.filter(link => { - return link["@rel"] === instructionType; - }); - - return await apiWrapper.extractLinks(filteredLinks); - } -}; \ No newline at end of file diff --git a/services/payInstructions/BenefitPayInstruction.js b/services/payInstructions/BenefitPayInstruction.js deleted file mode 100644 index 8754415..0000000 --- a/services/payInstructions/BenefitPayInstruction.js +++ /dev/null @@ -1,7 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class BenefitPayInstruction extends BaseInstruction { - get name() { - return "Benefit"; - } -}; \ No newline at end of file diff --git a/services/payInstructions/NiAdjustmentPayInstruction.js b/services/payInstructions/NiAdjustmentPayInstruction.js deleted file mode 100644 index 228a94a..0000000 --- a/services/payInstructions/NiAdjustmentPayInstruction.js +++ /dev/null @@ -1,7 +0,0 @@ -const NiPayInstruction = require("./NiPayInstruction"); - -module.exports = class NiAdjustmentPayInstruction extends NiPayInstruction { - get name() { - return "NI Adjustment"; - } -}; \ No newline at end of file diff --git a/services/payInstructions/NiPayInstruction.js b/services/payInstructions/NiPayInstruction.js deleted file mode 100644 index b022602..0000000 --- a/services/payInstructions/NiPayInstruction.js +++ /dev/null @@ -1,11 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class NiPayInstruction extends BaseInstruction { - get name() { - return "National Insurance"; - } - - get canInstructionsOverlap() { - return true; - } -}; \ No newline at end of file diff --git a/services/payInstructions/PensionPayInstruction.js b/services/payInstructions/PensionPayInstruction.js deleted file mode 100644 index e3069f4..0000000 --- a/services/payInstructions/PensionPayInstruction.js +++ /dev/null @@ -1,40 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); -const ApiWrapper = require("../../services/api-wrapper"); - -let apiWrapper = new ApiWrapper(); - -module.exports = class PensionPayInstruction extends BaseInstruction { - get name() { - return "Pension"; - } - - get canInstructionsOverlap() { - return true; - } - - async extendViewModel(ctx, vm) { - let extendedViewModel = await super.extendViewModel(ctx, vm); - let pensions = await apiWrapper.getAndExtractLinks(ctx, `Employer/${vm.EmployerId}/Pensions`); - - extendedViewModel.Pensions = pensions.map(pension => { - return { - Id: pension.Id, - Name: `${pension.ProviderName} - ${pension.SchemeName}` - }; - }); - - return extendedViewModel; - } - - parseForApi(body) { - let employerId = body.EmployerId; - let cleanBody = super.parseForApi(body); - - cleanBody.SalarySacrifice = (cleanBody.SalarySacrifice !== undefined && cleanBody.SalarySacrifice !== null && cleanBody.SalarySacrifice.toLowerCase() === "on"); - cleanBody.Pension = { - "@href": `/Employer/${employerId}/Pension/${body.Pension}` - }; - - return cleanBody; - } -}; \ No newline at end of file diff --git a/services/payInstructions/PrimitivePayInstruction.js b/services/payInstructions/PrimitivePayInstruction.js deleted file mode 100644 index a2de205..0000000 --- a/services/payInstructions/PrimitivePayInstruction.js +++ /dev/null @@ -1,11 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class PrimitivePayInstruction extends BaseInstruction { - get name() { - return "Primitive"; - } - - get canInstructionsOverlap() { - return true; - } -}; \ No newline at end of file diff --git a/services/payInstructions/RatePayInstruction.js b/services/payInstructions/RatePayInstruction.js deleted file mode 100644 index b682293..0000000 --- a/services/payInstructions/RatePayInstruction.js +++ /dev/null @@ -1,11 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class RatePayInstruction extends BaseInstruction { - get name() { - return "Rate"; - } - - get canInstructionsOverlap() { - return true; - } -}; \ No newline at end of file diff --git a/services/payInstructions/SalaryPayInstruction.js b/services/payInstructions/SalaryPayInstruction.js deleted file mode 100644 index b3a9398..0000000 --- a/services/payInstructions/SalaryPayInstruction.js +++ /dev/null @@ -1,11 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class SalaryPayInstruction extends BaseInstruction { - get name() { - return "Salary"; - } - - get canInstructionsOverlap() { - return false; - } -}; \ No newline at end of file diff --git a/services/payInstructions/ShppPayInstruction.js b/services/payInstructions/ShppPayInstruction.js deleted file mode 100644 index b319c1b..0000000 --- a/services/payInstructions/ShppPayInstruction.js +++ /dev/null @@ -1,7 +0,0 @@ -const AbsencePayInstruction = require("./AbsencePayInstruction"); - -module.exports = class ShppPayInstruction extends AbsencePayInstruction { - get name() { - return "Shared Parental Leave"; - } -}; \ No newline at end of file diff --git a/services/payInstructions/SmpPayInstruction.js b/services/payInstructions/SmpPayInstruction.js deleted file mode 100644 index cdcd526..0000000 --- a/services/payInstructions/SmpPayInstruction.js +++ /dev/null @@ -1,36 +0,0 @@ -const AbsencePayInstruction = require("./AbsencePayInstruction"); - -module.exports = class SmpPayInstruction extends AbsencePayInstruction { - get name() { - return "Statutory Maternity Pay"; - } - - parseForApi(body) { - let cleanBody = super.parseForApi(body); - - if (cleanBody.PayAsLumpSum && cleanBody.PayAsLumpSum.toLowerCase() === "on") { - cleanBody.PayAsLumpSum = true; - } - else { - cleanBody.PayAsLumpSum = false; - } - - if (cleanBody.PayPartWeek && cleanBody.PayPartWeek.toLowerCase() === "on") { - cleanBody.PayPartWeek = true; - } - else { - cleanBody.PayPartWeek = false; - } - - if (cleanBody.Stillbirth && cleanBody.Stillbirth.toLowerCase() === "on") { - cleanBody.Stillbirth = true; - } - else { - cleanBody.Stillbirth = false; - } - - // todo: parse KeepInTouchDays. - - return cleanBody; - } -}; \ No newline at end of file diff --git a/services/payInstructions/StudentLoanPayInstruction.js b/services/payInstructions/StudentLoanPayInstruction.js deleted file mode 100644 index d98c2c1..0000000 --- a/services/payInstructions/StudentLoanPayInstruction.js +++ /dev/null @@ -1,11 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class StudentLoanPayInstruction extends BaseInstruction { - get name() { - return "Student Loan"; - } - - get canInstructionsOverlap() { - return true; - } -}; \ No newline at end of file diff --git a/services/payInstructions/TaxPayInstruction.js b/services/payInstructions/TaxPayInstruction.js deleted file mode 100644 index 63e666c..0000000 --- a/services/payInstructions/TaxPayInstruction.js +++ /dev/null @@ -1,11 +0,0 @@ -const BaseInstruction = require("./BaseInstruction"); - -module.exports = class TaxPayInstruction extends BaseInstruction { - get name() { - return "Tax"; - } - - get canInstructionsOverlap() { - return false; - } -}; \ No newline at end of file diff --git a/src/.eslintrc.json b/src/.eslintrc.json new file mode 100644 index 0000000..56387cb --- /dev/null +++ b/src/.eslintrc.json @@ -0,0 +1,12 @@ +{ + "env": { + "browser": true + }, + "globals": { + "$": true, + "window": true, + "document": true, + "navigator": true, + "NProgress": true + } +} \ No newline at end of file diff --git a/src/api-calls/api-calls.html b/src/api-calls/api-calls.html new file mode 100644 index 0000000..f9a12d5 --- /dev/null +++ b/src/api-calls/api-calls.html @@ -0,0 +1,94 @@ + \ No newline at end of file diff --git a/src/api-calls/api-calls.js b/src/api-calls/api-calls.js new file mode 100644 index 0000000..d0fa4cb --- /dev/null +++ b/src/api-calls/api-calls.js @@ -0,0 +1,89 @@ +import { inject, customElement } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { HttpClient } from "aurelia-http-client"; + +@customElement("api-calls") +@inject(EventAggregator) +export class APICalls { + constructor(EventAggregator) { + this.ea = EventAggregator; + this.visible = false; + this.calls = []; + this.client = new HttpClient(); + } + + attached() { + this.toggleAPICallsSubscriber = this.ea.subscribe("toggleAPICalls", () => { + this.visible = !this.visible; + }); + + this.loadCalls(); + } + + loadCalls() { + this.client.get("/api/api-calls").then(res => { + let response = res.response; + + if (response === "") { + return; + } + + let calls = JSON.parse(response); + + if (this.calls.length !== calls.length) { + this.calls = calls; + } + + window.setTimeout(() => { + this.loadCalls(); + }, 1500); + }); + } + + showCallDetails(call) { + this.selectedCall = call; + + $(".api-calls-container").animate({ scrollTop: 0 }, 500); + } + + copyTextToClipboard(e) { + let $btn = $(e.target); + let $code = $btn.parent().find("code"); + let text = $code.text(); + + if (!navigator.clipboard) { + this.fallbackCopyTextToClipboard(text); + return; + } + + navigator.clipboard.writeText(text).then(() => { }, () => { + this.fallbackCopyTextToClipboard(text); + }); + } + + fallbackCopyTextToClipboard(text) { + let textarea = document.createElement("textarea"); + + textarea.textContent = text; + document.body.appendChild(textarea); + + let selection = document.getSelection(); + let range = document.createRange(); + + range.selectNode(textarea); + selection.removeAllRanges(); + selection.addRange(range); + + selection.removeAllRanges(); + + document.body.removeChild(textarea); + } + + detached() { + this.toggleAPICallsSubscriber.dispose(); + } + + close() { + this.visible = false; + } +} \ No newline at end of file diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..32b69d0 --- /dev/null +++ b/src/app.html @@ -0,0 +1,28 @@ + \ No newline at end of file diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..d6143b1 --- /dev/null +++ b/src/app.js @@ -0,0 +1,100 @@ +import { inject } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { DialogService } from "aurelia-dialog"; +import { JobDetailsModal } from "job/job-details-modal"; +import { PLATFORM } from "aurelia-pal"; +import { HttpClient } from "aurelia-http-client"; +import { Redirect } from "aurelia-router"; + +@inject(EventAggregator, DialogService) +export class App { + constructor(eventAggregator, dialogService) { + this.ea = eventAggregator; + this.dialogService = dialogService; + } + + activate() { + this.ea.subscribe("app:view-job", job => { + let opts = { + viewModel: JobDetailsModal, + model: job + }; + + this.dialogService.open(opts); + }); + } + + configureRouter(config, router) { + config.title = "PayRun.io Demo"; + + config.map([ + { + name: "get-started", + route: "", + moduleId: PLATFORM.moduleName("welcome/welcome"), + title: "Get started", + auth: false, + includeInBreadcrumbs: true + }, + { + name: "setup", + route: "setup", + moduleId: PLATFORM.moduleName("welcome/setup"), + title: "Setup", + auth: false, + previousInstruction: "get-started" + }, + { + name: "employers", + route: "employers", + moduleId: PLATFORM.moduleName("employer/list"), + title: "Employers", + auth: true, + includeInBreadcrumbs: true, + previousInstruction: "get-started" + }, + { + name: "employer", + route: "employer/:id?", + moduleId: PLATFORM.moduleName("employer/employer"), + title: "Employer", + auth: true, + includeInBreadcrumbs: true, + previousInstruction: "employers" + }, + { + name: "employee", + route: "employer/:employerId/employee/:employeeId?", + moduleId: PLATFORM.moduleName("employee/employee"), + title: "Employee", + auth: true, + includeInBreadcrumbs: true, + previousInstruction: "employer" + } + ]); + + config.addPipelineStep("authorize", AuthorizeStep); + + this.router = router; + } +} + +class AuthorizeStep { + run(navigationInstruction, next) { + return new Promise(resolve => { + let client = new HttpClient(); + + client.get("/api/has-been-setup").then(res => { + let parsedResponse = JSON.parse(res.response); + let currentRoute = navigationInstruction.config; + let loginRequired = currentRoute.auth && currentRoute.auth === true; + + if (!parsedResponse.hasBeenSetup && loginRequired) { + return resolve(next.cancel(new Redirect("setup"))); + } + + return resolve(next()); + }); + }); + } +} diff --git a/src/base-view-model.js b/src/base-view-model.js new file mode 100644 index 0000000..f6f3ab8 --- /dev/null +++ b/src/base-view-model.js @@ -0,0 +1,13 @@ +export class BaseViewModel { + constructor(router) { + this.router = router; + } + + setTitle(title) { + this.router.currentInstruction.config.title = title; + } + + setParams(params) { + this.router.currentInstruction.config.params = params; + } +} \ No newline at end of file diff --git a/src/dialogs/confirm.html b/src/dialogs/confirm.html new file mode 100644 index 0000000..9cc1ecd --- /dev/null +++ b/src/dialogs/confirm.html @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/src/dialogs/confirm.js b/src/dialogs/confirm.js new file mode 100644 index 0000000..3f0e09e --- /dev/null +++ b/src/dialogs/confirm.js @@ -0,0 +1,21 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; + +@inject(DialogController) +export class Confirm { + constructor(dialogController) { + this.dialogController = dialogController; + } + + activate(state) { + this.state = state; + } + + yes() { + this.dialogController.ok(); + } + + no() { + this.dialogController.cancel(); + } +} \ No newline at end of file diff --git a/views/partials/employeeForm.hbs b/src/employee/elements/employee-form.html similarity index 54% rename from views/partials/employeeForm.hbs rename to src/employee/elements/employee-form.html index 0e2d6d1..7000a0c 100644 --- a/views/partials/employeeForm.hbs +++ b/src/employee/elements/employee-form.html @@ -1,9 +1,19 @@ -{{#if Id}} -
      -{{else}} - -{{/if}} - + \ No newline at end of file diff --git a/src/employee/elements/employee-form.js b/src/employee/elements/employee-form.js new file mode 100644 index 0000000..0138006 --- /dev/null +++ b/src/employee/elements/employee-form.js @@ -0,0 +1,160 @@ +import { bindable, inject, customElement } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { HttpClient } from "aurelia-http-client"; +import { ValidationControllerFactory, ValidationRules } from "aurelia-validation"; +import { DialogService } from "aurelia-dialog"; +import { Confirm } from "../../dialogs/confirm"; + +@customElement("employee-form") +@inject(EventAggregator, ValidationControllerFactory, DialogService) +export class EmployeeForm { + constructor(EventAggregator, controllerFactory, dialogService) { + this.ea = EventAggregator; + this.paySchedules = null; + this.client = new HttpClient(); + this.validationController = controllerFactory.createForCurrentScope(); + this.dialogService = dialogService; + this.showSaveButton = true; + } + + @bindable employee = null; + + attached() { + this.setupTabEvents(); + this.setupValidationRules(); + } + + detached() { + } + + save() { + this.validationController.validate().then(result => { + if (result.valid) { + let url = `/api/employer/${this.employee.EmployerId}/employee`; + let data = this.employee; + + this.ea.publish("request:processing"); + + this.client.post(url, data).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.employee.Id = parsedResponse.employeeId; + + this.ea.publish("employee:reload", { + employerId: this.employee.EmployerId, + employeeId: parsedResponse.employeeId + }); + }); + } + else { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + }); + } + + employeeChanged() { + if (!this.employee.HoursPerWeek) { + this.employee.HoursPerWeek = 40; + } + + if (!this.employee.EmployeePartner) { + this.employee.EmployeePartner = { + Title: "", + FirstName: "", + Initials: "", + MiddleName: "", + LastName: "", + NiNumber: "" + }; + } + + if (!this.paySchedules) { + let employerId = this.employee.EmployerId; + + this.ea.publish("request:processing"); + + this.client.get(`/api/employer/${employerId}/pay-schedules`).then(res => { + this.ea.publish("request:complete"); + + this.paySchedules = JSON.parse(res.response); + }); + } + } + + setupTabEvents() { + $("a[data-toggle='tab']").on("shown.bs.tab", (e) => { + this.showSaveButton = e.target.id !== "revisions-tab"; + }); + } + + setupValidationRules() { + ValidationRules + .ensure("LastName").required().withMessage("Last name is required") + .ensure("Code").required().withMessage("Code is required") + .ensure("EffectiveDate").required().withMessage("Effective date is required") + .ensure("DateOfBirth").required().withMessage("Date of birth is required") + .ensure("Gender").required().withMessage("Gender is required") + .ensure("StarterDeclaration").required().withMessage("Starter declaration is required") + .ensure("Territory").required().withMessage("Territory is required") + .ensure("Region").required().withMessage("Region is required") + .ensure("HoursPerWeek").required().withMessage("Hours per week is required") + .ensure("AEAssessmentOverride").required().withMessage("AEAssessment override is required") + .on(this.employee); + } + + deleteRevision(revision) { + let opts = { + viewModel: Confirm, + model: { + title: "Are you sure?", + message: "Are you sure you want to delete this revision?" + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + let employerId = this.employee.EmployerId; + let employeeId = this.employee.Id; + let effectiveDate = revision.EffectiveDate; + let url = `/api/employer/${employerId}/employee/${employeeId}/revision/${effectiveDate}`; + + this.ea.publish("request:processing"); + + this.client.delete(url).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.employer.Revisions = this.employee.Revisions.filter(rev => rev.Revision !== revision.Revision); + + this.ea.publish("employee:reload", { + employerId: employerId, + employeeId: employeeId + }); + }); + } + }); + } +} \ No newline at end of file diff --git a/src/employee/elements/p45-pay-instruction.html b/src/employee/elements/p45-pay-instruction.html new file mode 100644 index 0000000..c3cc1d3 --- /dev/null +++ b/src/employee/elements/p45-pay-instruction.html @@ -0,0 +1,192 @@ + \ No newline at end of file diff --git a/src/employee/elements/p45-pay-instruction.js b/src/employee/elements/p45-pay-instruction.js new file mode 100644 index 0000000..1f5101f --- /dev/null +++ b/src/employee/elements/p45-pay-instruction.js @@ -0,0 +1,127 @@ +import { bindable, inject, customElement } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { DialogService } from "aurelia-dialog"; +import { ValidationControllerFactory, ValidationRules } from "aurelia-validation"; +import { HttpClient } from "aurelia-http-client"; +import { Confirm } from "../../dialogs/confirm"; + +@customElement("p45-pay-instruction") +@inject(EventAggregator, ValidationControllerFactory, DialogService) +export class P45PayInstruction { + constructor(EventAggregator, controllerFactory, dialogService) { + this.ea = EventAggregator; + this.validationController = controllerFactory.createForCurrentScope(); + this.dialogService = dialogService; + this.client = new HttpClient(); + } + + @bindable employerid = null; + @bindable employeeid = null; + @bindable p45payinstruction = null; + + setupValidationRules() { + ValidationRules + .ensure("StartDate").required().withMessage("Start date is required") + .ensure("TaxablePay").required().withMessage("Taxable pay is required") + .ensure("TaxPaid").required().withMessage("Tax paid is required") + .ensure("TaxCode").required().withMessage("Tax code is required") + .ensure("LeavingDate").required().withMessage("Leaving date is required") + .on(this.p45payinstruction); + } + + add() { + this.p45payinstruction = { + TaxBasis: "Cumulative", + StudentLoan: "Off", + PayFrequency: "Weekly" + }; + } + + save() { + this.validationController.validate().then(result => { + if (result.valid) { + let data = { + StartDate: this.p45payinstruction.StartDate, + EndDate: this.p45payinstruction.EndDate, + Description: this.p45payinstruction.Description, + TaxablePay: this.p45payinstruction.TaxablePay, + TaxPaid: this.p45payinstruction.TaxPaid, + TaxCode: this.p45payinstruction.TaxCode, + TaxBasis: this.p45payinstruction.TaxBasis, + StudentLoan: this.p45payinstruction.StudentLoan, + PayFrequency: this.p45payinstruction.PayFrequency, + LeavingDate: this.p45payinstruction.LeavingDate, + PreviousEmployerPayeRef: this.p45payinstruction.PreviousEmployerPayeRef + }; + let url = `/api/employer/${this.employerid}/Employee/${this.employeeid}/P45Instruction`; + + this.ea.publish("request:processing"); + + this.client.post(url, data).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + }); + } + else { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + }); + } + + delete() { + let opts = { + viewModel: Confirm, + model: { + title: "Are you sure?", + message: "Are you sure you want to delete this pay instruction?" + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + let employerId = this.employerid; + let employeeId = this.employeeid; + let payInstructionId = this.p45payinstruction.Id; + let url = `/api/employer/${employerId}/employee/${employeeId}/payInstruction/${payInstructionId}`; + + this.ea.publish("request:processing"); + + this.client.delete(url).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.p45payinstruction = null; + this.status = parsedResponse.status; + }); + } + }); + } + + p45payinstructionChanged() { + if (this.p45payinstruction) { + this.setupValidationRules(); + } + } +} \ No newline at end of file diff --git a/src/employee/employee.html b/src/employee/employee.html new file mode 100644 index 0000000..d58815e --- /dev/null +++ b/src/employee/employee.html @@ -0,0 +1,159 @@ + \ No newline at end of file diff --git a/src/employee/employee.js b/src/employee/employee.js new file mode 100644 index 0000000..62e46d5 --- /dev/null +++ b/src/employee/employee.js @@ -0,0 +1,193 @@ +import { inject } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { HttpClient } from "aurelia-http-client"; +import { DialogService } from "aurelia-dialog"; +import { Router } from "aurelia-router"; +import { Confirm } from "../dialogs/confirm"; +import { PayInstructionModal } from "../pay-instruction/pay-instruction-modal"; +import { BaseViewModel } from "../base-view-model"; + +@inject(EventAggregator, DialogService, Router) +export class Employee extends BaseViewModel { + constructor(eventAggregator, dialogService, router) { + super(router); + + this.employee = null; + this.ea = eventAggregator; + this.dialogService = dialogService; + this.client = new HttpClient(); + + this.typesOfPayInstruction = [ + "AoePayInstruction", + "BenefitPayInstruction", + "NiAdjustmentPayInstruction", + "NiPayInstruction", + "PensionPayInstruction", + "PrimitivePayInstruction", + "RatePayInstruction", + "SalaryPayInstruction", + "ShppPayInstruction", + "SspPayInstruction", + "StudentLoanPayInstruction", + "TaxPayInstruction" + ]; + + this.typesOfYTDPayInstruction = [ + "NiYtdPayInstruction", + "PensionYtdPayInstruction", + "PrimitiveYtdPayInstruction", + "SapYtdPayInstruction", + "ShppYtdPayInstruction", + "SmpYtdPayInstruction", + "SppYtdPayInstruction", + "SspYtdPayInstruction", + "StudentLoanYtdPayInstruction", + "TaxYtdPayInstruction" + ]; + } + + activate(params) { + this.getPayInstructionTypes(); + + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 100); + + if (params && params.employerId && params.employeeId) { + return this.getEmployeeDetails(params.employerId, params.employeeId); + } + else { + this.employee = { + EmployerId: params.employerId + }; + } + } + + attached() { + if (this.employee) { + super.setTitle(this.employee.Code); + } + else { + super.setTitle("New Employee"); + } + } + + deactivate() { + if (this.reloadEmployeeSubscriber) { + this.reloadEmployeeSubscriber.dispose(); + } + } + + getEmployeeDetails(employerId, employeeId) { + return new Promise(resolve => { + this.ea.publish("request:processing"); + + this.client.get(`/api/employer/${employerId}/employee/${employeeId}`).then(res => { + this.ea.publish("request:complete"); + + this.employee = JSON.parse(res.response); + + this.employee.EmployerId = employerId; + + resolve(); + }); + }); + } + + getPayInstructionTypes() { + return new Promise(resolve => { + this.ea.publish("request:processing"); + + this.client.get("/api/pay-instructions").then(res => { + this.ea.publish("request:complete"); + + let response = JSON.parse(res.response); + + this.typesOfPayInstruction = response.filter(pi => pi.group === "normal"); + this.typesOfYTDPayInstruction = response.filter(pi => pi.group === "year-to-date"); + + resolve(); + }); + }); + } + + openAddPayInstructionModal(piType) { + let employerId = this.employee.EmployerId; + let employeeId = this.employee.Id; + let opts = { + viewModel: PayInstructionModal, + model: { + type: piType, + employerId: employerId, + employeeId: employeeId + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.status = response.output; + + this.getEmployeeDetails(employerId, employeeId); + } + }); + } + + openEditPayInstructionModal(pi) { + let employerId = this.employee.EmployerId; + let employeeId = this.employee.Id; + let opts = { + viewModel: PayInstructionModal, + model: { + id: pi.Id, + employerId: employerId, + employeeId: employeeId + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.status = response.output; + + this.getEmployeeDetails(employerId, employeeId); + } + }); + } + + deleteInstruction(pi) { + let opts = { + viewModel: Confirm, + model: { + title: "Are you sure?", + message: "Are you sure you want to delete this pay instruction?" + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + let employerId = this.employee.EmployerId; + let employeeId = this.employee.Id; + let payInstructionId = pi.Id; + let url = `/api/employer/${employerId}/employee/${employeeId}/payInstruction/${payInstructionId}`; + + this.ea.publish("request:processing"); + + this.client.delete(url).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.getEmployeeDetails(employerId, employeeId); + }); + } + }); + } +} \ No newline at end of file diff --git a/src/employer/employer-form.html b/src/employer/employer-form.html new file mode 100644 index 0000000..cb80e46 --- /dev/null +++ b/src/employer/employer-form.html @@ -0,0 +1,442 @@ + \ No newline at end of file diff --git a/src/employer/employer-form.js b/src/employer/employer-form.js new file mode 100644 index 0000000..fb241d0 --- /dev/null +++ b/src/employer/employer-form.js @@ -0,0 +1,123 @@ +import { bindable, inject, customElement } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { HttpClient } from "aurelia-http-client"; +import { ValidationControllerFactory, ValidationRules } from "aurelia-validation"; +import { DialogService } from "aurelia-dialog"; +import { Confirm } from "../dialogs/confirm"; + +@customElement("employer-form") +@inject(EventAggregator, ValidationControllerFactory, DialogService) +export class EmployerForm { + constructor(EventAggregator, controllerFactory, dialogService) { + this.validationSetup = false; + + this.ea = EventAggregator; + this.client = new HttpClient(); + this.validationController = controllerFactory.createForCurrentScope(); + this.dialogService = dialogService; + this.showSaveButton = true; + } + + @bindable employer = null; + + attached() { + if (!this.employer) { + this.employer = { + Territory: "UnitedKingdom", + Region: "NotSet", + + }; + } + + this.setupTabEvents(); + this.setupValidationRules(); + } + + detached() { + } + + save() { + this.validationController.validate().then(result => { + if (result.valid) { + this.ea.publish("request:processing"); + + this.client.post("/api/Employer", this.employer).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + + this.ea.publish("employer:reload", { + employerId: parsedResponse.employerId + }); + }); + } + else { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + }); + } + + setupTabEvents() { + $("a[data-toggle='tab']").on("shown.bs.tab", (e) => { + this.showSaveButton = e.target.id !== "revisions-tab"; + }); + } + + setupValidationRules() { + ValidationRules + .ensure("Name").required().withMessage("Details > Name is required") + .ensure("EffectiveDate").required().withMessage("Details > Effective date is required") + .on(this.employer); + } + + deleteRevision(revision) { + let opts = { + viewModel: Confirm, + model: { + title: "Are you sure?", + message: "Are you sure you want to delete this revision?" + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + let employerId = this.employer.Id; + let effectiveDate = revision.EffectiveDate; + let url = `/api/employer/${employerId}/revision/${effectiveDate}`; + + this.ea.publish("request:processing"); + + this.client.delete(url).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.employer.Revisions = this.employer.Revisions.filter(rev => rev.Revision !== revision.Revision); + + this.ea.publish("employer:reload", { employerId: employerId }); + }); + } + }); + } +} \ No newline at end of file diff --git a/src/employer/employer.html b/src/employer/employer.html new file mode 100644 index 0000000..697d6bf --- /dev/null +++ b/src/employer/employer.html @@ -0,0 +1,343 @@ + \ No newline at end of file diff --git a/src/employer/employer.js b/src/employer/employer.js new file mode 100644 index 0000000..0233a6a --- /dev/null +++ b/src/employer/employer.js @@ -0,0 +1,471 @@ +import { inject } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { HttpClient } from "aurelia-http-client"; +import { DialogService } from "aurelia-dialog"; +import { Router } from "aurelia-router"; +import { PayScheduleModal } from "../pay-schedule/pay-schedule-modal"; +import { PensionModal } from "../pension/pension-modal"; +import { PayCodeModal } from "../pay-code/pay-code-modal"; +import { InfoModal } from "../pay-run/info-modal"; +import { NewPayRunModal } from "../pay-run/new-pay-run-modal"; +import { RtiTransactionModal } from "../rti-transaction/rti-transaction-modal"; +import { Confirm } from "../dialogs/confirm"; +import { BaseViewModel } from "../base-view-model"; + +@inject(EventAggregator, DialogService, Router) +export class Employer extends BaseViewModel { + constructor(eventAggregator, dialogService, router) { + super(router); + + this.employer = null; + this.ea = eventAggregator; + this.dialogService = dialogService; + this.client = new HttpClient(); + } + + activate(params) { + this.params = params; + + this.reloadEmployerSubscriber = this.ea.subscribe("employer:reload", state => { + this.getEmployerDetails(state.employerId); + }); + + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 100); + + if (params && params.id) { + return this.getEmployerDetails(params.id); + } + } + + attached() { + super.setParams(this.params); + + if (this.employer) { + super.setTitle(this.employer.Name); + } + else { + super.setTitle("New Employer"); + } + } + + deactivate() { + if (this.reloadEmployerSubscriber) { + this.reloadEmployerSubscriber.dispose(); + } + + if (this.getPaySchedulesTimeout) { + window.clearTimeout(this.getPaySchedulesTimeout); + } + + if (this.getRtiSubmissionsTimeout) { + window.clearTimeout(this.getRtiSubmissionsTimeout); + } + } + + getEmployerDetails(employerId) { + return new Promise((resolve) => { + this.ea.publish("request:processing"); + + this.client.get(`/api/employer/${employerId}`).then(data => { + this.ea.publish("request:complete"); + + this.employer = JSON.parse(data.response); + + this.createPaySchedulesTimer(); + this.createRtiSubmissionsTimer(); + + resolve(); + }); + }); + } + + getPaySchedules() { + this.ea.publish("request:processing"); + + this.client.get(`/api/employer/${this.employer.Id}/pay-schedules`).then(data => { + this.ea.publish("request:complete"); + + this.employer.PaySchedules = JSON.parse(data.response); + + this.createPaySchedulesTimer(); + }); + } + + createPaySchedulesTimer() { + this.getPaySchedulesTimeout = window.setTimeout(() => this.getPaySchedules(), 15000); + } + + getRtiSubmissions() { + this.ea.publish("request:processing"); + + this.client.get(`/api/employer/${this.employer.Id}/rti-submissions`).then(data => { + this.ea.publish("request:complete"); + + this.employer.RTITransactions = JSON.parse(data.response); + + this.createRtiSubmissionsTimer(); + }); + } + + createRtiSubmissionsTimer() { + this.getRtiSubmissionsTimeout = window.setTimeout(() => this.getRtiSubmissions(), 15000); + } + + canAddPayRun(context) { + return context.Employees.length > 0 && context.PaySchedules && context.PaySchedules.length > 0; + } + + addAPaySchedule() { + this.openPayScheduleModal({}); + } + + editPaySchedule(schedule) { + this.openPayScheduleModal(schedule); + } + + deletePaySchedule(schedule) { + let opts = { + viewModel: Confirm, + model: { + title: "Are you sure?", + message: "Are you sure you want to delete this pay schedule?" + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.ea.publish("request:processing"); + + this.client.post(`/api/employer/${this.employer.Id}/paySchedule/${schedule.Key}/delete/`).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.getEmployerDetails(this.employer.Id); + }); + } + }); + } + + openPayScheduleModal(schedule) { + schedule.employerId = this.employer.Id; + + let opts = { + viewModel: PayScheduleModal, + model: JSON.parse(JSON.stringify(schedule)) + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.status = response.output; + + this.getEmployerDetails(this.employer.Id); + } + }); + } + + addAPayCode() { + this.openPayCodeModal({ + Niable: false, + Taxable: false + }); + } + + editPayCode(payCode) { + this.openPayCodeModal(payCode); + } + + deletePayCode(employerId, payCodeId) { + this.ea.publish("request:processing"); + + this.client.delete(`/api/employer/${employerId}/payCode/${payCodeId}`).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.getEmployerDetails(employerId); + }); + } + + openPayCodeModal(payCode) { + payCode.employerId = this.employer.Id; + + let model = { + payCode: JSON.parse(JSON.stringify(payCode)), + nominalCodes: this.employer.NominalCodes + }; + let opts = { + viewModel: PayCodeModal, + model: model + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.status = response.output; + + this.getEmployerDetails(this.employer.Id); + } + }); + } + + addAPension() { + this.openPensionModal({}); + } + + editPension(pension) { + this.openPensionModal(pension); + } + + defaultPensionForAE(employerId, pensionId) { + this.ea.publish("request:processing"); + + this.client.patch(`/api/employer/${employerId}/pension/${pensionId}`).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.getEmployerDetails(employerId); + }); + } + + deletePension(employerId, pensionId) { + this.ea.publish("request:processing"); + + this.client.delete(`/api/employer/${employerId}/pension/${pensionId}`).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.getEmployerDetails(employerId); + }); + } + + openPensionModal(pension) { + pension.employerId = this.employer.Id; + + let opts = { + viewModel: PensionModal, + model: JSON.parse(JSON.stringify(pension)) + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.status = response.output; + + this.getEmployerDetails(this.employer.Id); + } + }); + } + + openPayRunInfoModal(employerId, payScheduleId, payRunId) { + let url = `api/employer/${employerId}/paySchedule/${payScheduleId}/payRun/${payRunId}`; + + this.ea.publish("request:processing"); + + this.client.get(url).then(res => { + this.ea.publish("request:complete"); + + let payRun = JSON.parse(res.response); + + payRun.EmployerId = this.employer.Id; + + let opts = { + viewModel: InfoModal, + model: payRun + }; + + this.dialogService.open(opts); + }); + } + + openAddPayRunModal(employerId, payScheduleId) { + let url = `/api/employer/${employerId}/paySchedule/${payScheduleId}/next-pay-run`; + + this.ea.publish("request:processing"); + + this.client.get(url).then(res => { + this.ea.publish("request:complete"); + + let nextPayRun = JSON.parse(res.response); + + let state = { + Title: "Create PayRun", + EmployerId: employerId, + PayScheduleId: payScheduleId, + PaymentDate: nextPayRun.paymentDate, + StartDate: nextPayRun.periodStart, + EndDate: nextPayRun.periodEnd, + PaySchedules: [] + }; + + let opts = { + viewModel: NewPayRunModal, + model: state + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.status = response.output; + + this.getEmployerDetails(this.employer.Id); + } + }); + }); + } + + openRerunPayRunModal(employerId, payScheduleId, payRun) { + let state = { + Title: "Rerun PayRun", + Instruction: "Re-running will delete the previous run.", + EmployerId: employerId, + PayScheduleId: payScheduleId, + PaymentDate: payRun.PaymentDate, + StartDate: payRun.PeriodStart, + EndDate: payRun.PeriodEnd, + PaySchedules: [] + }; + + let opts = { + viewModel: NewPayRunModal, + model: state + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.status = response.output; + + this.getEmployerDetails(this.employer.Id); + } + }); + } + + deletePayRun(employerId, payScheduleId, payRunId) { + let opts = { + viewModel: Confirm, + model: { + title: "Are you sure?", + message: "Are you sure you want to delete this pay run?" + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.ea.publish("request:processing"); + + this.client.delete(`/api/employer/${employerId}/paySchedule/${payScheduleId}/payRun/${payRunId}`).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.getEmployerDetails(employerId); + }); + } + }); + } + + openAddRtiSubmissionModal(employerId) { + this.ea.publish("request:processing"); + + this.client.get(`/api/employer/${employerId}/payRuns`).then(res => { + this.ea.publish("request:complete"); + + let payRuns = JSON.parse(res.response); + + let opts = { + viewModel: RtiTransactionModal, + model: { + employerId: employerId, + payRuns: payRuns + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.status = response.output; + + this.getEmployerDetails(this.employer.Id); + } + }); + }); + } + + deleteEmployee(employerId, employeeId) { + let opts = { + viewModel: Confirm, + model: { + title: "Are you sure?", + message: "Are you sure you want to delete this employee?" + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.ea.publish("request:processing"); + + this.client.delete(`/api/employer/${employerId}/employee/${employeeId}`).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.getEmployerDetails(employerId); + }); + } + }); + } +} \ No newline at end of file diff --git a/src/employer/list.html b/src/employer/list.html new file mode 100644 index 0000000..923d4e4 --- /dev/null +++ b/src/employer/list.html @@ -0,0 +1,96 @@ + \ No newline at end of file diff --git a/src/employer/list.js b/src/employer/list.js new file mode 100644 index 0000000..4558842 --- /dev/null +++ b/src/employer/list.js @@ -0,0 +1,65 @@ +import { inject } from "aurelia-framework"; +import { HttpClient } from "aurelia-http-client"; +import { DialogService } from "aurelia-dialog"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { Confirm } from "../dialogs/confirm"; + +@inject(DialogService, EventAggregator) +export class List { + constructor(dialogService, eventAggregator) { + this.dialogService = dialogService; + this.ea = eventAggregator; + this.client = new HttpClient(); + } + + activate() { + return this.getEmployers(); + } + + getEmployers() { + return new Promise(resolve => { + this.ea.publish("request:processing"); + + this.client.get("/api/employers").then(data => { + this.ea.publish("request:complete"); + + this.employers = JSON.parse(data.response); + + resolve(); + }); + }); + } + + deleteEmployer(id) { + let opts = { + viewModel: Confirm, + model: { + title: "Are you sure?", + message: "Are you sure you want to delete this employer?" + } + }; + + this.dialogService.open(opts).whenClosed(response => { + if (!response.wasCancelled) { + this.ea.publish("request:processing"); + + this.client.delete(`/api/employer/${id}`).then(res => { + this.ea.publish("request:complete"); + + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + this.status = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.status = parsedResponse.status; + this.getEmployers(); + }); + } + }); + } +} \ No newline at end of file diff --git a/src/environment.js b/src/environment.js new file mode 100644 index 0000000..3495e9a --- /dev/null +++ b/src/environment.js @@ -0,0 +1,4 @@ +export default { + debug: true, + testing: true +}; diff --git a/src/footer/footer.html b/src/footer/footer.html new file mode 100644 index 0000000..b500861 --- /dev/null +++ b/src/footer/footer.html @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/footer/footer.js b/src/footer/footer.js new file mode 100644 index 0000000..dc61beb --- /dev/null +++ b/src/footer/footer.js @@ -0,0 +1,28 @@ +import { inject } from "aurelia-framework"; +import { HttpClient } from "aurelia-http-client"; +import { Router } from "aurelia-router"; + +@inject(Router) +export class Footer { + constructor(router) { + this.router = router; + } + + attached() { + this.showVersionInfo = this.router.currentInstruction.config.auth; + + var GitHubButtons = require("github-buttons"); + + GitHubButtons.render(); + + return new Promise(resolve => { + let client = new HttpClient(); + + client.get("/api/version").then(data => { + this.state = JSON.parse(data.response); + + resolve(); + }); + }); + } +} \ No newline at end of file diff --git a/src/header/header.html b/src/header/header.html new file mode 100644 index 0000000..084f90e --- /dev/null +++ b/src/header/header.html @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/header/header.js b/src/header/header.js new file mode 100644 index 0000000..86bc7b0 --- /dev/null +++ b/src/header/header.js @@ -0,0 +1,19 @@ +import { inject } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { Router } from "aurelia-router"; + +@inject(EventAggregator, Router) +export class Header { + constructor(EventAggregator, router) { + this.ea = EventAggregator; + this.router = router; + } + + attached() { + this.showApiCallsButton = this.router.currentInstruction.config.auth; + } + + toggleAPICalls() { + this.ea.publish("toggleAPICalls"); + } +} \ No newline at end of file diff --git a/src/job/job-details-modal.html b/src/job/job-details-modal.html new file mode 100644 index 0000000..9e279af --- /dev/null +++ b/src/job/job-details-modal.html @@ -0,0 +1,102 @@ + \ No newline at end of file diff --git a/src/job/job-details-modal.js b/src/job/job-details-modal.js new file mode 100644 index 0000000..932f4b7 --- /dev/null +++ b/src/job/job-details-modal.js @@ -0,0 +1,31 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; +import { HttpClient } from "aurelia-http-client"; + +@inject(DialogController) +export class JobDetailsModal { + constructor(dialogController) { + this.dialogController = dialogController; + this.client = new HttpClient(); + } + + activate(job) { + this.job = job; + + return this.getJobInfo(); + } + + getJobInfo() { + return new Promise((resolve) => { + let url = `/api/job/${this.job.id}/${this.job.type}`; + + this.client.get(url).then(data => { + this.state = JSON.parse(data.response); + + window.setTimeout(() => this.getJobInfo(), 500); + + resolve(); + }); + }); + } +} \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..8873ea2 --- /dev/null +++ b/src/main.js @@ -0,0 +1,23 @@ +import { PLATFORM } from "aurelia-pal"; +import environment from "./environment"; + +export function configure(aurelia) { + aurelia.use + .standardConfiguration() + .plugin("aurelia-validation") + .plugin(PLATFORM.moduleName("aurelia-dialog"), config => { + config.useDefaults(); + config.settings.centerHorizontalOnly = true; + }) + .feature("resources"); + + if (environment.debug) { + aurelia.use.developmentLogging(); + } + + if (environment.testing) { + aurelia.use.plugin("aurelia-testing"); + } + + return aurelia.start().then(() => aurelia.setRoot()); +} diff --git a/src/pay-code/pay-code-modal.html b/src/pay-code/pay-code-modal.html new file mode 100644 index 0000000..802d767 --- /dev/null +++ b/src/pay-code/pay-code-modal.html @@ -0,0 +1,259 @@ + \ No newline at end of file diff --git a/src/pay-code/pay-code-modal.js b/src/pay-code/pay-code-modal.js new file mode 100644 index 0000000..5e73538 --- /dev/null +++ b/src/pay-code/pay-code-modal.js @@ -0,0 +1,58 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; +import { ValidationControllerFactory, ValidationRules } from "aurelia-validation"; +import { HttpClient } from "aurelia-http-client"; + +@inject(ValidationControllerFactory, DialogController) +export class PayCodeModal { + constructor(controllerFactory, dialogController) { + this.dialogController = dialogController; + this.validationController = controllerFactory.createForCurrentScope(); + this.client = new HttpClient(); + } + + activate(state) { + this.state = state.payCode; + + this.nominalCodes = state.nominalCodes; + + this.territories = [ + { value: "UnitedKingdom", text: "United Kingdom" } + ]; + + this.regions = [ + { value: "NotSet", text: "Not set" }, + { value: "England", text: "England" }, + { value: "Scotland", text: "Scotland" } + ]; + + this.types = [ + { value: "Payment", text: "Payment" }, + { value: "Deduction", text: "Deduction" } + ]; + } + + save() { + this.validationController.validate().then(result => { + if (result.valid) { + this.client.post(`/api/employer/${this.state.employerId}/payCode`, this.state).then(res => { + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.dialogController.ok(parsedResponse.status); + }); + } + else { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + }); + } +} \ No newline at end of file diff --git a/src/pay-instruction/pay-instruction-modal.html b/src/pay-instruction/pay-instruction-modal.html new file mode 100644 index 0000000..3aa23dd --- /dev/null +++ b/src/pay-instruction/pay-instruction-modal.html @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instruction-modal.js b/src/pay-instruction/pay-instruction-modal.js new file mode 100644 index 0000000..dd4fe46 --- /dev/null +++ b/src/pay-instruction/pay-instruction-modal.js @@ -0,0 +1,58 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; +import { HttpClient } from "aurelia-http-client"; + +@inject(DialogController) +export class PayInstructionModal { + constructor(dialogController) { + this.dialogController = dialogController; + this.client = new HttpClient(); + } + + activate(state) { + this.state = state; + + return new Promise(resolve => { + let apiUrl; + + if (state.id) { + apiUrl = `/api/employer/${state.employerId}/employee/${state.employeeId}/payInstruction/${state.id}`; + } + else { + apiUrl = `/api/employer/${state.employerId}/employee/${state.employeeId}/${state.type}`; + } + + this.client.get(apiUrl).then(res => { + this.pi = JSON.parse(res.response); + + resolve(); + }); + }); + } + + save() { + let data = this.pi; + let url = `/api/employer/${this.state.employerId}/employee/${this.state.employeeId}/payInstruction`; + + this.client.post(url, data).then(res => { + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.dialogController.ok(parsedResponse.status); + }); + } + + getPayInstructionPartial(pi) { + if (pi.InstructionType.trim().toLowerCase().indexOf("ytd") != -1) { + return `./ytd-pay-instructions/forms/${pi.InstructionType}.html`; + } + + return `./pay-instructions/forms/${pi.InstructionType}.html`; + } +} \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/AoePayInstruction.html b/src/pay-instruction/pay-instructions/forms/AoePayInstruction.html new file mode 100644 index 0000000..c570076 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/AoePayInstruction.html @@ -0,0 +1,211 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/BenefitPayInstruction.html b/src/pay-instruction/pay-instructions/forms/BenefitPayInstruction.html new file mode 100644 index 0000000..e5213d9 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/BenefitPayInstruction.html @@ -0,0 +1,97 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/NiAdjustmentPayInstruction.html b/src/pay-instruction/pay-instructions/forms/NiAdjustmentPayInstruction.html new file mode 100644 index 0000000..5ddba46 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/NiAdjustmentPayInstruction.html @@ -0,0 +1,94 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/NiPayInstruction.html b/src/pay-instruction/pay-instructions/forms/NiPayInstruction.html new file mode 100644 index 0000000..4cf3992 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/NiPayInstruction.html @@ -0,0 +1,47 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/PensionPayInstruction.html b/src/pay-instruction/pay-instructions/forms/PensionPayInstruction.html new file mode 100644 index 0000000..3fe4234 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/PensionPayInstruction.html @@ -0,0 +1,223 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/PrimitivePayInstruction.html b/src/pay-instruction/pay-instructions/forms/PrimitivePayInstruction.html new file mode 100644 index 0000000..7c580bd --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/PrimitivePayInstruction.html @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/RatePayInstruction.html b/src/pay-instruction/pay-instructions/forms/RatePayInstruction.html new file mode 100644 index 0000000..8135fc2 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/RatePayInstruction.html @@ -0,0 +1,68 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/SalaryPayInstruction.html b/src/pay-instruction/pay-instructions/forms/SalaryPayInstruction.html new file mode 100644 index 0000000..d3bbba5 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/SalaryPayInstruction.html @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/ShppPayInstruction.html b/src/pay-instruction/pay-instructions/forms/ShppPayInstruction.html new file mode 100644 index 0000000..454aee2 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/ShppPayInstruction.html @@ -0,0 +1,128 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/SmpPayInstruction.html b/src/pay-instruction/pay-instructions/forms/SmpPayInstruction.html new file mode 100644 index 0000000..6b7bc10 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/SmpPayInstruction.html @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/SspPayInstruction.html b/src/pay-instruction/pay-instructions/forms/SspPayInstruction.html new file mode 100644 index 0000000..ccbdfd7 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/SspPayInstruction.html @@ -0,0 +1,67 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/StudentLoanPayInstruction.html b/src/pay-instruction/pay-instructions/forms/StudentLoanPayInstruction.html new file mode 100644 index 0000000..5e5cb46 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/StudentLoanPayInstruction.html @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/TaxPayInstruction.html b/src/pay-instruction/pay-instructions/forms/TaxPayInstruction.html new file mode 100644 index 0000000..415af36 --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/TaxPayInstruction.html @@ -0,0 +1,36 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/forms/pay-instruction.html b/src/pay-instruction/pay-instructions/forms/pay-instruction.html new file mode 100644 index 0000000..463dfcf --- /dev/null +++ b/src/pay-instruction/pay-instructions/forms/pay-instruction.html @@ -0,0 +1,89 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/AoePayInstruction.html b/src/pay-instruction/pay-instructions/lists/AoePayInstruction.html new file mode 100644 index 0000000..b8ea71c --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/AoePayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/BenefitPayInstruction.html b/src/pay-instruction/pay-instructions/lists/BenefitPayInstruction.html new file mode 100644 index 0000000..92d0e2c --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/BenefitPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/NiAdjustmentPayInstruction.html b/src/pay-instruction/pay-instructions/lists/NiAdjustmentPayInstruction.html new file mode 100644 index 0000000..c3efaa9 --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/NiAdjustmentPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/NiPayInstruction.html b/src/pay-instruction/pay-instructions/lists/NiPayInstruction.html new file mode 100644 index 0000000..d95c1d6 --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/NiPayInstruction.html @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/PensionPayInstruction.html b/src/pay-instruction/pay-instructions/lists/PensionPayInstruction.html new file mode 100644 index 0000000..b6ea5ec --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/PensionPayInstruction.html @@ -0,0 +1,50 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/PrimitivePayInstruction.html b/src/pay-instruction/pay-instructions/lists/PrimitivePayInstruction.html new file mode 100644 index 0000000..65bb320 --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/PrimitivePayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/RatePayInstruction.html b/src/pay-instruction/pay-instructions/lists/RatePayInstruction.html new file mode 100644 index 0000000..20dcda4 --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/RatePayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/SalaryPayInstruction.html b/src/pay-instruction/pay-instructions/lists/SalaryPayInstruction.html new file mode 100644 index 0000000..7cc0478 --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/SalaryPayInstruction.html @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/ShppPayInstruction.html b/src/pay-instruction/pay-instructions/lists/ShppPayInstruction.html new file mode 100644 index 0000000..cceb155 --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/ShppPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/SspPayInstruction.html b/src/pay-instruction/pay-instructions/lists/SspPayInstruction.html new file mode 100644 index 0000000..f2de70f --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/SspPayInstruction.html @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/StudentLoanPayInstruction.html b/src/pay-instruction/pay-instructions/lists/StudentLoanPayInstruction.html new file mode 100644 index 0000000..d79afb1 --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/StudentLoanPayInstruction.html @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/src/pay-instruction/pay-instructions/lists/TaxPayInstruction.html b/src/pay-instruction/pay-instructions/lists/TaxPayInstruction.html new file mode 100644 index 0000000..6558200 --- /dev/null +++ b/src/pay-instruction/pay-instructions/lists/TaxPayInstruction.html @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/NiYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/NiYtdPayInstruction.html new file mode 100644 index 0000000..e2dbf3a --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/NiYtdPayInstruction.html @@ -0,0 +1,237 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/PensionYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/PensionYtdPayInstruction.html new file mode 100644 index 0000000..e36282e --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/PensionYtdPayInstruction.html @@ -0,0 +1,99 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/PrimitiveYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/PrimitiveYtdPayInstruction.html new file mode 100644 index 0000000..3024d2e --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/PrimitiveYtdPayInstruction.html @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/SapYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/SapYtdPayInstruction.html new file mode 100644 index 0000000..c37f7d1 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/SapYtdPayInstruction.html @@ -0,0 +1,100 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/ShppYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/ShppYtdPayInstruction.html new file mode 100644 index 0000000..d51cc98 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/ShppYtdPayInstruction.html @@ -0,0 +1,78 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/SmpYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/SmpYtdPayInstruction.html new file mode 100644 index 0000000..3ffecae --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/SmpYtdPayInstruction.html @@ -0,0 +1,100 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/SppYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/SppYtdPayInstruction.html new file mode 100644 index 0000000..d51cc98 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/SppYtdPayInstruction.html @@ -0,0 +1,78 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/SspYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/SspYtdPayInstruction.html new file mode 100644 index 0000000..35d79a7 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/SspYtdPayInstruction.html @@ -0,0 +1,106 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/StudentLoanYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/StudentLoanYtdPayInstruction.html new file mode 100644 index 0000000..f82d148 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/StudentLoanYtdPayInstruction.html @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/TaxYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/forms/TaxYtdPayInstruction.html new file mode 100644 index 0000000..72248a4 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/TaxYtdPayInstruction.html @@ -0,0 +1,68 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/forms/ytd-pay-instruction.html b/src/pay-instruction/ytd-pay-instructions/forms/ytd-pay-instruction.html new file mode 100644 index 0000000..6760bdf --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/forms/ytd-pay-instruction.html @@ -0,0 +1,106 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/NiYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/NiYtdPayInstruction.html new file mode 100644 index 0000000..dead7a4 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/NiYtdPayInstruction.html @@ -0,0 +1,50 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/PensionYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/PensionYtdPayInstruction.html new file mode 100644 index 0000000..432e0d3 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/PensionYtdPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/PrimitiveYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/PrimitiveYtdPayInstruction.html new file mode 100644 index 0000000..fe737a8 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/PrimitiveYtdPayInstruction.html @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/SapYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/SapYtdPayInstruction.html new file mode 100644 index 0000000..0b9679b --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/SapYtdPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/ShppYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/ShppYtdPayInstruction.html new file mode 100644 index 0000000..494e73e --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/ShppYtdPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/SmpYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/SmpYtdPayInstruction.html new file mode 100644 index 0000000..1ad8b87 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/SmpYtdPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/SppYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/SppYtdPayInstruction.html new file mode 100644 index 0000000..e20e383 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/SppYtdPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/SspYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/SspYtdPayInstruction.html new file mode 100644 index 0000000..95b94b0 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/SspYtdPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/StudentLoanYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/StudentLoanYtdPayInstruction.html new file mode 100644 index 0000000..27ec6ef --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/StudentLoanYtdPayInstruction.html @@ -0,0 +1,42 @@ + \ No newline at end of file diff --git a/src/pay-instruction/ytd-pay-instructions/lists/TaxYtdPayInstruction.html b/src/pay-instruction/ytd-pay-instructions/lists/TaxYtdPayInstruction.html new file mode 100644 index 0000000..3637a35 --- /dev/null +++ b/src/pay-instruction/ytd-pay-instructions/lists/TaxYtdPayInstruction.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/src/pay-run/info-modal.html b/src/pay-run/info-modal.html new file mode 100644 index 0000000..694a0bc --- /dev/null +++ b/src/pay-run/info-modal.html @@ -0,0 +1,146 @@ + \ No newline at end of file diff --git a/src/pay-run/info-modal.js b/src/pay-run/info-modal.js new file mode 100644 index 0000000..1f668eb --- /dev/null +++ b/src/pay-run/info-modal.js @@ -0,0 +1,24 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; +import { Router } from "aurelia-router"; + +@inject(DialogController, Router) +export class InfoModal { + constructor(dialogController, router) { + this.dialogController = dialogController; + this.router = router; + } + + activate(state) { + this.state = state; + } + + viewEmployee(employerId, employeeId) { + this.router.navigateToRoute("employee", { + employerId: employerId, + employeeId: employeeId + }); + + this.dialogController.ok(); + } +} \ No newline at end of file diff --git a/src/pay-run/new-pay-run-modal.html b/src/pay-run/new-pay-run-modal.html new file mode 100644 index 0000000..6836ba8 --- /dev/null +++ b/src/pay-run/new-pay-run-modal.html @@ -0,0 +1,94 @@ + \ No newline at end of file diff --git a/src/pay-run/new-pay-run-modal.js b/src/pay-run/new-pay-run-modal.js new file mode 100644 index 0000000..0cb6f09 --- /dev/null +++ b/src/pay-run/new-pay-run-modal.js @@ -0,0 +1,59 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; +import { ValidationControllerFactory, ValidationRules } from "aurelia-validation"; +import { HttpClient } from "aurelia-http-client"; + +@inject(ValidationControllerFactory, DialogController) +export class NewPayRunModal { + constructor(controllerFactory, dialogController) { + this.dialogController = dialogController; + this.validationController = controllerFactory.createForCurrentScope(); + this.client = new HttpClient(); + } + + activate(state) { + this.state = state; + + this.setupValidationRules(); + } + + setupValidationRules() { + ValidationRules + .ensure("PayScheduleId").required().withMessage("Pay Schedule is required") + .ensure("PaymentDate").required().withMessage("Payment Date is required") + .ensure("StartDate").required().withMessage("Pay Period Start is required") + .ensure("EndDate").required().withMessage("Pay Period End is required") + .on(this.state); + } + + save() { + let data = { + PayScheduleId: this.state.PayScheduleId, + PaymentDate: this.state.PaymentDate, + StartDate: this.state.StartDate, + EndDate: this.state.EndDate + }; + + this.validationController.validate().then(result => { + if (result.valid) { + this.client.post(`/api/employer/${this.state.EmployerId}/payRun`, data).then(res => { + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.dialogController.ok(parsedResponse.status); + }); + } + else { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + }); + } +} \ No newline at end of file diff --git a/src/pay-schedule/pay-schedule-modal.html b/src/pay-schedule/pay-schedule-modal.html new file mode 100644 index 0000000..2709d74 --- /dev/null +++ b/src/pay-schedule/pay-schedule-modal.html @@ -0,0 +1,65 @@ + \ No newline at end of file diff --git a/src/pay-schedule/pay-schedule-modal.js b/src/pay-schedule/pay-schedule-modal.js new file mode 100644 index 0000000..dd4c51b --- /dev/null +++ b/src/pay-schedule/pay-schedule-modal.js @@ -0,0 +1,62 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; +import { ValidationControllerFactory, ValidationRules } from "aurelia-validation"; +import { HttpClient } from "aurelia-http-client"; + +@inject(ValidationControllerFactory, DialogController) +export class PayScheduleModal { + constructor(controllerFactory, dialogController) { + this.dialogController = dialogController; + this.validationController = controllerFactory.createForCurrentScope(); + this.client = new HttpClient(); + } + + activate(state) { + this.state = state; + this.frequencies = [ + { text: "Weekly", value: "Weekly" }, + { text: "Monthly", value: "Monthly" }, + { text: "Two weekly", value: "TwoWeekly" }, + { text: "Four weekly", value: "FourWeekly" } + ]; + + this.setupValidationRules(); + } + + setupValidationRules() { + ValidationRules + .ensure("Name").required().withMessage("Name is required") + .ensure("PayFrequency").required().withMessage("Pay Frequency is required") + .on(this.state); + } + + save() { + let data = { + Id: this.state.Key, + Name: this.state.Name, + PayFrequency: this.state.PayFrequency + }; + + this.validationController.validate().then(result => { + if (result.valid) { + this.client.post(`/api/employer/${this.state.employerId}/paySchedule`, data).then(res => { + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.dialogController.ok(parsedResponse.status); + }); + } + else { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + }); + } +} \ No newline at end of file diff --git a/src/pension/pension-modal.html b/src/pension/pension-modal.html new file mode 100644 index 0000000..0e838b6 --- /dev/null +++ b/src/pension/pension-modal.html @@ -0,0 +1,335 @@ + \ No newline at end of file diff --git a/src/pension/pension-modal.js b/src/pension/pension-modal.js new file mode 100644 index 0000000..4d12f62 --- /dev/null +++ b/src/pension/pension-modal.js @@ -0,0 +1,67 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; +import { ValidationControllerFactory, ValidationRules } from "aurelia-validation"; +import { HttpClient } from "aurelia-http-client"; + +@inject(ValidationControllerFactory, DialogController) +export class PensionModal { + constructor(controllerFactory, dialogController) { + this.dialogController = dialogController; + this.validationController = controllerFactory.createForCurrentScope(); + this.client = new HttpClient(); + } + + activate(state) { + this.state = state; + + this.proRataMethods = [ + { value: "NotSet", text: "Not set" }, + { value: "Annual260Days", text: "Annual 260 days" }, + { value: "Annual365Days", text: "Annual 365 days" }, + { value: "AnnualQualifyingDays", text: "Annual qualifying days" }, + { value: "DaysPerCalenderMonth", text: "Days per calender month" }, + { value: "DaysPerTaxPeriod", text: "Days per tax period" }, + ]; + + this.taxationMethods = [ + { value: "NotSet", text: "Not set" }, + { value: "NetBased", text: "Net based" }, + { value: "ReliefAtSource", text: "Relief at source" } + ]; + + this.setupValidationRules(); + } + + setupValidationRules() { + ValidationRules + .ensure("SchemeName").required().withMessage("Scheme name is required") + .ensure("ProviderName").required().withMessage("Provider name is required") + .ensure("ProviderEmployerRef").required().withMessage("Provider employer ref is required") + .ensure("EffectiveDate").required().withMessage("Effective date is required") + .on(this.state); + } + + save() { + this.validationController.validate().then(result => { + if (result.valid) { + this.client.post(`/api/employer/${this.state.employerId}/pension`, this.state).then(res => { + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.dialogController.ok(parsedResponse.status); + }); + } + else { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + }); + } +} \ No newline at end of file diff --git a/src/resources/elements/address-form/address-form.html b/src/resources/elements/address-form/address-form.html new file mode 100644 index 0000000..9f4ec56 --- /dev/null +++ b/src/resources/elements/address-form/address-form.html @@ -0,0 +1,78 @@ + \ No newline at end of file diff --git a/src/resources/elements/address-form/address-form.js b/src/resources/elements/address-form/address-form.js new file mode 100644 index 0000000..23370a6 --- /dev/null +++ b/src/resources/elements/address-form/address-form.js @@ -0,0 +1,16 @@ +import { bindable, customElement } from "aurelia-framework"; + +@customElement("address-form") +export class AddressForm { + @bindable address = null; + + addressChanged() { + if (!this.address) { + this.address = {}; + } + + if (!this.address.Country) { + this.address.Country = "United Kingdom"; + } + } +} \ No newline at end of file diff --git a/src/resources/elements/api-errors/api-errors.html b/src/resources/elements/api-errors/api-errors.html new file mode 100644 index 0000000..ed6fc18 --- /dev/null +++ b/src/resources/elements/api-errors/api-errors.html @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/resources/elements/api-errors/api-errors.js b/src/resources/elements/api-errors/api-errors.js new file mode 100644 index 0000000..f5cf246 --- /dev/null +++ b/src/resources/elements/api-errors/api-errors.js @@ -0,0 +1,14 @@ +import { bindable, customElement } from "aurelia-framework"; + +@customElement("api-errors") +export class ApiErrors { + @bindable errors = null; + + errorsChanged() { + if (this.errors) { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + } +} \ No newline at end of file diff --git a/src/resources/elements/bank-account-form/bank-account-form.html b/src/resources/elements/bank-account-form/bank-account-form.html new file mode 100644 index 0000000..c668cc0 --- /dev/null +++ b/src/resources/elements/bank-account-form/bank-account-form.html @@ -0,0 +1,44 @@ + \ No newline at end of file diff --git a/src/resources/elements/bank-account-form/bank-account-form.js b/src/resources/elements/bank-account-form/bank-account-form.js new file mode 100644 index 0000000..8c3a8f2 --- /dev/null +++ b/src/resources/elements/bank-account-form/bank-account-form.js @@ -0,0 +1,6 @@ +import { bindable, customElement } from "aurelia-framework"; + +@customElement("bank-account-form") +export class BankAccountForm { + @bindable bankaccount = null; +} \ No newline at end of file diff --git a/src/resources/elements/breadcrumbs/breadcrumbs.html b/src/resources/elements/breadcrumbs/breadcrumbs.html new file mode 100644 index 0000000..083b034 --- /dev/null +++ b/src/resources/elements/breadcrumbs/breadcrumbs.html @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/resources/elements/breadcrumbs/breadcrumbs.js b/src/resources/elements/breadcrumbs/breadcrumbs.js new file mode 100644 index 0000000..481f0b1 --- /dev/null +++ b/src/resources/elements/breadcrumbs/breadcrumbs.js @@ -0,0 +1,58 @@ +import { inject, customElement } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import { Router } from "aurelia-router"; + +@customElement("breadcrumbs") +@inject(EventAggregator, Router) +export class Breadcrumbs { + constructor(eventAggregator, router) { + this.ea = eventAggregator; + this.router = router; + } + + attached() { + this.navigationSubscriber = this.ea.subscribe("router:navigation:success", () => { + this.loadInstructions(); + }); + + this.loadInstructions(); + } + + detached() { + if (this.navigationSubscriber) { + this.navigationSubscriber.dispose(); + } + } + + loadInstructions() { + let parentInstructions = this.getParentInstructions(this.router.currentInstruction); + + this.instructions = parentInstructions + .slice(0, parentInstructions.length - 1) + .concat(this.router.currentInstruction.getAllInstructions()) + .filter(instruction => instruction.config.includeInBreadcrumbs && instruction.config.title); + } + + navigateToRoute(instruction) { + this.router.navigateToRoute(instruction.config.name, instruction.params); + } + + getParentInstructions(instruction) { + let arr = [instruction]; + + if (!instruction.config.previousInstruction) { + return arr; + } + + let routes = this.router.routes; + let previousInstruction = routes.find(e => e.name === instruction.config.previousInstruction); + + if (!previousInstruction) { + return arr; + } + + previousInstruction.config = previousInstruction; + + return this.getParentInstructions(previousInstruction).concat(arr); + } +} \ No newline at end of file diff --git a/src/resources/elements/coming-soon/coming-soon.html b/src/resources/elements/coming-soon/coming-soon.html new file mode 100644 index 0000000..6ab6764 --- /dev/null +++ b/src/resources/elements/coming-soon/coming-soon.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/resources/elements/coming-soon/coming-soon.js b/src/resources/elements/coming-soon/coming-soon.js new file mode 100644 index 0000000..3453044 --- /dev/null +++ b/src/resources/elements/coming-soon/coming-soon.js @@ -0,0 +1,5 @@ +import { customElement } from "aurelia-framework"; + +@customElement("coming-soon") +export class ComingSoon { +} \ No newline at end of file diff --git a/src/resources/elements/pay-schedule-dropdown/pay-schedule-dropdown.html b/src/resources/elements/pay-schedule-dropdown/pay-schedule-dropdown.html new file mode 100644 index 0000000..8308f33 --- /dev/null +++ b/src/resources/elements/pay-schedule-dropdown/pay-schedule-dropdown.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/src/resources/elements/pay-schedule-dropdown/pay-schedule-dropdown.js b/src/resources/elements/pay-schedule-dropdown/pay-schedule-dropdown.js new file mode 100644 index 0000000..4358617 --- /dev/null +++ b/src/resources/elements/pay-schedule-dropdown/pay-schedule-dropdown.js @@ -0,0 +1,7 @@ +import { bindable, customElement } from "aurelia-framework"; + +@customElement("pay-schedule-dropdown") +export class PayScheduleDropdown { + @bindable payschedule = null; + @bindable payschedules = null; +} \ No newline at end of file diff --git a/src/resources/elements/request-indicator/request-indicator.html b/src/resources/elements/request-indicator/request-indicator.html new file mode 100644 index 0000000..4d47272 --- /dev/null +++ b/src/resources/elements/request-indicator/request-indicator.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/resources/elements/request-indicator/request-indicator.js b/src/resources/elements/request-indicator/request-indicator.js new file mode 100644 index 0000000..dbbefbf --- /dev/null +++ b/src/resources/elements/request-indicator/request-indicator.js @@ -0,0 +1,26 @@ +import { inject, customElement } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; + +@customElement("request-indicator") +@inject(EventAggregator) +export class RequestIndicator { + constructor(EventAggregator) { + this.ea = EventAggregator; + this.visible = false; + } + + attached() { + this.processingSubscriber = this.ea.subscribe("request:processing", () => { + this.visible = true; + }); + + this.completeSubscriber = this.ea.subscribe("request:complete", () => { + this.visible = false; + }); + } + + detached() { + this.processingSubscriber.dispose(); + this.completeSubscriber.dispose(); + } +} \ No newline at end of file diff --git a/src/resources/elements/router-progress-indicator/router-progress-indicator.html b/src/resources/elements/router-progress-indicator/router-progress-indicator.html new file mode 100644 index 0000000..41a40c8 --- /dev/null +++ b/src/resources/elements/router-progress-indicator/router-progress-indicator.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/resources/elements/router-progress-indicator/router-progress-indicator.js b/src/resources/elements/router-progress-indicator/router-progress-indicator.js new file mode 100644 index 0000000..25ec834 --- /dev/null +++ b/src/resources/elements/router-progress-indicator/router-progress-indicator.js @@ -0,0 +1,26 @@ +import { inject, customElement } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; +import * as nprogress from "nprogress"; + +@customElement("router-progress-indicator") +@inject(EventAggregator) +export class RouterProgressIndicator { + constructor(EventAggregator) { + this.ea = EventAggregator; + } + + attached() { + this.processingSubscriber = this.ea.subscribe("router:navigation:processing", () => { + nprogress.start(); + }); + + this.completeSubscriber = this.ea.subscribe("router:navigation:complete", () => { + nprogress.done(); + }); + } + + detached() { + this.processingSubscriber.dispose(); + this.completeSubscriber.dispose(); + } +} \ No newline at end of file diff --git a/src/resources/elements/rule-exclusions/rule-exclusions.html b/src/resources/elements/rule-exclusions/rule-exclusions.html new file mode 100644 index 0000000..cb78324 --- /dev/null +++ b/src/resources/elements/rule-exclusions/rule-exclusions.html @@ -0,0 +1,32 @@ + \ No newline at end of file diff --git a/src/resources/elements/rule-exclusions/rule-exclusions.js b/src/resources/elements/rule-exclusions/rule-exclusions.js new file mode 100644 index 0000000..e5d70a0 --- /dev/null +++ b/src/resources/elements/rule-exclusions/rule-exclusions.js @@ -0,0 +1,6 @@ +import { bindable, customElement } from "aurelia-framework"; + +@customElement("rule-exclusions") +export class RuleExclusions { + @bindable ruleexclusions = null; +} \ No newline at end of file diff --git a/src/resources/elements/status/status.html b/src/resources/elements/status/status.html new file mode 100644 index 0000000..a949878 --- /dev/null +++ b/src/resources/elements/status/status.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/src/resources/elements/status/status.js b/src/resources/elements/status/status.js new file mode 100644 index 0000000..bc8c4b0 --- /dev/null +++ b/src/resources/elements/status/status.js @@ -0,0 +1,26 @@ +import { inject, bindable, customElement } from "aurelia-framework"; +import { EventAggregator } from "aurelia-event-aggregator"; + +@customElement("status") +@inject(EventAggregator) +export class Status { + constructor(eventAggregator) { + this.ea = eventAggregator; + } + + @bindable status = null; + + viewJob() { + this.ea.publish("app:view-job", this.status.job); + } + + statusChanged() { + if (this.status) { + $("#status").fadeIn(); + + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + } +} \ No newline at end of file diff --git a/src/resources/elements/validation-errors/validation-errors.html b/src/resources/elements/validation-errors/validation-errors.html new file mode 100644 index 0000000..ee1420a --- /dev/null +++ b/src/resources/elements/validation-errors/validation-errors.html @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/src/resources/elements/validation-errors/validation-errors.js b/src/resources/elements/validation-errors/validation-errors.js new file mode 100644 index 0000000..4750e0b --- /dev/null +++ b/src/resources/elements/validation-errors/validation-errors.js @@ -0,0 +1,14 @@ +import { bindable, customElement } from "aurelia-framework"; + +@customElement("validation-errors") +export class ValidationErrors { + @bindable errors = null; + + errorsChanged() { + if (this.errors && this.errors.length > 0) { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + } +} \ No newline at end of file diff --git a/src/resources/index.js b/src/resources/index.js new file mode 100644 index 0000000..6b131cf --- /dev/null +++ b/src/resources/index.js @@ -0,0 +1,12 @@ +export function configure(config) { + config.globalResources([ + "./value-converters/address", + "./value-converters/bank-account", + "./value-converters/employee-name", + "./value-converters/extract-href", + "./value-converters/extract-id-from-link", + "./value-converters/format-salary", + "./value-converters/long-date-time", + "./value-converters/short-date", + ]); +} diff --git a/src/resources/value-converters/address.js b/src/resources/value-converters/address.js new file mode 100644 index 0000000..57a4435 --- /dev/null +++ b/src/resources/value-converters/address.js @@ -0,0 +1,18 @@ +export class AddressValueConverter { + toView(address) { + if (address) { + let parts = [ + address.Address1, + address.Address2, + address.Address3, + address.Address4, + address.Country, + address.Postcode + ].filter(part => part !== null && part !== undefined && part.trim().length > 0); + + return parts.join("
      "); + } + + return ""; + } +} \ No newline at end of file diff --git a/src/resources/value-converters/bank-account.js b/src/resources/value-converters/bank-account.js new file mode 100644 index 0000000..c6e1529 --- /dev/null +++ b/src/resources/value-converters/bank-account.js @@ -0,0 +1,15 @@ +export class BankAccountValueConverter { + toView(account) { + if (account) { + let parts = [ + account.AccountName, + account.AccountNumber, + account.SortCode + ].filter(part => part !== null && part !== undefined && part.trim().length > 0); + + return parts.join("
      "); + } + + return ""; + } +} \ No newline at end of file diff --git a/src/resources/value-converters/employee-name.js b/src/resources/value-converters/employee-name.js new file mode 100644 index 0000000..9e5fd0d --- /dev/null +++ b/src/resources/value-converters/employee-name.js @@ -0,0 +1,13 @@ +export class EmployeeNameValueConverter { + toView(employee) { + let firstname = employee.FirstName || employee.Initials; + + let parts = [ + employee.Title, + firstname, + employee.LastName + ].filter(part => part !== undefined && part !== null && part.trim().length > 0); + + return parts.join(" "); + } +} \ No newline at end of file diff --git a/src/resources/value-converters/extract-href.js b/src/resources/value-converters/extract-href.js new file mode 100644 index 0000000..6092b99 --- /dev/null +++ b/src/resources/value-converters/extract-href.js @@ -0,0 +1,5 @@ +export class ExtractHrefValueConverter { + toView(obj) { + return obj["@href"]; + } +} \ No newline at end of file diff --git a/src/resources/value-converters/extract-id-from-link.js b/src/resources/value-converters/extract-id-from-link.js new file mode 100644 index 0000000..97bb577 --- /dev/null +++ b/src/resources/value-converters/extract-id-from-link.js @@ -0,0 +1,8 @@ +export class ExtractIdFromLinkValueConverter { + toView(obj) { + let href = obj["@href"]; + let parts = href.split("/"); + + return parts[parts.length - 1]; + } +} \ No newline at end of file diff --git a/src/resources/value-converters/format-salary.js b/src/resources/value-converters/format-salary.js new file mode 100644 index 0000000..b93f919 --- /dev/null +++ b/src/resources/value-converters/format-salary.js @@ -0,0 +1,9 @@ +export class FormatSalaryValueConverter { + toView(obj) { + if (obj) { + return parseFloat(obj).toFixed(2); + } + + return ""; + } +} \ No newline at end of file diff --git a/src/resources/value-converters/long-date-time.js b/src/resources/value-converters/long-date-time.js new file mode 100644 index 0000000..ebb7480 --- /dev/null +++ b/src/resources/value-converters/long-date-time.js @@ -0,0 +1,11 @@ +const moment = require("moment"); + +export class LongDateTimeValueConverter { + toView(value) { + if (value) { + return moment(value).format("YYYY-MM-DD HH:mm:ss"); + } + + return ""; + } +} \ No newline at end of file diff --git a/src/resources/value-converters/short-date.js b/src/resources/value-converters/short-date.js new file mode 100644 index 0000000..462d9ad --- /dev/null +++ b/src/resources/value-converters/short-date.js @@ -0,0 +1,11 @@ +const moment = require("moment"); + +export class ShortDateValueConverter { + toView(value) { + if (value) { + return moment(value).format("YYYY-MM-DD"); + } + + return ""; + } +} \ No newline at end of file diff --git a/src/rti-transaction/rti-transaction-modal.html b/src/rti-transaction/rti-transaction-modal.html new file mode 100644 index 0000000..510835c --- /dev/null +++ b/src/rti-transaction/rti-transaction-modal.html @@ -0,0 +1,80 @@ + \ No newline at end of file diff --git a/src/rti-transaction/rti-transaction-modal.js b/src/rti-transaction/rti-transaction-modal.js new file mode 100644 index 0000000..ca5dac2 --- /dev/null +++ b/src/rti-transaction/rti-transaction-modal.js @@ -0,0 +1,45 @@ +import { inject } from "aurelia-framework"; +import { DialogController } from "aurelia-dialog"; +import { HttpClient } from "aurelia-http-client"; + +@inject(DialogController) +export class RtiTransactionModal { + constructor(dialogController) { + this.dialogController = dialogController; + this.client = new HttpClient(); + } + + activate(state) { + this.state = state; + this.state.PayRun = state.payRuns[0]; + this.state.LateReason = ""; + } + + save() { + let data = { + Generate: true, + Transmit: true, + PayScheduleId: this.state.PayRun.PayScheduleKey, + PayRunId: this.state.PayRun.PayRunKey, + HoldingDate: this.state.HoldingDate, + LateReason: this.state.LateReason + }; + + this.client.post(`/api/employer/${this.state.employerId}/rtiTransaction`, data).then(res => { + let parsedResponse = JSON.parse(res.response); + + this.apiErrors = null; + + if (parsedResponse.errors) { + this.apiErrors = parsedResponse.errors; + return; + } + + this.dialogController.ok(parsedResponse.status); + }); + } + + onLateReasonSelected(newValue) { + this.state.LateReason = newValue; + } +} \ No newline at end of file diff --git a/views/setup.hbs b/src/welcome/setup.html similarity index 64% rename from views/setup.hbs rename to src/welcome/setup.html index 66e6642..fd3dc6e 100644 --- a/views/setup.hbs +++ b/src/welcome/setup.html @@ -1,9 +1,9 @@ - - {{>status}} - - {{>validationErrors}} + \ No newline at end of file diff --git a/src/welcome/setup.js b/src/welcome/setup.js new file mode 100644 index 0000000..5f8db74 --- /dev/null +++ b/src/welcome/setup.js @@ -0,0 +1,51 @@ +import { inject } from "aurelia-framework"; +import { HttpClient } from "aurelia-http-client"; +import { ValidationControllerFactory, ValidationRules } from "aurelia-validation"; +import { Router } from "aurelia-router"; + +@inject(ValidationControllerFactory, Router) +export class Setup { + constructor(controllerFactory, router) { + this.controller = controllerFactory.createForCurrentScope(); + this.router = router; + this.client = new HttpClient(); + } + + activate() { + this.client.get("/api/setup").then(data => { + this.state = JSON.parse(data.response); + this.environments = ["Test", "Production"]; + + this.setupValidationRules(); + }); + } + + setupValidationRules() { + ValidationRules + .ensure("ConsumerSecret").required().withMessage("Consumer Secret is required") + .ensure("ConsumerKey").required().withMessage("Consumer Key is required") + .ensure("Environment").required().withMessage("Environment is required") + .on(this.state); + } + + save() { + let data = { + Environment: this.state.Environment, + ConsumerKey: this.state.ConsumerKey, + ConsumerSecret: this.state.ConsumerSecret + }; + + this.controller.validate().then(result => { + if (result.valid) { + this.client.post("/api/setup", data).then(() => { + this.router.navigate("employers"); + }); + } + else { + $("html, body, ux-dialog-container, ux-dialog, ux-dialog-body").animate({ + scrollTop: 0 + }, 500); + } + }); + } +} \ No newline at end of file diff --git a/views/index.hbs b/src/welcome/welcome.html similarity index 83% rename from views/index.hbs rename to src/welcome/welcome.html index 0cdb8cc..835afd6 100644 --- a/views/index.hbs +++ b/src/welcome/welcome.html @@ -1,5 +1,5 @@ -
      -

      Demo-UI Project

      + \ No newline at end of file diff --git a/src/welcome/welcome.js b/src/welcome/welcome.js new file mode 100644 index 0000000..a7a327b --- /dev/null +++ b/src/welcome/welcome.js @@ -0,0 +1,17 @@ +import { HttpClient } from "aurelia-http-client"; + +export class Welcome { + constructor() { + } + + activate() { + let client = new HttpClient(); + + client.get("/api/has-been-setup").then(data => { + this.state = JSON.parse(data.response); + }); + } + + deactivate() { + } +} \ No newline at end of file diff --git a/views/aurelia.hbs b/views/aurelia.hbs new file mode 100644 index 0000000..eed8889 --- /dev/null +++ b/views/aurelia.hbs @@ -0,0 +1,32 @@ + + + + + PayRun.io Demo + + + + + + + + + + + + + + + + + + +
      +
      + +
      +
      + + + + \ No newline at end of file diff --git a/views/download-p60.hbs b/views/download-p60.hbs deleted file mode 100644 index 24f83ec..0000000 --- a/views/download-p60.hbs +++ /dev/null @@ -1,19 +0,0 @@ - - {{>breadcrumbs}} - - {{>validationErrors}} - -
      - - - -
      - -
      -
      - -
      -
      - \ No newline at end of file diff --git a/views/employee.hbs b/views/employee.hbs deleted file mode 100644 index 9bc83da..0000000 --- a/views/employee.hbs +++ /dev/null @@ -1,150 +0,0 @@ -{{>breadcrumbs}} - -{{>status}} - -{{>validationErrors}} - -{{#if ShowTabs}} - - -
      -
      - {{>employeeForm}} -
      - -
      -
      -
      - -
      - - -
      - - {{#each GroupedPayInstructions}} -
      -
      -
      -
      -
      {{payInstructionFriendlyName InstructionType}}
      -
      -
      - {{payInstructionListPartial this ../this}} -
      -
      -
      -
      - {{/each}} -
      - -
      - {{>p45PayInstruction}} -
      - -
      -
      -
      - -
      - - -
      - - {{#each GroupedYTDPayInstructions}} -
      -
      -
      -
      -
      {{payInstructionFriendlyName InstructionType}}
      -
      -
      - {{payInstructionListPartial this ../this}} -
      -
      -
      -
      - {{/each}} -
      -
      -{{else}} - {{>employeeForm}} -{{/if}} - - \ No newline at end of file diff --git a/views/employeeLeaveDetails.hbs b/views/employeeLeaveDetails.hbs deleted file mode 100644 index e69de29..0000000 diff --git a/views/employer.hbs b/views/employer.hbs deleted file mode 100644 index df2541c..0000000 --- a/views/employer.hbs +++ /dev/null @@ -1,352 +0,0 @@ -{{>breadcrumbs}} - -{{>status}} - -{{>validationErrors}} - -{{#if ShowTabs}} - - -
      -
      - {{>employerForm}} -
      - -
      - - - {{#if Employees}} - - - - - - - - - - - - {{#each Employees}} - - - - - - - - {{/each}} - -
      CodeNameAddressBank Account
      - - {{this.Code}} - - {{employeeName this}}{{address this.Address}}{{bankAccount this.BankAccount}} - Add leaver details -
      - Download P45 -
      - Download P60 -
      - Delete -
      - {{/if}} -
      - -
      - - - {{#if PaySchedules.PaySchedulesTable.PaySchedule}} - - - - - - - - - - - - - - {{#each PaySchedules.PaySchedulesTable.PaySchedule}} - - - - - - - - - - {{/each}} - -
      IdNameFrequencyEmployeesLast Pay DayNext Pay Day
      - - {{this.Key}} - - {{this.Name}}{{this.PayFrequency}}{{this.EmployeeCount}} - {{#if this.LastPayDay}} - {{this.LastPayDay}} - {{else}} - Never - {{/if}} - - {{#if this.NextPayDay}} - {{this.NextPayDay}} - {{else}} - - - {{/if}} - - -
      - {{/if}} -
      - -
      - {{#canAddPayRun this}} - {{!--
      -
      -
      -
      --}} - {{else}} -
      -
      Pay Runs
      -
      -

      - Add a Pay Schedule and an Employee before starting a pay run. -

      -
      -
      - {{/canAddPayRun}} - -
      - - {{#each PaySchedules.PaySchedulesTable.PaySchedule}} -
      -
      -
      {{this.Name}}
      -
      -
      - {{#if this.PayRuns}} - - - - - - - - - - - - {{#each this.PayRuns}} - - - - - - - - {{/each}} - -
      Payment DateTax PeriodPay PeriodSupplementary - Add PayRun -
      - - {{formatDate this.PaymentDate}} - - {{this.TaxYear}}/{{this.TaxPeriod}}{{formatDate this.PeriodStart}} - {{formatDate this.PeriodEnd}}{{this.IsSupplementary}} - {{#ifCond ../HeadSequence this.Sequence this}} - - - {{/ifCond}} -
      - {{else}} -

      - There are currently no payruns for this pay schedule. - Add PayRun -

      - {{/if}} -
      -
      - {{/each}} -
      - -
      -
      - -
      - - {{#if Pensions}} - - - - - - - - - - - - {{#each Pensions}} - - - - - - - - {{/each}} - -
      IdSchemeProviderProvider Employer Ref
      - - {{this.Id}} - - {{this.SchemeName}}{{this.ProviderName}}{{this.ProviderEmployerRef}} - {{#unless this.UseForAutoEnrolment}} - - {{/unless}} - - -
      - {{/if}} -
      - -
      - {{#if PayRuns}} - - {{else}} -
      -
      RTI submissions
      -
      -

      - Start a new Pay Run before creating an RTI submission. -

      -
      -
      - {{/if}} - - {{#if RTITransactions}} - - - - - - - - - - - {{#each RTITransactions}} - - - - - - - {{/each}} - -
      IdTax YearTransmission DateTransaction Status
      - - {{this.Id}} - - {{TaxYear}}{{longDateTime TransmissionDate}}{{TransactionStatus}}
      - {{/if}} -
      - -
      -
      -

      Coming soon!

      -

      Check soon to see this functionality wired up with the API

      -
      -
      - -
      -{{else}} - {{>employerForm}} -{{/if}} - - - - \ No newline at end of file diff --git a/views/employers.hbs b/views/employers.hbs deleted file mode 100644 index 2b44020..0000000 --- a/views/employers.hbs +++ /dev/null @@ -1,90 +0,0 @@ - - -{{#if employers}} - - - - - - - - - - {{#each employers.EmployerTable.Employer}} - - - - - - {{/each}} - -
      NamePAYE RefPay Schedules -
      -
      -
      -
      - Name -
      -
      - Pay Frequency -
      -
      - Employees -
      -
      - Last Pay Date -
      -
      - Next Pay Date -
      -
      -
      -
      -
      - - {{this.Name}} - - {{this.TaxOfficeNumber}}/{{this.TaxOfficeReference}} - {{#if this.PaySchedule}} - {{#each this.PaySchedule}} -
      -
      -
      -
      - {{Name}} -
      -
      - {{PayFrequency}} -
      -
      - {{EmployeeCount}} -
      -
      - {{#if this.LastPayDay}} - {{this.LastPayDay}} - {{else}} - Never - {{/if}} -
      -
      - {{#if this.NextPayDay}} - {{this.NextPayDay}} - {{else}} - - - {{/if}} -
      -
      -
      -
      - {{/each}} - {{else}} - Add a Pay Schedule - {{/if}} -
      -{{/if}} \ No newline at end of file diff --git a/views/job-details.hbs b/views/job-details.hbs deleted file mode 100644 index 8119f50..0000000 --- a/views/job-details.hbs +++ /dev/null @@ -1,79 +0,0 @@ -{{>breadcrumbs}} - -
      - {{#if Errors}} -
      -
      - -
      -
      - {{/if}} - -
      -
      - Progress -
      - -
      -
      -
      -
      -
      -
      - -
      -
      -
      -
      - Status -
      - -
      - {{JobStatus}} -
      -
      - -
      -
      - Job Id -
      - -
      - {{JobId}} -
      -
      -
      - -
      -
      -
      - Last updated on -
      - -
      - {{longDateTime LastUpdated}} -
      -
      - -
      -
      - Created on -
      - -
      - {{longDateTime Created}} -
      -
      -
      -
      -
      \ No newline at end of file diff --git a/views/layouts/main.hbs b/views/layouts/main.hbs deleted file mode 100644 index c090c37..0000000 --- a/views/layouts/main.hbs +++ /dev/null @@ -1,102 +0,0 @@ - - - - {{title}} - - - - - - - - - - - - - - - - - - - -
      - -
      - -
      -
      -
      - {{{content}}} -
      -
      -
      - - - -
      -
      -
      -
      -
      -
      -
      -
      - API calls -
      - -
      - -
      -
      - -
      -
      - {{>apiCalls}} -
      -
      -
      -
      -
      - - {{>modal}} - - - - - - - - - - - \ No newline at end of file diff --git a/views/layouts/modal.hbs b/views/layouts/modal.hbs deleted file mode 100644 index af14dc2..0000000 --- a/views/layouts/modal.hbs +++ /dev/null @@ -1 +0,0 @@ -{{{content}}} diff --git a/views/partials/addressForm.hbs b/views/partials/addressForm.hbs deleted file mode 100644 index 7686455..0000000 --- a/views/partials/addressForm.hbs +++ /dev/null @@ -1,79 +0,0 @@ -

      Address

      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      -
      -
      - - - -
      -
      -
      -
      - - - -
      -
      -
      - - - diff --git a/views/partials/apiCalls.hbs b/views/partials/apiCalls.hbs deleted file mode 100644 index 24b7e07..0000000 --- a/views/partials/apiCalls.hbs +++ /dev/null @@ -1,3 +0,0 @@ -
      - - \ No newline at end of file diff --git a/views/partials/bankAccountForm.hbs b/views/partials/bankAccountForm.hbs deleted file mode 100644 index 10023ec..0000000 --- a/views/partials/bankAccountForm.hbs +++ /dev/null @@ -1,47 +0,0 @@ -

      Bank Account

      - -
      - - - -
      - -
      -
      -
      - - - -
      -
      -
      -
      - - - -
      -
      -
      - - - diff --git a/views/partials/breadcrumbs.hbs b/views/partials/breadcrumbs.hbs deleted file mode 100644 index 952b9fb..0000000 --- a/views/partials/breadcrumbs.hbs +++ /dev/null @@ -1,13 +0,0 @@ - \ No newline at end of file diff --git a/views/partials/comingSoon.hbs b/views/partials/comingSoon.hbs deleted file mode 100644 index 22a09e6..0000000 --- a/views/partials/comingSoon.hbs +++ /dev/null @@ -1,5 +0,0 @@ -
      -

      Coming soon!

      - -

      Check soon to see this functionality wired up with the API

      -
      \ No newline at end of file diff --git a/views/partials/employerForm.hbs b/views/partials/employerForm.hbs deleted file mode 100644 index 1cab65f..0000000 --- a/views/partials/employerForm.hbs +++ /dev/null @@ -1,421 +0,0 @@ -{{#if Id}} -
      -{{else}} - -{{/if}} - - - -
      - -
      - -
      -
      -
      - - -
      -
      -
      -
      - - -
      -
      -
      - -
      -
      -
      - - - - - - The Tax Office Number is the first part of your employer's PAYE reference issued by HMRC; it consists of 3 numbers. Required - to make RTI submissions. - -
      - -
      - - - - - - The Tax Office Reference is the second part of your employer's PAYE refernce issued by HMRC; it consists of up to 10 apha-numeric - charaters. Required to make RTI submissions. - -
      - -
      - - - - - - The Accounting Office Reference is issued by HMRC; typically it is found on employer's P30BC Employer Payment Booklet. Required - to make RTI submissions. - -
      - -
      - - - -
      - -
      - - - -
      - -
      -
      - {{> addressForm}} -
      -
      -
      - -
      -
      -
      - {{> bankAccountForm}} -
      -
      -
      - - - -
      -
      -
      -
      - -
      -
      -
      -
      - - - {{#select HmrcSettings.Sender}} - - {{/select}} - - The entity type that is making the RTI submission on behalf of the employer. Required to make - RTI submissions. -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      -
      -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - - - The designated HMRC contact person's email address; RTI submission acknowledgements will be sent - to this address. -
      - -
      - - - -
      - -
      - - - -
      -
      -
      -
      - -
      -
      -
      -
      -
      -
      - - - {{#select Territory}} - - {{/select}} -
      -
      -
      -
      - - - {{#select Region}} - - {{/select}} -
      -
      -
      - -
      - - - - - The apprenticeship levy will only apply to employers with annual paybill in excess of £3 million. -
      - - {{>ruleExclusions}} -
      -
      -
      - -
      -
      -
      -
      - - -
      - -
      - - -
      - -
      - - - - - The optional employers auto enrolment re-enrolment day offset. Allows the tri-annual re-enrolment to be offset by a number - of days. Supports positive and negative integers. - -
      - -
      - - - - - The optional employers auto enrolment re-enrolment month offset. Allows the tri-annual re-enrolment to be offset by a number - of months. Supports positive and negative integers. - -
      -
      -
      -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      -
      -
      -
      - -
      -
      -
      -
      - - - -
      - -
      Revision History
      - Employer revisions must be deleted in order, validation rules will prevent revisions being deleted if they invalidate an existing payrun. - - - - - - - - - - {{#each Revisions.EmployerRevisions.Revisions.Revision}} - - - - - - {{/each}} - -
      RevEffective Date
      {{Revision}}{{EffectiveDate}} - Delete -
      -
      -
      -
      - -
      -
      - -
      -
      -
      -
      \ No newline at end of file diff --git a/views/partials/modal.hbs b/views/partials/modal.hbs deleted file mode 100644 index 9315008..0000000 --- a/views/partials/modal.hbs +++ /dev/null @@ -1,17 +0,0 @@ - \ No newline at end of file diff --git a/views/partials/p45PayInstruction.hbs b/views/partials/p45PayInstruction.hbs deleted file mode 100644 index 813eb45..0000000 --- a/views/partials/p45PayInstruction.hbs +++ /dev/null @@ -1,200 +0,0 @@ -
      -
      - -
      -
      - -
      -
      -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      - -
      - - - - - - The year to date taxable pay from the previous employment. - -
      - -
      - - - - - - The year to date tax paid from the previous employment. - -
      - -
      - - - - - - The tax code from the previous employment. - -
      -
      - -
      -
      - - - {{#select P45PayInstruction.TaxBasis}} - - {{/select}} -
      - -
      - - - {{#select P45PayInstruction.StudentLoan}} - - {{/select}} -
      - -
      - - - {{#select P45PayInstruction.PayFrequency}} - - {{/select}} -
      - -
      - - - - - - The leaving date from the previous employment. - -
      - -
      - - - - - - The previous employer's PAYE scheme reference if known. - -
      -
      -
      - -
      -
      - -
      - -
      - -
      -
      -
      -
      - - \ No newline at end of file diff --git a/views/partials/payInstructions/forms/AoePayInstruction.hbs b/views/partials/payInstructions/forms/AoePayInstruction.hbs deleted file mode 100644 index ede6bde..0000000 --- a/views/partials/payInstructions/forms/AoePayInstruction.hbs +++ /dev/null @@ -1,258 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - - - - The attachment of earnings case number. Used to uniquely identify the attachment order. - -
      - -
      - - - {{#select AoeType}} - - {{/select}} -
      - -
      - - - - - - The issue date. The date when the attachment comes into affect. - -
      - -
      - - - - - - The stop date. The optional date when the attachment ends. - -
      - -
      - - - -
      - -
      - - - - - - The starting amount already paid. Used when the instruction - started partway through the attachment. For example: when an employee - starts a new job part way through the attachment period and - has already made historic payments. - -
      -
      - -
      -
      - - - - - - The starting amount owed in arrears. Used when the - instruction started partway through the attachment. For example: - when an employee starts a new job part way through the attachment - period and has arrears to be settled. - -
      - -
      - - - -
      - -
      - - - - - - The protected earnings amount. Indicates the amount of earnings - that cannot be collected in repayment of the attachment. - -
      - -
      - - - - - - The deduction amount. Indicates the fixed amount to be collected in repayment of attachment. - -
      - -
      - - - - - - The protected earnings percentage. Indicates the percentage of - earnings that cannot be collected in repayment of attachment. - -
      - -
      - - - - - - The deduction percentage. Indicates the percentage amount to be collected in repayment of the attachment. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/BenefitPayInstruction.hbs b/views/partials/payInstructions/forms/BenefitPayInstruction.hbs deleted file mode 100644 index 1e6254d..0000000 --- a/views/partials/payInstructions/forms/BenefitPayInstruction.hbs +++ /dev/null @@ -1,139 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - - - The code that represents the benefit type and it's treatment. - -
      - -
      - - - - - The total cost (or value) of the benefit for the remainder of the financial year. - -
      -
      - -
      -
      - - - - - The amount the employee contributes towards the benefit for the rest of the financial year. - -
      - -
      - - - - - The per period cash equivalent value of the benefit.
      - [Optional] used to override the calculated cash equivilent value. -
      -
      - -
      - - - {{#select AccountingMethod}} - - {{/select}} - - - The accounting method used to report the benefit to HMRC. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/NiAdjustmentPayInstruction.hbs b/views/partials/payInstructions/forms/NiAdjustmentPayInstruction.hbs deleted file mode 100644 index 20afb5b..0000000 --- a/views/partials/payInstructions/forms/NiAdjustmentPayInstruction.hbs +++ /dev/null @@ -1,146 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - {{#select DirCalculationMethod}} - - {{/select}} - - - The calculation method to be used when treating and employee as a director. - See employees as directors for more information. - -
      - -
      - - - {{#select NiLetter}} - - {{/select}} - - - The employee's NI letter category. - See using the correct NI letter for more information. - -
      -
      - -
      -
      - - - - - - The affected periods the adjustment applies to as a comma separated list. - -
      - -
      - - - {{#select TaxYear}} - - {{/select}} -
      - -
      - - - - - - An optional description for reasons why the adjustment was made. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/NiPayInstruction.hbs b/views/partials/payInstructions/forms/NiPayInstruction.hbs deleted file mode 100644 index 0926985..0000000 --- a/views/partials/payInstructions/forms/NiPayInstruction.hbs +++ /dev/null @@ -1,99 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - {{#select DirCalculationMethod}} - - {{/select}} - - - The calculation method to be used when treating and employee as a director. - See employees as directors for more information. - -
      -
      - -
      -
      - - - {{#select NiLetter}} - - {{/select}} - - - The employee's NI letter category. - See using the correct NI letter for more information. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/PensionPayInstruction.hbs b/views/partials/payInstructions/forms/PensionPayInstruction.hbs deleted file mode 100644 index dcafef1..0000000 --- a/views/partials/payInstructions/forms/PensionPayInstruction.hbs +++ /dev/null @@ -1,273 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - - - - The payment code override. If omitted; use value defined in pension scheme. - -
      - -
      - - - - - - A link to the related pension scheme. - -
      - -
      - - - - - - The employee cash contribution amount override. If omitted; use value defined in pension scheme. - -
      - -
      - - - - - - The employer cash contribution amount override. If omitted; use value defined in pension scheme. - -
      - -
      - - - - - - The employee contribution percentage override. If omitted; use value defined in pension scheme. - -
      - -
      - - - - - - The employer contribution percentage override. If omitted; use value defined in pension scheme. - -
      -
      - -
      -
      - - - - - - The employee additional voluntary cash contribution amount. - -
      - -
      - - - - - - The employee additional voluntary contribution percentage amount. - -
      - -
      - - - - - - The lower contribution cut off threshold. If specified; contributions will - only be calculated on pensionable pay exceeding the thresh hold. If omitted; - use value defined in pension scheme. - -
      - -
      - - - - - - The upper contribution cut off threshold. If specified; contributions will only - be calculated on pensionable pay below the thresh hold. If omitted; use value - defined in pension scheme. - -
      - -
      - - - - - - Determines if the contributions are calculated using the salary sacrifice method. If omitted; use value defined in pension scheme. - -
      - -
      - - - {{#select TaxationMethod}} - - {{/select}} - - - The pension calculation taxation method override. If omitted; use value defined in pension scheme. - -
      - -
      - - - {{#select ProRataMethod}} - - {{/select}} - - - The pro-rata method option to be used. If omitted; use the value defined in the pension scheme. - See Pro-rata Calculation Methods for more information. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/PrimitivePayInstruction.hbs b/views/partials/payInstructions/forms/PrimitivePayInstruction.hbs deleted file mode 100644 index 917efb0..0000000 --- a/views/partials/payInstructions/forms/PrimitivePayInstruction.hbs +++ /dev/null @@ -1,87 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - - - The code that represents the benefit type and it's treatment. - -
      -
      - -
      -
      - - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/RatePayInstruction.hbs b/views/partials/payInstructions/forms/RatePayInstruction.hbs deleted file mode 100644 index 755fd48..0000000 --- a/views/partials/payInstructions/forms/RatePayInstruction.hbs +++ /dev/null @@ -1,116 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - -
      - -
      - - - - - The payment code override. If omitted; the BASIC payment code is used. - -
      -
      - -
      -
      - - - {{#select RateUoM}} - - {{/select}} -
      - -
      - - - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/SalaryPayInstruction.hbs b/views/partials/payInstructions/forms/SalaryPayInstruction.hbs deleted file mode 100644 index e7613a6..0000000 --- a/views/partials/payInstructions/forms/SalaryPayInstruction.hbs +++ /dev/null @@ -1,89 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - -
      -
      - -
      -
      - - - {{#select ProRataMethod}} - - {{/select}} - - - The pro-rata method option to be used; the default is not set. - See Pro-rata Calculation Methods for more information. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/ShppPayInstruction.hbs b/views/partials/payInstructions/forms/ShppPayInstruction.hbs deleted file mode 100644 index d82d64d..0000000 --- a/views/partials/payInstructions/forms/ShppPayInstruction.hbs +++ /dev/null @@ -1,170 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - - - Optional override value to the Average Weekly Earnings calculation. - If this value is set then the calculated value is ignored. - -
      - -
      - - - - - The start date of the employee absence. - -
      - -
      - - - - - The end date of the employee absence, leave blank if the absence is long-term and the end date is not known. - -
      - -
      - - - - - - Flag to indicate if the statutory payment should be offset. - -
      -
      - -
      -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/SmpPayInstruction.hbs b/views/partials/payInstructions/forms/SmpPayInstruction.hbs deleted file mode 100644 index 5042992..0000000 --- a/views/partials/payInstructions/forms/SmpPayInstruction.hbs +++ /dev/null @@ -1,9 +0,0 @@ -
      -
      -
      -

      Coming soon!

      - -

      Check soon to see this functionality wired up with the API

      -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/SspPayInstruction.hbs b/views/partials/payInstructions/forms/SspPayInstruction.hbs deleted file mode 100644 index d63df10..0000000 --- a/views/partials/payInstructions/forms/SspPayInstruction.hbs +++ /dev/null @@ -1,109 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - - - Optional override value to the Average Weekly Earnings calculation. - If this value is set then the calculated value is ignored. - -
      - -
      - - - - - The start date of the employee absence. - -
      -
      - -
      -
      - - - - - The end date of the employee absence, leave blank if the absence is long-term and the end date is not known. - -
      - -
      - - - - - - Flag to indicate if the statutory payment should be offset. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/StudentLoanPayInstruction.hbs b/views/partials/payInstructions/forms/StudentLoanPayInstruction.hbs deleted file mode 100644 index 02fd679..0000000 --- a/views/partials/payInstructions/forms/StudentLoanPayInstruction.hbs +++ /dev/null @@ -1,71 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      -
      - -
      -
      - - - {{#select StudentLoanCalculationMethod}} - - {{/select}} -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/TaxPayInstruction.hbs b/views/partials/payInstructions/forms/TaxPayInstruction.hbs deleted file mode 100644 index 0ec01a7..0000000 --- a/views/partials/payInstructions/forms/TaxPayInstruction.hbs +++ /dev/null @@ -1,85 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - {{#select ProRataMethod}} - - {{/select}} - - - The tax basis to be used for the employee's tax calculations. - -
      -
      - -
      -
      - - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/NiYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/NiYtdPayInstruction.hbs deleted file mode 100644 index db1e12a..0000000 --- a/views/partials/payInstructions/forms/yearToDate/NiYtdPayInstruction.hbs +++ /dev/null @@ -1,300 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - {{#select NiLetter}} - - {{/select}} -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      -
      - -
      -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - {{#select DirCalculationMethod}} - - {{/select}} -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/PensionYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/PensionYtdPayInstruction.hbs deleted file mode 100644 index 15e2940..0000000 --- a/views/partials/payInstructions/forms/yearToDate/PensionYtdPayInstruction.hbs +++ /dev/null @@ -1,164 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - - - The total amount of pensionable pay. -
      - -
      - - - - - - The employee contribution amount. - -
      -
      - -
      -
      - - - - - - The employer contribution amount. - -
      - -
      - - - - - - The code that represents the pension payment code. - -
      - -
      - - - - - - The related pension scheme. - -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/PrimitiveYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/PrimitiveYtdPayInstruction.hbs deleted file mode 100644 index b5f6f78..0000000 --- a/views/partials/payInstructions/forms/yearToDate/PrimitiveYtdPayInstruction.hbs +++ /dev/null @@ -1,102 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      -
      - -
      -
      - - - -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/SapYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/SapYtdPayInstruction.hbs deleted file mode 100644 index 1d4ac01..0000000 --- a/views/partials/payInstructions/forms/yearToDate/SapYtdPayInstruction.hbs +++ /dev/null @@ -1,163 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      -
      - -
      -
      - - - -
      - -
      - - - -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      - -
      -
      -
      -
      - -
      -
      - -
      - -
      -
      - -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/ShppYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/ShppYtdPayInstruction.hbs deleted file mode 100644 index 5ef9dd2..0000000 --- a/views/partials/payInstructions/forms/yearToDate/ShppYtdPayInstruction.hbs +++ /dev/null @@ -1,141 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      -
      - -
      -
      - - - -
      - -
      - - - -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/SmpYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/SmpYtdPayInstruction.hbs deleted file mode 100644 index 1d4ac01..0000000 --- a/views/partials/payInstructions/forms/yearToDate/SmpYtdPayInstruction.hbs +++ /dev/null @@ -1,163 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      -
      - -
      -
      - - - -
      - -
      - - - -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      - -
      -
      -
      -
      - -
      -
      - -
      - -
      -
      - -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/SppYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/SppYtdPayInstruction.hbs deleted file mode 100644 index 3106907..0000000 --- a/views/partials/payInstructions/forms/yearToDate/SppYtdPayInstruction.hbs +++ /dev/null @@ -1,141 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      -
      - -
      -
      - - - -
      - -
      - - - -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/SspYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/SspYtdPayInstruction.hbs deleted file mode 100644 index 204c3b8..0000000 --- a/views/partials/payInstructions/forms/yearToDate/SspYtdPayInstruction.hbs +++ /dev/null @@ -1,169 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      -
      - -
      -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/StudentLoanYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/StudentLoanYtdPayInstruction.hbs deleted file mode 100644 index ce8cb8a..0000000 --- a/views/partials/payInstructions/forms/yearToDate/StudentLoanYtdPayInstruction.hbs +++ /dev/null @@ -1,102 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      - -
      - - - {{#select StudentLoanCalculationMethod}} - - {{/select}} -
      -
      - -
      -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/forms/yearToDate/TaxYtdPayInstruction.hbs b/views/partials/payInstructions/forms/yearToDate/TaxYtdPayInstruction.hbs deleted file mode 100644 index 51b1c03..0000000 --- a/views/partials/payInstructions/forms/yearToDate/TaxYtdPayInstruction.hbs +++ /dev/null @@ -1,131 +0,0 @@ -
      -
      -
      - - - - - - The date the instruction will come into effect. - -
      - -
      - - - - - - The date the instruction will end, open ended instructions will run forever. - -
      - -
      - - - -
      - -
      - - - -
      -
      - -
      -
      - - - -
      - -
      - - - {{#select TaxBasis}} - - {{/select}} -
      - -
      - - - - - - Indicates if the instruction is an adjustment. Pay lines - generated from adjustment YTD instructions appear on the employee pay slip. - -
      - -
      - - - - - - This description will override the default description from the pay code. - See Customising the Payslip for more information on customising the payslip output and using runtime variables. - -
      -
      -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/AoePayInstruction.hbs b/views/partials/payInstructions/lists/AoePayInstruction.hbs deleted file mode 100644 index 6f7bcd8..0000000 --- a/views/partials/payInstructions/lists/AoePayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdCase NumberTypeStart DateEnd DateDescription
      - - {{this.Id}} - - - {{this.CaseNumber}} - - {{this.Code}} - - {{this.StartDate}} - - {{this.EndDate}} - - {{this.Description}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/BenefitPayInstruction.hbs b/views/partials/payInstructions/lists/BenefitPayInstruction.hbs deleted file mode 100644 index 1899e90..0000000 --- a/views/partials/payInstructions/lists/BenefitPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdCodeTotal CostEmployee ContributionStart DateEnd Date
      - - {{this.Id}} - - - {{this.Code}} - - {{fixedDecimal this.TotalCost 2}} - - {{fixedDecimal this.EmployeeContribution 2}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/NiAdjustmentPayInstruction.hbs b/views/partials/payInstructions/lists/NiAdjustmentPayInstruction.hbs deleted file mode 100644 index 3503754..0000000 --- a/views/partials/payInstructions/lists/NiAdjustmentPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdPeriodsNI LetterStart DateEnd DateDescription
      - - {{this.Id}} - - - {{this.Periods}} - - {{this.NiLetter}} - - {{this.StartDate}} - - {{this.EndDate}} - - {{this.Description}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/NiPayInstruction.hbs b/views/partials/payInstructions/lists/NiPayInstruction.hbs deleted file mode 100644 index 1b6eed5..0000000 --- a/views/partials/payInstructions/lists/NiPayInstruction.hbs +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - {{/each}} - -
      IdNI TableStart DateEnd DateDescription
      - - {{this.Id}} - - - {{this.NiLetter}} - - {{this.StartDate}} - - {{this.EndDate}} - - {{this.Description}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/PensionPayInstruction.hbs b/views/partials/payInstructions/lists/PensionPayInstruction.hbs deleted file mode 100644 index 011ea9d..0000000 --- a/views/partials/payInstructions/lists/PensionPayInstruction.hbs +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdPensionEmployee ContributionEmployer ContributionSalary Sacrifice?Taxation Method
      - - {{this.Id}} - - - - {{extractIdFromLink this.Pension}} - - - {{getPensionContribution this.EmployeeContributionCash this.EmployeeContributionPercent}} - - {{getPensionContribution this.EmployerContributionCash this.EmployerContributionPercent}} - - - - {{this.TaxationMethod}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/PrimitivePayInstruction.hbs b/views/partials/payInstructions/lists/PrimitivePayInstruction.hbs deleted file mode 100644 index 088cdf6..0000000 --- a/views/partials/payInstructions/lists/PrimitivePayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdCodeValueStart DateEnd DateDescription
      - - {{this.Id}} - - - {{this.Code}} - - {{fixedDecimal this.Value 2}} - - {{this.StartDate}} - - {{this.EndDate}} - - {{this.Description}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/RatePayInstruction.hbs b/views/partials/payInstructions/lists/RatePayInstruction.hbs deleted file mode 100644 index 0d1c211..0000000 --- a/views/partials/payInstructions/lists/RatePayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdRateUnitsStart DateEnd DateDescription
      - - {{this.Id}} - - - {{fixedDecimal this.Rate 2}} - - {{fixedDecimal this.Units 2}} - - {{this.StartDate}} - - {{this.EndDate}} - - {{this.Description}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/SalaryPayInstruction.hbs b/views/partials/payInstructions/lists/SalaryPayInstruction.hbs deleted file mode 100644 index de181b2..0000000 --- a/views/partials/payInstructions/lists/SalaryPayInstruction.hbs +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - {{/each}} - -
      IdSalaryStart DateEnd DateDescription
      - - {{this.Id}} - - - {{formatSalary this.AnnualSalary}} - - {{this.StartDate}} - - {{this.EndDate}} - - {{this.Description}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/ShppPayInstruction.hbs b/views/partials/payInstructions/lists/ShppPayInstruction.hbs deleted file mode 100644 index 26e5835..0000000 --- a/views/partials/payInstructions/lists/ShppPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdDue DateBorn DateAbsence StartAbsence EndStatutory Offset?
      - - {{this.Id}} - - - {{this.BabyDueDate}} - - {{this.BabyBornDate}} - - {{this.AbsenceStart}} - - {{this.AbsenceEnd}} - - {{this.StatutoryOffset}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/SspPayInstruction.hbs b/views/partials/payInstructions/lists/SspPayInstruction.hbs deleted file mode 100644 index a1bb41f..0000000 --- a/views/partials/payInstructions/lists/SspPayInstruction.hbs +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - {{/each}} - -
      IdAbsence StartAbsence EndStatutory Offset?
      - - {{this.Id}} - - - {{this.AbsenceStart}} - - {{this.AbsenceEnd}} - - {{this.StatutoryOffset}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/StudentLoanPayInstruction.hbs b/views/partials/payInstructions/lists/StudentLoanPayInstruction.hbs deleted file mode 100644 index fc5cc07..0000000 --- a/views/partials/payInstructions/lists/StudentLoanPayInstruction.hbs +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - {{/each}} - -
      IdCalculation MethodStart DateEnd DateDescription
      - - {{this.Id}} - - - {{this.StudentLoanCalculationMethod}} - - {{this.StartDate}} - - {{this.EndDate}} - - {{this.Description}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/TaxPayInstruction.hbs b/views/partials/payInstructions/lists/TaxPayInstruction.hbs deleted file mode 100644 index 70e8b09..0000000 --- a/views/partials/payInstructions/lists/TaxPayInstruction.hbs +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - {{/each}} - -
      IdTax codeStart DateEnd DateDescription
      - - {{this.Id}} - - - {{this.TaxCode}} - - {{this.StartDate}} - - {{this.EndDate}} - - {{this.Description}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/NiYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/NiYtdPayInstruction.hbs deleted file mode 100644 index 4e2dad0..0000000 --- a/views/partials/payInstructions/lists/yearToDate/NiYtdPayInstruction.hbs +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - - {{/each}} - -
      IdValueEmployer NINiable PayNI LetterStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{formatSalary this.EmployerNI}} - - {{formatSalary this.NiablePay}} - - {{this.NiLetter}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/PensionYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/PensionYtdPayInstruction.hbs deleted file mode 100644 index 16edd91..0000000 --- a/views/partials/payInstructions/lists/yearToDate/PensionYtdPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdPensionable PayEmployer ContributionCodeStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.PensionablePay}} - - {{formatSalary this.EmployerContribution}} - - {{this.Code}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/PrimitiveYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/PrimitiveYtdPayInstruction.hbs deleted file mode 100644 index 8826d6b..0000000 --- a/views/partials/payInstructions/lists/yearToDate/PrimitiveYtdPayInstruction.hbs +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - {{/each}} - -
      IdValueStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/SapYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/SapYtdPayInstruction.hbs deleted file mode 100644 index 6fb50dc..0000000 --- a/views/partials/payInstructions/lists/yearToDate/SapYtdPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdValueAbsence StartAbsence EndStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{this.AbsenceStart}} - - {{this.AbsenceEnd}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/ShppYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/ShppYtdPayInstruction.hbs deleted file mode 100644 index 5941099..0000000 --- a/views/partials/payInstructions/lists/yearToDate/ShppYtdPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdValueAbsence StartAbsence EndStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{this.AbsenceStart}} - - {{this.AbsenceEnd}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/SmpYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/SmpYtdPayInstruction.hbs deleted file mode 100644 index 802b269..0000000 --- a/views/partials/payInstructions/lists/yearToDate/SmpYtdPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdValueAbsence StartAbsence EndStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{this.AbsenceStart}} - - {{this.AbsenceEnd}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/SppYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/SppYtdPayInstruction.hbs deleted file mode 100644 index 7c4a15c..0000000 --- a/views/partials/payInstructions/lists/yearToDate/SppYtdPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdValueAbsence StartAbsence EndStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{this.AbsenceStart}} - - {{this.AbsenceEnd}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/SspYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/SspYtdPayInstruction.hbs deleted file mode 100644 index c48138c..0000000 --- a/views/partials/payInstructions/lists/yearToDate/SspYtdPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdValueAbsence StartAbsence EndStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{this.AbsenceStart}} - - {{this.AbsenceEnd}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/StudentLoanYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/StudentLoanYtdPayInstruction.hbs deleted file mode 100644 index 06b573f..0000000 --- a/views/partials/payInstructions/lists/yearToDate/StudentLoanYtdPayInstruction.hbs +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - {{/each}} - -
      IdValueCalculation MethodStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{this.StudentLoanCalculationMethod}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payInstructions/lists/yearToDate/TaxYtdPayInstruction.hbs b/views/partials/payInstructions/lists/yearToDate/TaxYtdPayInstruction.hbs deleted file mode 100644 index ca846c3..0000000 --- a/views/partials/payInstructions/lists/yearToDate/TaxYtdPayInstruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - {{#each Instructions}} - - - - - - - - - - {{/each}} - -
      IdValueTaxable PayTax CodeStart DateEnd Date
      - - {{this.Id}} - - - {{formatSalary this.Value}} - - {{formatSalary this.TaxablePay}} - - {{this.TaxCode}} - - {{this.StartDate}} - - {{this.EndDate}} - - -
      \ No newline at end of file diff --git a/views/partials/payScheduleDropdown.hbs b/views/partials/payScheduleDropdown.hbs deleted file mode 100644 index 595fe37..0000000 --- a/views/partials/payScheduleDropdown.hbs +++ /dev/null @@ -1,15 +0,0 @@ -
      - - - -
      \ No newline at end of file diff --git a/views/partials/ruleExclusions.hbs b/views/partials/ruleExclusions.hbs deleted file mode 100644 index afbfb17..0000000 --- a/views/partials/ruleExclusions.hbs +++ /dev/null @@ -1,27 +0,0 @@ -
      - - - {{#multipleSelect RuleExclusions}} - - {{/multipleSelect}} - - - The list of pre-claculation rules to exclude by default for all employees. - See Pre-calculation rules for more information on how they work. - -
      \ No newline at end of file diff --git a/views/partials/status.hbs b/views/partials/status.hbs deleted file mode 100644 index bdcfc4f..0000000 --- a/views/partials/status.hbs +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/views/partials/validationErrors.hbs b/views/partials/validationErrors.hbs deleted file mode 100644 index 5382d63..0000000 --- a/views/partials/validationErrors.hbs +++ /dev/null @@ -1,13 +0,0 @@ - \ No newline at end of file diff --git a/views/pay-instruction.hbs b/views/pay-instruction.hbs deleted file mode 100644 index fe151ba..0000000 --- a/views/pay-instruction.hbs +++ /dev/null @@ -1,27 +0,0 @@ -{{#if Id}} -
      -{{else}} - -{{/if}} - - {{>validationErrors}} - - {{#if EnableForm}} - {{payInstructionPartial this}} - {{else}} -
      -
      Instructions
      -
      -

      - Add an End Date against all existing Instructions of this type before adding a new instruction. -

      -
      -
      - {{/if}} - - - - -
      - - \ No newline at end of file diff --git a/views/pay-run-creation.hbs b/views/pay-run-creation.hbs deleted file mode 100644 index f485d92..0000000 --- a/views/pay-run-creation.hbs +++ /dev/null @@ -1,68 +0,0 @@ -
      - - {{>validationErrors}} - - {{#if this.Status}} -

      {{this.Status}}

      - {{/if}} - -
      -
      - {{#if this.PayScheduleId}} - - {{else}} -
      - - -
      - {{/if}} - -
      - - - - The date you wish to appear on the employee's payslip (aka pay day). -
      - -
      -
      -
      - - -
      -
      -
      -
      - - -
      -
      -
      -
      -
      -
      \ No newline at end of file diff --git a/views/pay-run.hbs b/views/pay-run.hbs deleted file mode 100644 index 952437a..0000000 --- a/views/pay-run.hbs +++ /dev/null @@ -1,118 +0,0 @@ -{{>breadcrumbs}} - -
      -
      -
      -
      -
      - Pay Schedule -
      - -
      - {{PaySchedule.Name}} -
      -
      - -
      -
      - Pay Frequency -
      - -
      - {{PaySchedule.PayFrequency}} -
      -
      -
      - -
      -
      -
      - Payment Date -
      - -
      - {{PaymentDate}} -
      -
      - -
      -
      - Tax Year / Period -
      - -
      - {{TaxYear}}/{{TaxPeriod}} -
      -
      -
      - -
      -
      -
      - Period start -
      - -
      - {{PeriodStart}} -
      -
      - -
      -
      - Period end -
      - -
      - {{PeriodEnd}} -
      -
      -
      -
      - -
      -
      - {{#if Employees}} -

      Employees

      - - - - - - - - - - - - - - - - {{#each Employees}} - - - - - - - - - - - {{/each}} - -
      NamePaymentsTaxEE NIER NIOther DeducsNet Pay
      - {{Name}} - {{PAYMENTS}}{{TAX}}{{EE_NI}}{{ER_NI}}{{OTHERDEDNS}}{{NETPAY}} - Payslip -  |  - {{#if Commentary}} - Commentary - {{/if}} -
      - {{/if}} -
      -
      -
      \ No newline at end of file diff --git a/views/pay-schedule.hbs b/views/pay-schedule.hbs deleted file mode 100644 index fffaafb..0000000 --- a/views/pay-schedule.hbs +++ /dev/null @@ -1,42 +0,0 @@ -{{#if Id}} -
      -{{else}} - -{{/if}} - - {{>validationErrors}} - -
      - - -
      - -
      - - - {{#select PayFrequency}} - - {{/select}} -
      - -
      -
      - -
      -
      - -
      \ No newline at end of file diff --git a/views/pension.hbs b/views/pension.hbs deleted file mode 100644 index cf6310b..0000000 --- a/views/pension.hbs +++ /dev/null @@ -1,314 +0,0 @@ -{{#if Id}} -
      -{{else}} - -{{/if}} - - {{>breadcrumbs}} - - {{>status}} - - {{>validationErrors}} - - - -
      - -
      - -
      - -
      -
      - - - - Allows an override of the default pay code used by the pension scheme. -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - -
      - -
      - - - - A decimal fraction between 0 and 1. Represents a percentage as a fraction of the number 1. -
      - -
      - - - - A decimal fraction between 0 and 1. Represents a percentage as a fraction of the number 1. -
      -
      - -
      -
      - - - - - The lower earning threshold; only pensionable pay above this value will be included for calculating contributions. - Thresholds are predominantly used for triggering Auto Enrolment contributions; see Auto Enrolment for more information. - -
      - -
      - - - - - The upper earning threshold; only pensionable pay above this value will be included for calculating contributions. - Thresholds are predominantly used for triggering Auto Enrolment contributions; see Auto Enrolment for more information. - -
      - -
      - - - {{#select TaxationMethod}} - - {{/select}} - - - The taxation method to use when calculating pension contributions; this should be mandated by your pension provider. - -
      - -
      - - - -
      - -
      - - - - - - The salary sacrifice option. Used to indicate if the pension scheme employee contributions should make use of salary sacrifice. - -
      - -
      - - - {{#select ProRataMethod}} - - {{/select}} - - - The pro-rata method option to be used; the default is not set. - See Pro-rata Calculation Methods for more information. - -
      - -
      - - - - - - The Auto Enrolment compatibility indicator. Used to indicate if this pension scheme is compatible with auto enrolment requirements. - -
      - -
      - - - - - - The Use Auto Enrolment Thresholds indicator. Used to indicate if this pension scheme uses the auto enrolment thresholds. - -
      -
      -
      - -
      - -
      - -
      - -
      - -
      - - -
      - -
      - -
      - -
      - - -
      - -
      - -
      - -
      -
      -
      -
      - -
      -
      -
      - - - \ No newline at end of file diff --git a/views/rti-instruction.hbs b/views/rti-instruction.hbs deleted file mode 100644 index 5ade166..0000000 --- a/views/rti-instruction.hbs +++ /dev/null @@ -1,48 +0,0 @@ -
      - - {{>validationErrors}} - - - - -
      - -
      - -
      - - - -
      - -
      - - - - Optional date, used to defer execution of the job until a future point in time. -
      - -
      - - - - - If applicable, the reason given for a late submission. -
      -
      -
      - -
      \ No newline at end of file