@@ -244,6 +250,16 @@
+
+
+
+
+
@@ -310,6 +326,7 @@ import LanguagesForm from './LanguagesForm.vue';
import PersonalInfoForm from './PersonalInfoForm.vue';
import TechnologiesForm from './TechnologiesForm.vue';
import EmergencyContactsForm from './EmergencyContactsForm.vue';
+import IntegrationDataForm from './IntegrationDataForm.vue';
import SubmitButton from '@/components/shared/buttons/SubmitButton.vue';
// |--------------------------------------------------|
@@ -350,7 +367,8 @@ const validTabs = reactive({
languages: true,
personal: true,
technologies: true,
- emergencyContacts: true
+ emergencyContacts: true,
+ integration: true,
});
// template refs
@@ -690,6 +708,10 @@ async function selectTab() {
num = 9;
card = 'Emergency Contacts';
break;
+ case 'Integrations':
+ num = 10;
+ card = 'Integrations'
+ break;
default:
num = 0;
card = 'Personal';
diff --git a/src/components/employee-beta/forms/IntegrationDataForm.vue b/src/components/employee-beta/forms/IntegrationDataForm.vue
new file mode 100644
index 000000000..0e6ef1ace
--- /dev/null
+++ b/src/components/employee-beta/forms/IntegrationDataForm.vue
@@ -0,0 +1,102 @@
+
+
+
Unanet
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/expense-types/forms/sections/Integrations.vue b/src/components/expense-types/forms/sections/Integrations.vue
index f72810e8b..f92c427f7 100644
--- a/src/components/expense-types/forms/sections/Integrations.vue
+++ b/src/components/expense-types/forms/sections/Integrations.vue
@@ -13,26 +13,65 @@
item-value="url"
label="Basecamp Campfire (optional)"
clearable
- >
+ />
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/expenses/ConvertExpensesToCsv.vue b/src/components/expenses/ConvertExpensesToCsv.vue
index 468e72fc4..86dc3b851 100644
--- a/src/components/expenses/ConvertExpensesToCsv.vue
+++ b/src/components/expenses/ConvertExpensesToCsv.vue
@@ -2,11 +2,11 @@
- file_download Download Grid Items
- Export Unanet Data
+ file_download Download Grid Items
+
+
+ Export Unanet Data
+
@@ -29,8 +29,8 @@ function download() {
/**
* Downloads expenses as CSV
*/
-function unanetReport() {
- expensesCsv.unanetReport(this.expenses);
+async function unanetReport() {
+ await expensesCsv.unanetReport(this.expenses);
} // download
// |--------------------------------------------------|
diff --git a/src/models/employee.js b/src/models/employee.js
index b2fa3e055..b6f480272 100644
--- a/src/models/employee.js
+++ b/src/models/employee.js
@@ -282,6 +282,9 @@ export class Employee {
/** @type {Object} */
this.preferences = properties.preferences ?? {};
+ /** @type {Object} */
+ this.integrationData = properties.integrationData ?? {};
+
// current address fields
/** @type {string} */
this.currentStreet = properties.currentStreet ?? '';
diff --git a/src/models/expense-types/expenseType.js b/src/models/expense-types/expenseType.js
index b2a3ad8a9..e2e838723 100644
--- a/src/models/expense-types/expenseType.js
+++ b/src/models/expense-types/expenseType.js
@@ -54,6 +54,10 @@ export class ExpenseType extends Base {
this.tagBudgets = properties.tagBudgets ?? [];
/** @type {string} */
this.to = properties.to;
+ /** @type {string} */
+ this.unanetExpenseType = properties.unanetExpenseType;
+ /** @type {string} */
+ this.unanetProject = properties.unanetProject;
return new Proxy(this, {
set(target, key, value) {
diff --git a/src/shared/api.js b/src/shared/api.js
index 79ec40a2a..47661eece 100644
--- a/src/shared/api.js
+++ b/src/shared/api.js
@@ -17,6 +17,7 @@ const PTO_CASH_OUTS = 'ptoCashOuts';
const SETTINGS = 'settings';
const TAGS = 'tags';
const ACCESS_GROUPS = 'accessGroups';
+const UNANET = 'unanet';
const API_HOSTNAME = API_CONFIG.apiHostname;
const API_PORT = API_CONFIG.apiPort;
const PORT = API_PORT === '443' ? '' : `:${API_PORT}`;
@@ -506,7 +507,7 @@ async function getEmployeesFromAdp() {
* @return - Array of IDs of employees who can see the user's data
*/
async function getAccessControlUsers(id) {
- return await execute('get', `/${ACCESS_GROUPS}/employee/groupUsers/${id}`)
+ return await execute('get', `/${ACCESS_GROUPS}/employee/groupUsers/${id}`);
}
/**
@@ -516,7 +517,14 @@ async function getAccessControlUsers(id) {
* @return - Array of IDs of employees who can see the user's data
*/
async function getUserProfileAccessControl(id) {
- return await execute('get', `/${ACCESS_GROUPS}/employee/showOnProfile/${id}`)
+ return await execute('get', `/${ACCESS_GROUPS}/employee/showOnProfile/${id}`);
+}
+
+/**
+ * Gets Unanet expense type data. Useful for exports to Unanet.
+ */
+async function getUnanetExpenseTypes() {
+ return await execute('get', `/${UNANET}/expenseTypes`);
}
export default {
@@ -562,6 +570,7 @@ export default {
getEmployeesFromAdp,
getAccessControlUsers,
getUserProfileAccessControl,
+ getUnanetExpenseTypes,
EXPENSE_TYPES,
EXPENSES,
EMPLOYEES,
diff --git a/src/utils/csv/expensesCsv.js b/src/utils/csv/expensesCsv.js
index 3db05ad15..4a29f6e3c 100644
--- a/src/utils/csv/expensesCsv.js
+++ b/src/utils/csv/expensesCsv.js
@@ -2,8 +2,10 @@
* Utilities to convert expense objects into objects passable to
* csv.js
*/
-import store from '~/store/index.js';
import { format, DEFAULT_ISOFORMAT, FORMATTED_ISOFORMAT } from '@/shared/dateUtils';
+import { indexBy } from '@/utils/utils.js';
+import store from '~/store/index.js';
+import api from '~/src/shared/api.js';
import csvUtils from '@/utils/csv/baseCsv.js';
/**
@@ -22,58 +24,95 @@ function download(expenses) {
* Downloads array of expenses as a report for Unanet import.
* @param expenses - array of expense objects
*/
-function unanetReport(expenses) {
- let csvExpenses = unanetExpenseData(expenses); // convert expenses into csv object
+async function unanetReport(expenses) {
+ let csvExpenses = await unanetExpenseData(expenses); // convert expenses into csv object
let csvFileString = csvUtils.generate(csvExpenses); // convert to csv file string
csvUtils.download(csvFileString, 'unanet_report.csv'); // download csv file string as .csv
} // unanetReport
-function unanetExpenseData(expenses) {
+async function unanetExpenseData(expenses) {
if (!Array.isArray(expenses)) expenses = [expenses];
- let employees = store.getters.employees;
- let employee;
- let expenseTypes = store.getters.expenseTypes;
- let expenseType;
+ let employees = indexBy(store.getters.employees, 'id');
+ let expenseTypes = indexBy(store.getters.expenseTypes, 'id');
+ let { projects: unanetProjects, expenseTypes: unanetETs } = await api.getUnanetExpenseTypes();
+ unanetProjects = indexBy(unanetProjects, 'key');
+ unanetETs = indexBy(unanetETs, 'key');
+
+ let employee, expenseType, unanetET, unanetProject;
+ let orgCode, projCode, taskName, expType;
return expenses.map((expense) => {
- employee = employees.find((employee) => {
- return employee.id === expense.employeeId;
- });
+ employee = employees[expense.employeeId];
+ expenseType = expenseTypes[expense.expenseTypeId];
+ unanetET = unanetETs[expenseType.unanetExpenseType]
+ unanetProject = unanetProjects[expenseType.unanetProject];
- expenseTypes.forEach((type) => {
- if (type.id === expense.expenseTypeId) {
- expenseType = type.budgetName;
- }
- });
+ console.log(unanetET);
+ console.log(unanetProject);
+
+ orgCode = unanetProject?.orgCode ?? ''; // eg. I_CASE
+ projCode = unanetProject?.code ?? ''; // eg. FRINGE.BENEFITS.GRAY
+ taskName = unanetET?.code?.toLowerCase() === 'team leads' ? 'Team Leads' : ''; // 'Team Leads' or nothing
+ expType = unanetET?.code; // eg. PHONE.INTERNET
return {
- username: employee.email, // email
- purpose: '', // blank
- location: '', // blank
- project_org_code: '',
- project_code: '',
- task_name: '',
- expense_date: format(expense.createdAt, null, FORMATTED_ISOFORMAT),
- expense_type: expenseType,
- currency_code: 'USD', // USD
- amount: expense.cost,
- exchange_rate: 1, // 1
- payment_method: '*Employee Paid', // *Employee Paid
- project_type: '', // blank
- comments: '', // blank
- receipt_included: expense.receipt ? 'Y' : 'N',
- no_receipt_reason: '', // blank
- vendor_name: '', // blank
- vat_amount: 0, // 0
- vat_location: '', // blank
- post_date: '', // blank
- cost_account: '', // blank
- exp_voucher: '', // blank
- delete: '', // blank
- ic_amount: '', // blank
- ic_cost_structure: '', // blank
- ic_cost_element: '', // blank
- amount_in: '' // blank
- };
+ 'username': employee.email,
+ 'purpose': expenseType.budgetName,
+ 'location': '', // blank
+ 'project_org_code': orgCode,
+ 'project_code': projCode,
+ 'task_name': taskName,
+ 'expense_date': format(expense.createdAt, null, FORMATTED_ISOFORMAT),
+ 'expense_type': expType,
+ 'currency_code': 'USD',
+ 'amount': expense.cost,
+ 'exchange_rate': 1, // USD -> USD is just 1
+ 'payment_method': '*Employee Paid', // *Employee Paid
+ 'project_type': '', // blank
+ 'comments': '', // blank
+ 'receipt_included': expense.receipt ? 'Y' : 'N',
+ 'no_receipt_reason': '', // blank
+ 'vendor_name': '', // blank
+ 'vat_amount': 0, // always 0
+ 'vat_location': '', // blank
+ 'post_date': '', // blank
+ 'cost_account': '', // blank
+ 'exp_voucher': '', // blank
+ 'delete': '', // blank
+ 'ic_amount': '', // blank
+ 'ic_cost_structure': '', // blank
+ 'ic_cost_element': '', // blank
+ 'amount_in': '' // blank
+ }
+
+ // return {
+ // username: employee.email, // email
+ // purpose: expenseType, // blank
+ // location: '', // blank
+ // project_org_code: '',
+ // project_code: '',
+ // task_name: '',
+ // expense_date: format(expense.createdAt, null, FORMATTED_ISOFORMAT),
+ // expense_type: expenseType,
+ // currency_code: 'USD', // USD
+ // amount: expense.cost,
+ // exchange_rate: 1, // 1
+ // payment_method: '*Employee Paid', // *Employee Paid
+ // project_type: '', // blank
+ // comments: '', // blank
+ // receipt_included: expense.receipt ? 'Y' : 'N',
+ // no_receipt_reason: '', // blank
+ // vendor_name: '', // blank
+ // vat_amount: 0, // 0
+ // vat_location: '', // blank
+ // post_date: '', // blank
+ // cost_account: '', // blank
+ // exp_voucher: '', // blank
+ // delete: '', // blank
+ // ic_amount: '', // blank
+ // ic_cost_structure: '', // blank
+ // ic_cost_element: '', // blank
+ // amount_in: '' // blank
+ // };
});
}