zoho books api added along with zoho people (employee api tested)
This commit is contained in:
parent
9e785012fe
commit
efce4cc90d
@ -278,4 +278,587 @@ async function getInvoices(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks, getAllProjectTaskLists, getAllProjectIssues, getAllProjectPhases, getSalesOrders, getPurchaseOrders, getInvoices };
|
||||
// Zoho People specific controllers
|
||||
async function getDepartments(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Departments are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const departments = await integrationService.getDepartments(provider, params);
|
||||
res.json(success('Zoho Departments retrieved successfully', departments));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getLeaveRequests(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Leave Requests are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const leaveRequests = await integrationService.getLeaveRequests(provider, params);
|
||||
res.json(success('Zoho Leave Requests retrieved successfully', leaveRequests));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getAttendance(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Attendance is only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const attendance = await integrationService.getAttendance(provider, params);
|
||||
res.json(success('Zoho Attendance retrieved successfully', attendance));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
// Zoho Books specific controllers
|
||||
async function getOrganizations(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Organizations are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const organizations = await integrationService.getOrganizations(provider, params);
|
||||
res.json(success('Zoho Organizations retrieved successfully', organizations));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getCustomers(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Customers are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const customers = await integrationService.getCustomers(provider, params);
|
||||
|
||||
res.json(success('Zoho Customers retrieved successfully', customers));
|
||||
} catch (error) {
|
||||
console.log('customer response error i got', JSON.stringify(error))
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getVendors(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Vendors are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const vendors = await integrationService.getVendors(provider, params);
|
||||
res.json(success('Zoho Vendors retrieved successfully', vendors));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getItems(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Items are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const items = await integrationService.getItems(provider, params);
|
||||
res.json(success('Zoho Items retrieved successfully', items));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getEstimates(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Estimates are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const estimates = await integrationService.getEstimates(provider, params);
|
||||
res.json(success('Zoho Estimates retrieved successfully', estimates));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getBills(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Bills are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const bills = await integrationService.getBills(provider, params);
|
||||
res.json(success('Zoho Bills retrieved successfully', bills));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getExpenses(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Expenses are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const expenses = await integrationService.getExpenses(provider, params);
|
||||
res.json(success('Zoho Expenses retrieved successfully', expenses));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getBankAccounts(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Bank Accounts are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const bankAccounts = await integrationService.getBankAccounts(provider, params);
|
||||
res.json(success('Zoho Bank Accounts retrieved successfully', bankAccounts));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getBankTransactions(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Bank Transactions are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const bankTransactions = await integrationService.getBankTransactions(provider, params);
|
||||
res.json(success('Zoho Bank Transactions retrieved successfully', bankTransactions));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getReports(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Reports are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const reports = await integrationService.getReports(provider, params);
|
||||
res.json(success('Zoho Reports retrieved successfully', reports));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getBooksSalesOrders(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Books Sales Orders are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const salesOrders = await integrationService.getBooksSalesOrders(provider, params);
|
||||
res.json(success('Zoho Books Sales Orders retrieved successfully', salesOrders));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getBooksPurchaseOrders(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Books Purchase Orders are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const purchaseOrders = await integrationService.getBooksPurchaseOrders(provider, params);
|
||||
res.json(success('Zoho Books Purchase Orders retrieved successfully', purchaseOrders));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getContacts(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Contacts are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const contacts = await integrationService.getContacts(provider, params);
|
||||
res.json(success('Zoho Books Contacts retrieved successfully', contacts));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
// Zoho People Forms API controllers
|
||||
async function getEmployeeForms(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Employee Forms are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const employeeForms = await integrationService.getEmployeeForms(provider, params);
|
||||
res.json(success('Zoho People Employee Forms retrieved successfully', employeeForms));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getEmployeeById(req, res) {
|
||||
try {
|
||||
const { provider, recordId, formLinkName } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Employee Details are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
if (!recordId) {
|
||||
return res.status(400).json(failure('recordId is required', 'MISSING_RECORD_ID'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const employeeDetail = await integrationService.getEmployeeById(provider, recordId, formLinkName);
|
||||
res.json(success('Zoho People Employee Details retrieved successfully', employeeDetail));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getAttendanceEntries(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Attendance Entries are only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const attendanceEntries = await integrationService.getAttendanceEntries(provider, params);
|
||||
res.json(success('Zoho People Attendance Entries retrieved successfully', attendanceEntries));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getShiftConfiguration(req, res) {
|
||||
try {
|
||||
const { provider, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Shift Configuration is only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const shiftConfig = await integrationService.getShiftConfiguration(provider, params);
|
||||
res.json(success('Zoho People Shift Configuration retrieved successfully', shiftConfig));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getLeaveData(req, res) {
|
||||
try {
|
||||
const { provider, formLinkName, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Leave Data is only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const leaveData = await integrationService.getLeaveData(provider, formLinkName, params);
|
||||
res.json(success('Zoho People Leave Data retrieved successfully', leaveData));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getGoalsData(req, res) {
|
||||
try {
|
||||
const { provider, formLinkName, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Goals Data is only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const goalsData = await integrationService.getGoalsData(provider, formLinkName, params);
|
||||
res.json(success('Zoho People Goals Data retrieved successfully', goalsData));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
async function getPerformanceData(req, res) {
|
||||
try {
|
||||
const { provider, formLinkName, page, limit, filters } = req.query;
|
||||
|
||||
if (provider !== 'zoho') {
|
||||
return res.status(400).json(failure('Performance Data is only available for Zoho provider', 'INVALID_PROVIDER'));
|
||||
}
|
||||
|
||||
const integrationService = new IntegrationService(req.user.uuid);
|
||||
const params = { page, limit };
|
||||
if (filters) {
|
||||
try {
|
||||
params.filters = JSON.parse(filters);
|
||||
} catch (e) {
|
||||
return res.status(400).json(failure('Invalid filters format', 'INVALID_FILTERS'));
|
||||
}
|
||||
}
|
||||
|
||||
const performanceData = await integrationService.getPerformanceData(provider, formLinkName, params);
|
||||
res.json(success('Zoho People Performance Data retrieved successfully', performanceData));
|
||||
} catch (error) {
|
||||
res.status(400).json(failure(error.message, 'INTEGRATION_ERROR'));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks,
|
||||
getAllProjectTaskLists, getAllProjectIssues, getAllProjectPhases, getSalesOrders,
|
||||
getPurchaseOrders, getInvoices, getDepartments, getLeaveRequests, getAttendance,
|
||||
getOrganizations, getCustomers, getVendors, getItems, getEstimates, getBills,
|
||||
getExpenses, getBankAccounts, getBankTransactions, getReports, getBooksSalesOrders,
|
||||
getBooksPurchaseOrders, getContacts, getEmployeeForms, getEmployeeById,
|
||||
getAttendanceEntries, getShiftConfiguration, getLeaveData, getGoalsData, getPerformanceData
|
||||
};
|
||||
|
||||
@ -1,6 +1,14 @@
|
||||
const express = require('express');
|
||||
const Joi = require('joi');
|
||||
const { getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks, getAllProjectTaskLists, getAllProjectIssues, getAllProjectPhases, getSalesOrders, getPurchaseOrders, getInvoices } = require('../controllers/integrationController');
|
||||
const {
|
||||
getData, getServices, getResources, getPortals, getAllProjects, getAllProjectTasks,
|
||||
getAllProjectTaskLists, getAllProjectIssues, getAllProjectPhases, getSalesOrders,
|
||||
getPurchaseOrders, getInvoices, getDepartments, getLeaveRequests, getAttendance,
|
||||
getOrganizations, getCustomers, getVendors, getItems, getEstimates, getBills,
|
||||
getExpenses, getBankAccounts, getBankTransactions, getReports, getBooksSalesOrders,
|
||||
getBooksPurchaseOrders, getContacts, getEmployeeForms, getEmployeeById,
|
||||
getAttendanceEntries, getShiftConfiguration, getLeaveData, getGoalsData, getPerformanceData
|
||||
} = require('../controllers/integrationController');
|
||||
const auth = require('../middlewares/auth');
|
||||
const ZohoHandler = require('../../integrations/zoho/handler');
|
||||
|
||||
@ -60,7 +68,8 @@ const portalsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required()
|
||||
});
|
||||
|
||||
router.get('/portals', auth, validate(portalsSchema), getPortals);
|
||||
// Zoho Projects specific routes with clear service identification
|
||||
router.get('/zoho/projects/portals', auth, validate(portalsSchema), getPortals);
|
||||
|
||||
// Get all Zoho projects (across all portals)
|
||||
const allProjectsSchema = Joi.object({
|
||||
@ -70,7 +79,7 @@ const allProjectsSchema = Joi.object({
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
router.get('/all-projects', auth, validate(allProjectsSchema), getAllProjects);
|
||||
router.get('/zoho/projects/all-projects', auth, validate(allProjectsSchema), getAllProjects);
|
||||
|
||||
// Get all project tasks for a specific portal
|
||||
const allProjectTasksSchema = Joi.object({
|
||||
@ -81,7 +90,7 @@ const allProjectTasksSchema = Joi.object({
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
router.get('/all-project-tasks', auth, validate(allProjectTasksSchema), getAllProjectTasks);
|
||||
router.get('/zoho/projects/all-project-tasks', auth, validate(allProjectTasksSchema), getAllProjectTasks);
|
||||
|
||||
// Get all project task lists for a specific portal
|
||||
const allProjectTaskListsSchema = Joi.object({
|
||||
@ -92,7 +101,7 @@ const allProjectTaskListsSchema = Joi.object({
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
router.get('/all-project-tasklists', auth, validate(allProjectTaskListsSchema), getAllProjectTaskLists);
|
||||
router.get('/zoho/projects/all-project-tasklists', auth, validate(allProjectTaskListsSchema), getAllProjectTaskLists);
|
||||
|
||||
// Get all project issues for a specific portal
|
||||
const allProjectIssuesSchema = Joi.object({
|
||||
@ -103,7 +112,7 @@ const allProjectIssuesSchema = Joi.object({
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
router.get('/all-project-issues', auth, validate(allProjectIssuesSchema), getAllProjectIssues);
|
||||
router.get('/zoho/projects/all-project-issues', auth, validate(allProjectIssuesSchema), getAllProjectIssues);
|
||||
|
||||
// Get all project phases for a specific portal
|
||||
const allProjectPhasesSchema = Joi.object({
|
||||
@ -114,7 +123,7 @@ const allProjectPhasesSchema = Joi.object({
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
router.get('/all-project-phases', auth, validate(allProjectPhasesSchema), getAllProjectPhases);
|
||||
router.get('/zoho/projects/all-project-phases', auth, validate(allProjectPhasesSchema), getAllProjectPhases);
|
||||
|
||||
// Get Zoho Sales Orders
|
||||
const salesOrdersSchema = Joi.object({
|
||||
@ -124,7 +133,8 @@ const salesOrdersSchema = Joi.object({
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
router.get('/sales-orders', auth, validate(salesOrdersSchema), getSalesOrders);
|
||||
// Zoho CRM specific routes with clear service identification
|
||||
router.get('/zoho/crm/sales-orders', auth, validate(salesOrdersSchema), getSalesOrders);
|
||||
|
||||
// Get Zoho Purchase Orders
|
||||
const purchaseOrdersSchema = Joi.object({
|
||||
@ -134,7 +144,7 @@ const purchaseOrdersSchema = Joi.object({
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
router.get('/purchase-orders', auth, validate(purchaseOrdersSchema), getPurchaseOrders);
|
||||
router.get('/zoho/crm/purchase-orders', auth, validate(purchaseOrdersSchema), getPurchaseOrders);
|
||||
|
||||
// Get Zoho Invoices
|
||||
const invoicesSchema = Joi.object({
|
||||
@ -144,12 +154,202 @@ const invoicesSchema = Joi.object({
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
router.get('/invoices', auth, validate(invoicesSchema), getInvoices);
|
||||
router.get('/zoho/crm/invoices', auth, validate(invoicesSchema), getInvoices);
|
||||
|
||||
// Zoho People specific routes
|
||||
const departmentsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const leaveRequestsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const attendanceSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
// Zoho People Forms API schemas
|
||||
const employeeFormsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const employeeByIdSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
recordId: Joi.string().required(),
|
||||
formLinkName: Joi.string().default('employee')
|
||||
});
|
||||
|
||||
const attendanceEntriesSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const shiftConfigurationSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const leaveDataSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
formLinkName: Joi.string().default('leave'),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const goalsDataSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
formLinkName: Joi.string().default('goals'),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const performanceDataSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
formLinkName: Joi.string().default('performance'),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
// Zoho People specific routes with clear service identification
|
||||
router.get('/zoho/people/departments', auth, validate(departmentsSchema), getDepartments);
|
||||
router.get('/zoho/people/leave-requests', auth, validate(leaveRequestsSchema), getLeaveRequests);
|
||||
router.get('/zoho/people/attendance', auth, validate(attendanceSchema), getAttendance);
|
||||
|
||||
// Zoho People Forms API routes
|
||||
router.get('/zoho/people/employee-forms', auth, validate(employeeFormsSchema), getEmployeeForms);
|
||||
router.get('/zoho/people/employee/:recordId', auth, validate(employeeByIdSchema), getEmployeeById);
|
||||
router.get('/zoho/people/attendance-entries', auth, validate(attendanceEntriesSchema), getAttendanceEntries);
|
||||
router.get('/zoho/people/shift-configuration', auth, validate(shiftConfigurationSchema), getShiftConfiguration);
|
||||
router.get('/zoho/people/leave-data', auth, validate(leaveDataSchema), getLeaveData);
|
||||
router.get('/zoho/people/goals-data', auth, validate(goalsDataSchema), getGoalsData);
|
||||
router.get('/zoho/people/performance-data', auth, validate(performanceDataSchema), getPerformanceData);
|
||||
|
||||
// Zoho Books specific routes
|
||||
const organizationsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const customersSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const vendorsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const itemsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const estimatesSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const billsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const expensesSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const bankAccountsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const bankTransactionsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const reportsSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const booksSalesOrdersSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
const booksPurchaseOrdersSchema = Joi.object({
|
||||
provider: Joi.string().valid('zoho').required(),
|
||||
page: Joi.number().min(1).default(1),
|
||||
limit: Joi.number().min(1).max(100).default(20),
|
||||
filters: Joi.string().optional()
|
||||
});
|
||||
|
||||
// Zoho Books specific routes with clear service identification
|
||||
router.get('/zoho/books/organizations', auth, validate(organizationsSchema), getOrganizations);
|
||||
router.get('/zoho/books/contacts', auth, validate(customersSchema), getContacts);
|
||||
router.get('/zoho/books/vendors', auth, validate(vendorsSchema), getVendors);
|
||||
router.get('/zoho/books/items', auth, validate(itemsSchema), getItems);
|
||||
router.get('/zoho/books/customers', auth, validate(customersSchema), getCustomers);
|
||||
router.get('/zoho/books/invoices', auth, validate(invoicesSchema), getInvoices);
|
||||
router.get('/zoho/books/estimates', auth, validate(estimatesSchema), getEstimates);
|
||||
router.get('/zoho/books/bills', auth, validate(billsSchema), getBills);
|
||||
router.get('/zoho/books/expenses', auth, validate(expensesSchema), getExpenses);
|
||||
router.get('/zoho/books/bank-accounts', auth, validate(bankAccountsSchema), getBankAccounts);
|
||||
router.get('/zoho/books/bank-transactions', auth, validate(bankTransactionsSchema), getBankTransactions);
|
||||
router.get('/zoho/books/reports', auth, validate(reportsSchema), getReports);
|
||||
router.get('/zoho/books/sales-orders', auth, validate(booksSalesOrdersSchema), getBooksSalesOrders);
|
||||
router.get('/zoho/books/purchase-orders', auth, validate(booksPurchaseOrdersSchema), getBooksPurchaseOrders);
|
||||
|
||||
// Webhook endpoints (no auth required - uses signature verification)
|
||||
const zohoHandler = new ZohoHandler();
|
||||
router.post('/webhooks/zoho/crm', zohoHandler.handleCrmWebhook.bind(zohoHandler));
|
||||
router.post('/webhooks/zoho/people', zohoHandler.handlePeopleWebhook.bind(zohoHandler));
|
||||
router.post('/webhooks/zoho/books', zohoHandler.handleBooksWebhook.bind(zohoHandler));
|
||||
router.post('/webhooks/zoho/projects', zohoHandler.handleProjectsWebhook.bind(zohoHandler));
|
||||
router.post('/webhooks/zoho/bulkread', zohoHandler.handleBulkReadWebhook.bind(zohoHandler));
|
||||
|
||||
|
||||
@ -8,7 +8,8 @@ class ZohoClient {
|
||||
this.userId = userId;
|
||||
this.baseUrls = {
|
||||
crm: 'https://www.zohoapis.com',
|
||||
people: 'https://www.zohoapis.com',
|
||||
people: 'https://people.zoho.com',
|
||||
books: 'https://www.zohoapis.com',
|
||||
projects: 'https://projectsapi.zoho.com'
|
||||
};
|
||||
}
|
||||
@ -30,12 +31,13 @@ class ZohoClient {
|
||||
const baseUrl = this.baseUrls[service] || this.baseUrls.crm;
|
||||
const url = `${baseUrl}${endpoint}`;
|
||||
|
||||
// Transform limit to per_page for Zoho APIs
|
||||
// Transform limit to per_page for Zoho APIs (except People APIs)
|
||||
let params = options.params || {};
|
||||
if (params.limit) {
|
||||
if (params.limit && service !== 'people') {
|
||||
params.per_page = params.limit;
|
||||
delete params.limit;
|
||||
}
|
||||
// For People APIs, keep limit as is
|
||||
|
||||
const config = {
|
||||
...options,
|
||||
@ -133,6 +135,134 @@ class ZohoClient {
|
||||
return ZohoMapper.mapApiResponse(response, 'employees');
|
||||
}
|
||||
|
||||
async getDepartments(params = {}) {
|
||||
const response = await this.makeRequest('/people/api/v1/departments', { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'departments');
|
||||
}
|
||||
|
||||
async getTimesheets(params = {}) {
|
||||
const response = await this.makeRequest('/people/api/v1/timesheets', { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'timesheets');
|
||||
}
|
||||
|
||||
async getLeaveRequests(params = {}) {
|
||||
const response = await this.makeRequest('/people/api/v1/leave', { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'leave_requests');
|
||||
}
|
||||
|
||||
async getAttendance(params = {}) {
|
||||
const response = await this.makeRequest('/people/api/v1/attendance', { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'attendance');
|
||||
}
|
||||
|
||||
// Zoho People Forms API methods
|
||||
async getEmployeeForms(params = {}) {
|
||||
const response = await this.makeRequest('/people/api/forms/employee/getRecords', { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'employee_forms');
|
||||
}
|
||||
|
||||
async getEmployeeById(recordId, formLinkName = 'employee') {
|
||||
const response = await this.makeRequest(`/people/api/forms/${formLinkName}/getDataByID`, {
|
||||
params: { recordId }
|
||||
}, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'employee_detail');
|
||||
}
|
||||
|
||||
async getAttendanceEntries(params = {}) {
|
||||
const response = await this.makeRequest('/people/api/attendance/getAttendanceEntries', { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'attendance_entries');
|
||||
}
|
||||
|
||||
async getShiftConfiguration(params = {}) {
|
||||
const response = await this.makeRequest('/people/api/attendance/getShiftConfiguration', { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'shift_configuration');
|
||||
}
|
||||
|
||||
async getLeaveData(formLinkName = 'leave', params = {}) {
|
||||
const response = await this.makeRequest(`/people/api/forms/${formLinkName}/getRecords`, { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'leave_data');
|
||||
}
|
||||
|
||||
async getGoalsData(formLinkName = 'goals', params = {}) {
|
||||
const response = await this.makeRequest(`/people/api/forms/${formLinkName}/getRecords`, { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'goals_data');
|
||||
}
|
||||
|
||||
async getPerformanceData(formLinkName = 'performance', params = {}) {
|
||||
const response = await this.makeRequest(`/people/api/forms/${formLinkName}/getRecords`, { params }, 'people');
|
||||
return ZohoMapper.mapApiResponse(response, 'performance_data');
|
||||
}
|
||||
|
||||
// Zoho Books methods
|
||||
async getOrganizations(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/organizations', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'organizations');
|
||||
}
|
||||
|
||||
async getCustomers(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/contacts', { params :{ ...params, contact_type: 'customer' }}, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'contacts');
|
||||
}
|
||||
async getContacts(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/contacts', { params}, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'contacts');
|
||||
}
|
||||
|
||||
async getVendors(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/contacts', { params: { ...params, contact_type: 'vendor' } }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'vendors');
|
||||
}
|
||||
|
||||
async getItems(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/items', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'items');
|
||||
}
|
||||
|
||||
async getInvoices(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/invoices', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'invoices');
|
||||
}
|
||||
|
||||
async getEstimates(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/estimates', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'estimates');
|
||||
}
|
||||
|
||||
async getBills(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/bills', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'bills');
|
||||
}
|
||||
|
||||
async getExpenses(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/expenses', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'expenses');
|
||||
}
|
||||
|
||||
async getBankAccounts(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/bankaccounts', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'bank_accounts');
|
||||
}
|
||||
|
||||
async getBankTransactions(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/banktransactions', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'bank_transactions');
|
||||
}
|
||||
|
||||
async getReports(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/reports', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'reports');
|
||||
}
|
||||
|
||||
async getBooksSalesOrders(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/salesorders', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'sales_orders');
|
||||
}
|
||||
|
||||
async getBooksPurchaseOrders(params = {}) {
|
||||
const response = await this.makeRequest('/books/v3/purchaseorders', { params }, 'books');
|
||||
return ZohoMapper.mapApiResponse(response, 'purchase_orders');
|
||||
}
|
||||
|
||||
// Zoho Projects methods
|
||||
async getPortals() {
|
||||
const response = await this.makeRequest('/api/v3/portals', {}, 'projects');
|
||||
@ -211,13 +341,14 @@ class ZohoClient {
|
||||
|
||||
// Service discovery
|
||||
getAvailableServices() {
|
||||
return ['crm', 'people', 'projects'];
|
||||
return ['crm', 'people', 'books', 'projects'];
|
||||
}
|
||||
|
||||
getAvailableResources(service) {
|
||||
const resources = {
|
||||
'crm': ['leads', 'contacts', 'deals', 'tasks', 'sales_orders', 'purchase_orders', 'invoices'],
|
||||
'people': ['employees', 'departments'],
|
||||
'people': ['employees', 'departments', 'timesheets', 'leave_requests', 'attendance', 'employee_forms', 'attendance_entries', 'shift_configuration', 'leave_data', 'goals_data', 'performance_data'],
|
||||
'books': ['organizations', 'customers', 'vendors', 'items', 'invoices', 'estimates', 'bills', 'expenses', 'bank_accounts', 'bank_transactions', 'reports', 'sales_orders', 'purchase_orders'],
|
||||
'projects': ['projects', 'tasks', 'timesheets']
|
||||
};
|
||||
return resources[service] || [];
|
||||
|
||||
@ -178,6 +178,68 @@ class ZohoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Zoho Books webhook events
|
||||
async handleBooksWebhook(req, res) {
|
||||
try {
|
||||
const signature = req.headers['x-zoho-signature'];
|
||||
const payload = JSON.stringify(req.body);
|
||||
|
||||
if (!this.verifyWebhookSignature(payload, signature)) {
|
||||
logger.warn('Invalid Zoho Books webhook signature', {
|
||||
correlationId: logger.getCorrelationId(req),
|
||||
ip: req.ip
|
||||
});
|
||||
return res.status(401).json({ status: 'error', message: 'Invalid signature' });
|
||||
}
|
||||
|
||||
const { event, data } = req.body;
|
||||
logger.info('Zoho Books webhook received', {
|
||||
correlationId: logger.getCorrelationId(req),
|
||||
event,
|
||||
recordId: data?.id
|
||||
});
|
||||
|
||||
// Process different Books events
|
||||
switch (event) {
|
||||
case 'customers.create':
|
||||
await this.handleCustomerCreated(data);
|
||||
break;
|
||||
case 'customers.update':
|
||||
await this.handleCustomerUpdated(data);
|
||||
break;
|
||||
case 'invoices.create':
|
||||
await this.handleBooksInvoiceCreated(data);
|
||||
break;
|
||||
case 'invoices.update':
|
||||
await this.handleBooksInvoiceUpdated(data);
|
||||
break;
|
||||
case 'bills.create':
|
||||
await this.handleBillCreated(data);
|
||||
break;
|
||||
case 'bills.update':
|
||||
await this.handleBillUpdated(data);
|
||||
break;
|
||||
case 'expenses.create':
|
||||
await this.handleExpenseCreated(data);
|
||||
break;
|
||||
case 'expenses.update':
|
||||
await this.handleExpenseUpdated(data);
|
||||
break;
|
||||
default:
|
||||
logger.warn('Unknown Zoho Books event', { event });
|
||||
}
|
||||
|
||||
res.json({ status: 'success', message: 'Webhook processed' });
|
||||
} catch (error) {
|
||||
logger.error('Zoho Books webhook processing failed', {
|
||||
correlationId: logger.getCorrelationId(req),
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
res.status(500).json({ status: 'error', message: 'Webhook processing failed' });
|
||||
}
|
||||
}
|
||||
|
||||
// CRM Event Handlers
|
||||
async handleLeadCreated(data) {
|
||||
logger.info('Lead created', { leadId: data.id, name: data.Full_Name });
|
||||
@ -616,6 +678,47 @@ class ZohoHandler {
|
||||
logger.info('Task updated', { taskId: data.id, name: data.name, projectId: data.project?.id });
|
||||
// Add your business logic here
|
||||
}
|
||||
|
||||
// Books Event Handlers
|
||||
async handleCustomerCreated(data) {
|
||||
logger.info('Customer created', { customerId: data.contact_id, name: data.contact_name });
|
||||
// Add your business logic here
|
||||
}
|
||||
|
||||
async handleCustomerUpdated(data) {
|
||||
logger.info('Customer updated', { customerId: data.contact_id, name: data.contact_name });
|
||||
// Add your business logic here
|
||||
}
|
||||
|
||||
async handleBooksInvoiceCreated(data) {
|
||||
logger.info('Books Invoice created', { invoiceId: data.invoice_id, invoiceNumber: data.invoice_number, total: data.total });
|
||||
// Add your business logic here
|
||||
}
|
||||
|
||||
async handleBooksInvoiceUpdated(data) {
|
||||
logger.info('Books Invoice updated', { invoiceId: data.invoice_id, invoiceNumber: data.invoice_number, total: data.total });
|
||||
// Add your business logic here
|
||||
}
|
||||
|
||||
async handleBillCreated(data) {
|
||||
logger.info('Bill created', { billId: data.bill_id, billNumber: data.bill_number, total: data.total });
|
||||
// Add your business logic here
|
||||
}
|
||||
|
||||
async handleBillUpdated(data) {
|
||||
logger.info('Bill updated', { billId: data.bill_id, billNumber: data.bill_number, total: data.total });
|
||||
// Add your business logic here
|
||||
}
|
||||
|
||||
async handleExpenseCreated(data) {
|
||||
logger.info('Expense created', { expenseId: data.expense_id, amount: data.amount, description: data.description });
|
||||
// Add your business logic here
|
||||
}
|
||||
|
||||
async handleExpenseUpdated(data) {
|
||||
logger.info('Expense updated', { expenseId: data.expense_id, amount: data.amount, description: data.description });
|
||||
// Add your business logic here
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ZohoHandler;
|
||||
|
||||
@ -54,61 +54,61 @@ class ZohoMapper {
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho CRM Sales Order to standardized format
|
||||
// Map Zoho Sales Order to standardized format (handles both CRM and Books)
|
||||
static mapSalesOrder(zohoSalesOrder) {
|
||||
return {
|
||||
id: zohoSalesOrder.id,
|
||||
subject: zohoSalesOrder.Subject,
|
||||
orderNumber: zohoSalesOrder.SO_Number,
|
||||
account: zohoSalesOrder.Account_Name,
|
||||
contact: zohoSalesOrder.Contact_Name,
|
||||
id: zohoSalesOrder.id || zohoSalesOrder.salesorder_id,
|
||||
subject: zohoSalesOrder.Subject || zohoSalesOrder.subject,
|
||||
orderNumber: zohoSalesOrder.SO_Number || zohoSalesOrder.salesorder_number,
|
||||
account: zohoSalesOrder.Account_Name || zohoSalesOrder.customer_name,
|
||||
contact: zohoSalesOrder.Contact_Name || zohoSalesOrder.contact_name,
|
||||
deal: zohoSalesOrder.Deal_Name,
|
||||
grandTotal: zohoSalesOrder.Grand_Total,
|
||||
status: zohoSalesOrder.Status,
|
||||
orderDate: zohoSalesOrder.Order_Date,
|
||||
dueDate: zohoSalesOrder.Due_Date,
|
||||
createdTime: zohoSalesOrder.Created_Time,
|
||||
modifiedTime: zohoSalesOrder.Modified_Time,
|
||||
owner: zohoSalesOrder.Owner?.name,
|
||||
grandTotal: zohoSalesOrder.Grand_Total || zohoSalesOrder.total,
|
||||
status: zohoSalesOrder.Status || zohoSalesOrder.status,
|
||||
orderDate: zohoSalesOrder.Order_Date || zohoSalesOrder.date,
|
||||
dueDate: zohoSalesOrder.Due_Date || zohoSalesOrder.due_date,
|
||||
createdTime: zohoSalesOrder.Created_Time || zohoSalesOrder.created_time,
|
||||
modifiedTime: zohoSalesOrder.Modified_Time || zohoSalesOrder.last_modified_time,
|
||||
owner: zohoSalesOrder.Owner?.name || zohoSalesOrder.owner?.name,
|
||||
customFields: this.mapCustomFields(zohoSalesOrder)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho CRM Purchase Order to standardized format
|
||||
// Map Zoho Purchase Order to standardized format (handles both CRM and Books)
|
||||
static mapPurchaseOrder(zohoPurchaseOrder) {
|
||||
return {
|
||||
id: zohoPurchaseOrder.id,
|
||||
subject: zohoPurchaseOrder.Subject,
|
||||
orderNumber: zohoPurchaseOrder.PO_Number,
|
||||
vendor: zohoPurchaseOrder.Vendor_Name,
|
||||
account: zohoPurchaseOrder.Account_Name,
|
||||
grandTotal: zohoPurchaseOrder.Grand_Total,
|
||||
status: zohoPurchaseOrder.Status,
|
||||
orderDate: zohoPurchaseOrder.PO_Date,
|
||||
dueDate: zohoPurchaseOrder.Expected_Delivery_Date,
|
||||
createdTime: zohoPurchaseOrder.Created_Time,
|
||||
modifiedTime: zohoPurchaseOrder.Modified_Time,
|
||||
owner: zohoPurchaseOrder.Owner?.name,
|
||||
id: zohoPurchaseOrder.id || zohoPurchaseOrder.purchaseorder_id,
|
||||
subject: zohoPurchaseOrder.Subject || zohoPurchaseOrder.subject,
|
||||
orderNumber: zohoPurchaseOrder.PO_Number || zohoPurchaseOrder.purchaseorder_number,
|
||||
vendor: zohoPurchaseOrder.Vendor_Name || zohoPurchaseOrder.vendor_name,
|
||||
account: zohoPurchaseOrder.Account_Name || zohoPurchaseOrder.customer_name,
|
||||
grandTotal: zohoPurchaseOrder.Grand_Total || zohoPurchaseOrder.total,
|
||||
status: zohoPurchaseOrder.Status || zohoPurchaseOrder.status,
|
||||
orderDate: zohoPurchaseOrder.PO_Date || zohoPurchaseOrder.date,
|
||||
dueDate: zohoPurchaseOrder.Expected_Delivery_Date || zohoPurchaseOrder.due_date,
|
||||
createdTime: zohoPurchaseOrder.Created_Time || zohoPurchaseOrder.created_time,
|
||||
modifiedTime: zohoPurchaseOrder.Modified_Time || zohoPurchaseOrder.last_modified_time,
|
||||
owner: zohoPurchaseOrder.Owner?.name || zohoPurchaseOrder.owner?.name,
|
||||
customFields: this.mapCustomFields(zohoPurchaseOrder)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho CRM Invoice to standardized format
|
||||
// Map Zoho Invoice to standardized format (handles both CRM and Books)
|
||||
static mapInvoice(zohoInvoice) {
|
||||
return {
|
||||
id: zohoInvoice.id,
|
||||
subject: zohoInvoice.Subject,
|
||||
invoiceNumber: zohoInvoice.Invoice_Number,
|
||||
account: zohoInvoice.Account_Name,
|
||||
contact: zohoInvoice.Contact_Name,
|
||||
id: zohoInvoice.id || zohoInvoice.invoice_id,
|
||||
subject: zohoInvoice.Subject || zohoInvoice.subject,
|
||||
invoiceNumber: zohoInvoice.Invoice_Number || zohoInvoice.invoice_number,
|
||||
account: zohoInvoice.Account_Name || zohoInvoice.customer_name,
|
||||
contact: zohoInvoice.Contact_Name || zohoInvoice.contact_name,
|
||||
deal: zohoInvoice.Deal_Name,
|
||||
grandTotal: zohoInvoice.Grand_Total,
|
||||
status: zohoInvoice.Status,
|
||||
invoiceDate: zohoInvoice.Invoice_Date,
|
||||
dueDate: zohoInvoice.Due_Date,
|
||||
createdTime: zohoInvoice.Created_Time,
|
||||
modifiedTime: zohoInvoice.Modified_Time,
|
||||
owner: zohoInvoice.Owner?.name,
|
||||
grandTotal: zohoInvoice.Grand_Total || zohoInvoice.total,
|
||||
status: zohoInvoice.Status || zohoInvoice.status,
|
||||
invoiceDate: zohoInvoice.Invoice_Date || zohoInvoice.date,
|
||||
dueDate: zohoInvoice.Due_Date || zohoInvoice.due_date,
|
||||
createdTime: zohoInvoice.Created_Time || zohoInvoice.created_time,
|
||||
modifiedTime: zohoInvoice.Modified_Time || zohoInvoice.last_modified_time,
|
||||
owner: zohoInvoice.Owner?.name || zohoInvoice.owner?.name,
|
||||
customFields: this.mapCustomFields(zohoInvoice)
|
||||
};
|
||||
}
|
||||
@ -131,6 +131,310 @@ class ZohoMapper {
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Department to standardized format
|
||||
static mapDepartment(zohoDepartment) {
|
||||
return {
|
||||
id: zohoDepartment.id,
|
||||
name: zohoDepartment.name,
|
||||
description: zohoDepartment.description,
|
||||
head: zohoDepartment.head,
|
||||
employeeCount: zohoDepartment.employeeCount,
|
||||
customFields: this.mapCustomFields(zohoDepartment)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Timesheet to standardized format
|
||||
static mapTimesheet(zohoTimesheet) {
|
||||
return {
|
||||
id: zohoTimesheet.id,
|
||||
employeeId: zohoTimesheet.employeeId,
|
||||
projectId: zohoTimesheet.projectId,
|
||||
taskId: zohoTimesheet.taskId,
|
||||
date: zohoTimesheet.date,
|
||||
hours: zohoTimesheet.hours,
|
||||
description: zohoTimesheet.description,
|
||||
status: zohoTimesheet.status,
|
||||
customFields: this.mapCustomFields(zohoTimesheet)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Leave Request to standardized format
|
||||
static mapLeaveRequest(zohoLeaveRequest) {
|
||||
return {
|
||||
id: zohoLeaveRequest.id,
|
||||
employeeId: zohoLeaveRequest.employeeId,
|
||||
leaveType: zohoLeaveRequest.leaveType,
|
||||
startDate: zohoLeaveRequest.startDate,
|
||||
endDate: zohoLeaveRequest.endDate,
|
||||
days: zohoLeaveRequest.days,
|
||||
reason: zohoLeaveRequest.reason,
|
||||
status: zohoLeaveRequest.status,
|
||||
customFields: this.mapCustomFields(zohoLeaveRequest)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Attendance to standardized format
|
||||
static mapAttendance(zohoAttendance) {
|
||||
return {
|
||||
id: zohoAttendance.id,
|
||||
employeeId: zohoAttendance.employeeId,
|
||||
date: zohoAttendance.date,
|
||||
checkIn: zohoAttendance.checkIn,
|
||||
checkOut: zohoAttendance.checkOut,
|
||||
hoursWorked: zohoAttendance.hoursWorked,
|
||||
status: zohoAttendance.status,
|
||||
customFields: this.mapCustomFields(zohoAttendance)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Employee Forms to standardized format
|
||||
static mapEmployeeForm(zohoEmployeeForm) {
|
||||
return {
|
||||
id: zohoEmployeeForm.id,
|
||||
employeeId: zohoEmployeeForm.employeeId,
|
||||
firstName: zohoEmployeeForm.firstName,
|
||||
lastName: zohoEmployeeForm.lastName,
|
||||
email: zohoEmployeeForm.email,
|
||||
phone: zohoEmployeeForm.phone,
|
||||
department: zohoEmployeeForm.department,
|
||||
designation: zohoEmployeeForm.designation,
|
||||
joiningDate: zohoEmployeeForm.joiningDate,
|
||||
status: zohoEmployeeForm.status,
|
||||
customFields: this.mapCustomFields(zohoEmployeeForm)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Attendance Entries to standardized format
|
||||
static mapAttendanceEntry(zohoAttendanceEntry) {
|
||||
return {
|
||||
id: zohoAttendanceEntry.id,
|
||||
employeeId: zohoAttendanceEntry.empId,
|
||||
emailId: zohoAttendanceEntry.emailId,
|
||||
date: zohoAttendanceEntry.date,
|
||||
checkIn: zohoAttendanceEntry.checkIn,
|
||||
checkOut: zohoAttendanceEntry.checkOut,
|
||||
hoursWorked: zohoAttendanceEntry.hoursWorked,
|
||||
status: zohoAttendanceEntry.status,
|
||||
customFields: this.mapCustomFields(zohoAttendanceEntry)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Shift Configuration to standardized format
|
||||
static mapShiftConfiguration(zohoShiftConfig) {
|
||||
return {
|
||||
id: zohoShiftConfig.id,
|
||||
employeeId: zohoShiftConfig.empId,
|
||||
shiftName: zohoShiftConfig.shiftName,
|
||||
startTime: zohoShiftConfig.startTime,
|
||||
endTime: zohoShiftConfig.endTime,
|
||||
breakDuration: zohoShiftConfig.breakDuration,
|
||||
workingDays: zohoShiftConfig.workingDays,
|
||||
customFields: this.mapCustomFields(zohoShiftConfig)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Leave Data to standardized format
|
||||
static mapLeaveData(zohoLeaveData) {
|
||||
return {
|
||||
id: zohoLeaveData.id,
|
||||
employeeId: zohoLeaveData.employeeId,
|
||||
leaveType: zohoLeaveData.leaveType,
|
||||
startDate: zohoLeaveData.startDate,
|
||||
endDate: zohoLeaveData.endDate,
|
||||
days: zohoLeaveData.days,
|
||||
reason: zohoLeaveData.reason,
|
||||
status: zohoLeaveData.status,
|
||||
customFields: this.mapCustomFields(zohoLeaveData)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Goals Data to standardized format
|
||||
static mapGoalsData(zohoGoalsData) {
|
||||
return {
|
||||
id: zohoGoalsData.id,
|
||||
employeeId: zohoGoalsData.employeeId,
|
||||
goalTitle: zohoGoalsData.goalTitle,
|
||||
description: zohoGoalsData.description,
|
||||
targetValue: zohoGoalsData.targetValue,
|
||||
currentValue: zohoGoalsData.currentValue,
|
||||
startDate: zohoGoalsData.startDate,
|
||||
endDate: zohoGoalsData.endDate,
|
||||
status: zohoGoalsData.status,
|
||||
customFields: this.mapCustomFields(zohoGoalsData)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho People Performance Data to standardized format
|
||||
static mapPerformanceData(zohoPerformanceData) {
|
||||
return {
|
||||
id: zohoPerformanceData.id,
|
||||
employeeId: zohoPerformanceData.employeeId,
|
||||
reviewPeriod: zohoPerformanceData.reviewPeriod,
|
||||
rating: zohoPerformanceData.rating,
|
||||
comments: zohoPerformanceData.comments,
|
||||
reviewer: zohoPerformanceData.reviewer,
|
||||
reviewDate: zohoPerformanceData.reviewDate,
|
||||
status: zohoPerformanceData.status,
|
||||
customFields: this.mapCustomFields(zohoPerformanceData)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Organization to standardized format
|
||||
static mapOrganization(zohoOrganization) {
|
||||
return {
|
||||
id: zohoOrganization.organization_id,
|
||||
name: zohoOrganization.organization_name,
|
||||
currency: zohoOrganization.currency_code,
|
||||
timezone: zohoOrganization.time_zone,
|
||||
fiscalYearStart: zohoOrganization.fiscal_year_start_month,
|
||||
accountCreatedDate: zohoOrganization.account_created_date,
|
||||
customFields: this.mapCustomFields(zohoOrganization)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Customer to standardized format
|
||||
static mapCustomer(zohoCustomer) {
|
||||
return {
|
||||
id: zohoCustomer.contact_id,
|
||||
name: zohoCustomer.contact_name,
|
||||
email: zohoCustomer.contact_persons?.[0]?.email,
|
||||
phone: zohoCustomer.contact_persons?.[0]?.phone,
|
||||
company: zohoCustomer.company_name,
|
||||
billingAddress: zohoCustomer.billing_address,
|
||||
shippingAddress: zohoCustomer.shipping_address,
|
||||
currency: zohoCustomer.currency_code,
|
||||
paymentTerms: zohoCustomer.payment_terms,
|
||||
customFields: this.mapCustomFields(zohoCustomer)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Vendor to standardized format
|
||||
static mapVendor(zohoVendor) {
|
||||
return {
|
||||
id: zohoVendor.contact_id,
|
||||
name: zohoVendor.contact_name,
|
||||
email: zohoVendor.contact_persons?.[0]?.email,
|
||||
phone: zohoVendor.contact_persons?.[0]?.phone,
|
||||
company: zohoVendor.company_name,
|
||||
billingAddress: zohoVendor.billing_address,
|
||||
shippingAddress: zohoVendor.shipping_address,
|
||||
currency: zohoVendor.currency_code,
|
||||
paymentTerms: zohoVendor.payment_terms,
|
||||
customFields: this.mapCustomFields(zohoVendor)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Item to standardized format
|
||||
static mapItem(zohoItem) {
|
||||
return {
|
||||
id: zohoItem.item_id,
|
||||
name: zohoItem.name,
|
||||
description: zohoItem.description,
|
||||
sku: zohoItem.sku,
|
||||
unit: zohoItem.unit,
|
||||
rate: zohoItem.rate,
|
||||
purchaseRate: zohoItem.purchase_rate,
|
||||
salesRate: zohoItem.sales_rate,
|
||||
itemType: zohoItem.item_type,
|
||||
status: zohoItem.status,
|
||||
customFields: this.mapCustomFields(zohoItem)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Invoice to standardized format
|
||||
static mapBooksInvoice(zohoInvoice) {
|
||||
return {
|
||||
id: zohoInvoice.invoice_id,
|
||||
invoiceNumber: zohoInvoice.invoice_number,
|
||||
customerId: zohoInvoice.customer_id,
|
||||
customerName: zohoInvoice.customer_name,
|
||||
date: zohoInvoice.date,
|
||||
dueDate: zohoInvoice.due_date,
|
||||
total: zohoInvoice.total,
|
||||
balance: zohoInvoice.balance,
|
||||
status: zohoInvoice.status,
|
||||
currency: zohoInvoice.currency_code,
|
||||
customFields: this.mapCustomFields(zohoInvoice)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Estimate to standardized format
|
||||
static mapEstimate(zohoEstimate) {
|
||||
return {
|
||||
id: zohoEstimate.estimate_id,
|
||||
estimateNumber: zohoEstimate.estimate_number,
|
||||
customerId: zohoEstimate.customer_id,
|
||||
customerName: zohoEstimate.customer_name,
|
||||
date: zohoEstimate.date,
|
||||
expiryDate: zohoEstimate.expiry_date,
|
||||
total: zohoEstimate.total,
|
||||
status: zohoEstimate.status,
|
||||
currency: zohoEstimate.currency_code,
|
||||
customFields: this.mapCustomFields(zohoEstimate)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Bill to standardized format
|
||||
static mapBill(zohoBill) {
|
||||
return {
|
||||
id: zohoBill.bill_id,
|
||||
billNumber: zohoBill.bill_number,
|
||||
vendorId: zohoBill.vendor_id,
|
||||
vendorName: zohoBill.vendor_name,
|
||||
date: zohoBill.date,
|
||||
dueDate: zohoBill.due_date,
|
||||
total: zohoBill.total,
|
||||
balance: zohoBill.balance,
|
||||
status: zohoBill.status,
|
||||
currency: zohoBill.currency_code,
|
||||
customFields: this.mapCustomFields(zohoBill)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Expense to standardized format
|
||||
static mapExpense(zohoExpense) {
|
||||
return {
|
||||
id: zohoExpense.expense_id,
|
||||
expenseNumber: zohoExpense.expense_number,
|
||||
accountId: zohoExpense.account_id,
|
||||
accountName: zohoExpense.account_name,
|
||||
date: zohoExpense.date,
|
||||
amount: zohoExpense.amount,
|
||||
description: zohoExpense.description,
|
||||
status: zohoExpense.status,
|
||||
currency: zohoExpense.currency_code,
|
||||
customFields: this.mapCustomFields(zohoExpense)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Bank Account to standardized format
|
||||
static mapBankAccount(zohoBankAccount) {
|
||||
return {
|
||||
id: zohoBankAccount.account_id,
|
||||
accountName: zohoBankAccount.account_name,
|
||||
accountNumber: zohoBankAccount.account_number,
|
||||
bankName: zohoBankAccount.bank_name,
|
||||
accountType: zohoBankAccount.account_type,
|
||||
balance: zohoBankAccount.balance,
|
||||
currency: zohoBankAccount.currency_code,
|
||||
customFields: this.mapCustomFields(zohoBankAccount)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Books Bank Transaction to standardized format
|
||||
static mapBankTransaction(zohoBankTransaction) {
|
||||
return {
|
||||
id: zohoBankTransaction.transaction_id,
|
||||
accountId: zohoBankTransaction.account_id,
|
||||
date: zohoBankTransaction.date,
|
||||
amount: zohoBankTransaction.amount,
|
||||
description: zohoBankTransaction.description,
|
||||
type: zohoBankTransaction.type,
|
||||
status: zohoBankTransaction.status,
|
||||
customFields: this.mapCustomFields(zohoBankTransaction)
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zoho Projects Project to standardized format
|
||||
static mapProject(zohoProject) {
|
||||
return {
|
||||
@ -176,13 +480,37 @@ class ZohoMapper {
|
||||
// Map multiple records using appropriate mapper
|
||||
static mapRecords(records, recordType) {
|
||||
const mapperMap = {
|
||||
// CRM
|
||||
'leads': this.mapLead,
|
||||
'contacts': this.mapContact,
|
||||
'deals': this.mapDeal,
|
||||
'sales_orders': this.mapSalesOrder,
|
||||
'purchase_orders': this.mapPurchaseOrder,
|
||||
'invoices': this.mapInvoice,
|
||||
// People
|
||||
'employees': this.mapEmployee,
|
||||
'departments': this.mapDepartment,
|
||||
'timesheets': this.mapTimesheet,
|
||||
'leave_requests': this.mapLeaveRequest,
|
||||
'attendance': this.mapAttendance,
|
||||
'employee_forms': this.mapEmployeeForm,
|
||||
'attendance_entries': this.mapAttendanceEntry,
|
||||
'shift_configuration': this.mapShiftConfiguration,
|
||||
'leave_data': this.mapLeaveData,
|
||||
'goals_data': this.mapGoalsData,
|
||||
'performance_data': this.mapPerformanceData,
|
||||
// Books
|
||||
'organizations': this.mapOrganization,
|
||||
'customers': this.mapCustomer,
|
||||
'vendors': this.mapVendor,
|
||||
'items': this.mapItem,
|
||||
'invoices': this.mapBooksInvoice,
|
||||
'estimates': this.mapEstimate,
|
||||
'bills': this.mapBill,
|
||||
'expenses': this.mapExpense,
|
||||
'bank_accounts': this.mapBankAccount,
|
||||
'bank_transactions': this.mapBankTransaction,
|
||||
// Projects
|
||||
'projects': this.mapProject,
|
||||
'tasks': this.mapTask
|
||||
};
|
||||
@ -288,10 +616,153 @@ class ZohoMapper {
|
||||
};
|
||||
break;
|
||||
|
||||
case 'sales_orders':
|
||||
case 'purchase_orders':
|
||||
case 'invoices':
|
||||
// CRM response structure for sales orders, purchase orders, and invoices
|
||||
|
||||
|
||||
case 'invoices':
|
||||
// Handle both CRM and Books invoices - check response structure
|
||||
if (zohoResponse.data && zohoResponse.info) {
|
||||
// Books response structure
|
||||
records = zohoResponse.data || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.info?.count || records.length,
|
||||
moreRecords: zohoResponse.info?.more_records || false,
|
||||
page: zohoResponse.info?.page || 1
|
||||
};
|
||||
} else {
|
||||
// CRM response structure
|
||||
records = zohoResponse.invoices || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.page_context?.count || records.length,
|
||||
moreRecords: zohoResponse.page_context?.more_records || false,
|
||||
page: zohoResponse.page_context?.page || 1
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'contacts':
|
||||
// Books response structure for contacts
|
||||
records = zohoResponse.contacts || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.page_context?.count || records.length,
|
||||
moreRecords: zohoResponse.page_context?.more_records || false,
|
||||
page: zohoResponse.page_context?.page || 1
|
||||
};
|
||||
break;
|
||||
|
||||
case 'vendors':
|
||||
// Books response structure for vendors (filtered contacts)
|
||||
records = zohoResponse.contacts || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.page_context?.count || records.length,
|
||||
moreRecords: zohoResponse.page_context?.more_records || false,
|
||||
page: zohoResponse.page_context?.page || 1
|
||||
};
|
||||
break;
|
||||
|
||||
case 'sales_orders':
|
||||
// Handle both CRM and Books sales orders - check response structure
|
||||
if (zohoResponse.data && zohoResponse.info) {
|
||||
// Books response structure
|
||||
records = zohoResponse.data || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.info?.count || records.length,
|
||||
moreRecords: zohoResponse.info?.more_records || false,
|
||||
page: zohoResponse.info?.page || 1
|
||||
};
|
||||
} else {
|
||||
// CRM response structure
|
||||
records = zohoResponse.salesorders || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.page_context?.count || records.length,
|
||||
moreRecords: zohoResponse.page_context?.more_records || false,
|
||||
page: zohoResponse.page_context?.page || 1
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'purchase_orders':
|
||||
// Handle both CRM and Books purchase orders - check response structure
|
||||
if (zohoResponse.data && zohoResponse.info) {
|
||||
// Books response structure
|
||||
records = zohoResponse.data || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.info?.count || records.length,
|
||||
moreRecords: zohoResponse.info?.more_records || false,
|
||||
page: zohoResponse.info?.page || 1
|
||||
};
|
||||
} else {
|
||||
// CRM response structure
|
||||
records = zohoResponse.purchaseorders || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.page_context?.count || records.length,
|
||||
moreRecords: zohoResponse.page_context?.more_records || false,
|
||||
page: zohoResponse.page_context?.page || 1
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'employee_forms':
|
||||
// Handle both CRM and Books sales orders - check response structure
|
||||
|
||||
// Books response structure
|
||||
records = zohoResponse.response.result || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.response.result?.count || records.length,
|
||||
moreRecords: zohoResponse.response.result?.more_records || false,
|
||||
page: zohoResponse.response.result?.page || 1
|
||||
};
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case 'departments':
|
||||
case 'timesheets':
|
||||
case 'leave_requests':
|
||||
case 'attendance':
|
||||
// People response structure
|
||||
records = zohoResponse.data || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.info?.count || records.length,
|
||||
moreRecords: zohoResponse.info?.more_records || false,
|
||||
page: zohoResponse.info?.page || 1
|
||||
};
|
||||
break;
|
||||
|
||||
case 'employee_forms':
|
||||
case 'attendance_entries':
|
||||
case 'shift_configuration':
|
||||
case 'leave_data':
|
||||
case 'goals_data':
|
||||
case 'performance_data':
|
||||
// People Forms API response structure
|
||||
records = zohoResponse.data || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.info?.count || records.length,
|
||||
moreRecords: zohoResponse.info?.more_records || false,
|
||||
page: zohoResponse.info?.page || 1
|
||||
};
|
||||
break;
|
||||
|
||||
case 'employee_detail':
|
||||
// Single employee detail response
|
||||
records = zohoResponse.data ? [zohoResponse.data] : [];
|
||||
pageInfo = {
|
||||
count: records.length,
|
||||
moreRecords: false,
|
||||
page: 1
|
||||
};
|
||||
break;
|
||||
|
||||
case 'organizations':
|
||||
case 'customers':
|
||||
case 'items':
|
||||
case 'estimates':
|
||||
case 'bills':
|
||||
case 'expenses':
|
||||
case 'bank_accounts':
|
||||
case 'bank_transactions':
|
||||
case 'reports':
|
||||
// Books response structure
|
||||
records = zohoResponse.data || [];
|
||||
pageInfo = {
|
||||
count: zohoResponse.info?.count || records.length,
|
||||
|
||||
@ -40,13 +40,33 @@ class IntegrationService {
|
||||
|
||||
getMethodName(service, resource) {
|
||||
const resourceMap = {
|
||||
// CRM
|
||||
'leads': 'Leads',
|
||||
'contacts': 'Contacts',
|
||||
'deals': 'Deals',
|
||||
'sales_orders': 'SalesOrders',
|
||||
'purchase_orders': 'PurchaseOrders',
|
||||
'invoices': 'Invoices',
|
||||
// People
|
||||
'employees': 'Employees',
|
||||
'departments': 'Departments',
|
||||
'timesheets': 'Timesheets',
|
||||
'leave_requests': 'LeaveRequests',
|
||||
'attendance': 'Attendance',
|
||||
// Books
|
||||
'organizations': 'Organizations',
|
||||
'customers': 'Customers',
|
||||
'vendors': 'Vendors',
|
||||
'items': 'Items',
|
||||
'estimates': 'Estimates',
|
||||
'bills': 'Bills',
|
||||
'expenses': 'Expenses',
|
||||
'bank_accounts': 'BankAccounts',
|
||||
'bank_transactions': 'BankTransactions',
|
||||
'reports': 'Reports',
|
||||
// Projects
|
||||
'projects': 'Projects',
|
||||
'tasks': 'Tasks',
|
||||
'timesheets': 'Timesheets'
|
||||
'tasks': 'Tasks'
|
||||
};
|
||||
|
||||
const resourceName = resourceMap[resource] || resource;
|
||||
@ -167,6 +187,262 @@ class IntegrationService {
|
||||
}
|
||||
return await client.getInvoices(params);
|
||||
}
|
||||
|
||||
// Zoho People specific methods
|
||||
async getDepartments(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Departments are only available for Zoho provider');
|
||||
}
|
||||
return await client.getDepartments(params);
|
||||
}
|
||||
|
||||
async getLeaveRequests(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Leave Requests are only available for Zoho provider');
|
||||
}
|
||||
return await client.getLeaveRequests(params);
|
||||
}
|
||||
|
||||
async getAttendance(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Attendance is only available for Zoho provider');
|
||||
}
|
||||
return await client.getAttendance(params);
|
||||
}
|
||||
|
||||
// Zoho Books specific methods
|
||||
async getOrganizations(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Organizations are only available for Zoho provider');
|
||||
}
|
||||
return await client.getOrganizations(params);
|
||||
}
|
||||
|
||||
async getCustomers(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Customers are only available for Zoho provider');
|
||||
}
|
||||
return await client.getCustomers(params);
|
||||
}
|
||||
|
||||
async getVendors(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Vendors are only available for Zoho provider');
|
||||
}
|
||||
return await client.getVendors(params);
|
||||
}
|
||||
|
||||
async getItems(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Items are only available for Zoho provider');
|
||||
}
|
||||
return await client.getItems(params);
|
||||
}
|
||||
|
||||
async getEstimates(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Estimates are only available for Zoho provider');
|
||||
}
|
||||
return await client.getEstimates(params);
|
||||
}
|
||||
|
||||
async getBills(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Bills are only available for Zoho provider');
|
||||
}
|
||||
return await client.getBills(params);
|
||||
}
|
||||
|
||||
async getExpenses(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Expenses are only available for Zoho provider');
|
||||
}
|
||||
return await client.getExpenses(params);
|
||||
}
|
||||
|
||||
async getBankAccounts(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Bank Accounts are only available for Zoho provider');
|
||||
}
|
||||
return await client.getBankAccounts(params);
|
||||
}
|
||||
|
||||
async getBankTransactions(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Bank Transactions are only available for Zoho provider');
|
||||
}
|
||||
return await client.getBankTransactions(params);
|
||||
}
|
||||
|
||||
async getReports(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Reports are only available for Zoho provider');
|
||||
}
|
||||
return await client.getReports(params);
|
||||
}
|
||||
|
||||
async getBooksSalesOrders(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Books Sales Orders are only available for Zoho provider');
|
||||
}
|
||||
return await client.getBooksSalesOrders(params);
|
||||
}
|
||||
|
||||
async getBooksPurchaseOrders(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Books Purchase Orders are only available for Zoho provider');
|
||||
}
|
||||
return await client.getBooksPurchaseOrders(params);
|
||||
}
|
||||
|
||||
async getContacts(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Contacts are only available for Zoho provider');
|
||||
}
|
||||
return await client.getContacts(params);
|
||||
}
|
||||
|
||||
// Zoho People Forms API methods
|
||||
async getEmployeeForms(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Employee Forms are only available for Zoho provider');
|
||||
}
|
||||
return await client.getEmployeeForms(params);
|
||||
}
|
||||
|
||||
async getEmployeeById(provider, recordId, formLinkName = 'employee') {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Employee Details are only available for Zoho provider');
|
||||
}
|
||||
return await client.getEmployeeById(recordId, formLinkName);
|
||||
}
|
||||
|
||||
async getAttendanceEntries(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Attendance Entries are only available for Zoho provider');
|
||||
}
|
||||
return await client.getAttendanceEntries(params);
|
||||
}
|
||||
|
||||
async getShiftConfiguration(provider, params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Shift Configuration is only available for Zoho provider');
|
||||
}
|
||||
return await client.getShiftConfiguration(params);
|
||||
}
|
||||
|
||||
async getLeaveData(provider, formLinkName = 'leave', params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Leave Data is only available for Zoho provider');
|
||||
}
|
||||
return await client.getLeaveData(formLinkName, params);
|
||||
}
|
||||
|
||||
async getGoalsData(provider, formLinkName = 'goals', params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Goals Data is only available for Zoho provider');
|
||||
}
|
||||
return await client.getGoalsData(formLinkName, params);
|
||||
}
|
||||
|
||||
async getPerformanceData(provider, formLinkName = 'performance', params = {}) {
|
||||
const client = this.clients[provider];
|
||||
if (!client) {
|
||||
throw new Error(`Provider ${provider} not supported`);
|
||||
}
|
||||
if (provider !== 'zoho') {
|
||||
throw new Error('Performance Data is only available for Zoho provider');
|
||||
}
|
||||
return await client.getPerformanceData(formLinkName, params);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IntegrationService;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user