diff --git a/backend/Actions/WpErp/RecordApiHelper.php b/backend/Actions/WpErp/RecordApiHelper.php new file mode 100644 index 000000000..630e8e17f --- /dev/null +++ b/backend/Actions/WpErp/RecordApiHelper.php @@ -0,0 +1,104 @@ +_integrationDetails = $integrationDetails; + $this->_integrationID = $integId; + } + + public function execute($fieldValues, $fieldMap, $utilities) + { + if (!\function_exists('erp_insert_people')) { + return [ + 'success' => false, + 'message' => __('WP ERP is not installed or activated', 'bit-integrations') + ]; + } + + $fieldData = static::generateReqDataFromFieldMap($fieldMap, $fieldValues); + $mainAction = $this->_integrationDetails->mainAction ?? ''; + + $defaultResponse = [ + 'success' => false, + // translators: %s: Plugin name + 'message' => wp_sprintf(__('%s plugin is not installed or activated', 'bit-integrations'), 'Bit Integrations Pro') + ]; + + $hookMap = [ + 'createContact' => ['hook' => 'wperp_create_contact', 'type' => 'contact'], + 'updateContact' => ['hook' => 'wperp_update_contact', 'type' => 'contact'], + 'createCompany' => ['hook' => 'wperp_create_company', 'type' => 'company'], + 'updateCompany' => ['hook' => 'wperp_update_company', 'type' => 'company'], + 'createContactGroup' => ['hook' => 'wperp_create_contact_group', 'type' => 'contact_group'], + 'addContactToGroup' => ['hook' => 'wperp_add_contact_to_group', 'type' => 'contact_group'], + 'removeContactFromGroup' => ['hook' => 'wperp_remove_contact_from_group', 'type' => 'contact_group'], + 'addNote' => ['hook' => 'wperp_add_note', 'type' => 'note'], + 'createTask' => ['hook' => 'wperp_create_task', 'type' => 'task'], + 'createDepartment' => ['hook' => 'wperp_create_department', 'type' => 'department'], + 'createDesignation' => ['hook' => 'wperp_create_designation', 'type' => 'designation'], + 'createHoliday' => ['hook' => 'wperp_create_holiday', 'type' => 'holiday'], + 'createExpense' => ['hook' => 'wperp_create_expense', 'type' => 'expense'], + 'createPayment' => ['hook' => 'wperp_create_payment', 'type' => 'payment'], + ]; + + if (!isset($hookMap[$mainAction])) { + $response = [ + 'success' => false, + 'message' => __('Invalid action', 'bit-integrations') + ]; + $type = 'WpErp'; + $actionType = 'unknown'; + } else { + $entry = $hookMap[$mainAction]; + $response = Hooks::apply( + Config::withPrefix($entry['hook']), + $defaultResponse, + $fieldData, + $utilities, + ); + $type = $entry['type']; + $actionType = $mainAction; + } + + $responseType = (!is_wp_error($response) && isset($response['success']) && $response['success']) ? 'success' : 'error'; + LogHandler::save($this->_integrationID, ['type' => $type, 'type_name' => $actionType], $responseType, $response); + + return $response; + } + + private static function generateReqDataFromFieldMap($fieldMap, $fieldValues) + { + $dataFinal = []; + foreach ($fieldMap as $item) { + $triggerValue = $item->formField; + $actionValue = $item->wpErpField; + + if (empty($actionValue)) { + continue; + } + + $dataFinal[$actionValue] = $triggerValue === 'custom' && isset($item->customValue) + ? Common::replaceFieldWithValue($item->customValue, $fieldValues) + : ($fieldValues[$triggerValue] ?? ''); + } + + return $dataFinal; + } +} diff --git a/backend/Actions/WpErp/Routes.php b/backend/Actions/WpErp/Routes.php new file mode 100644 index 000000000..c2e951bc5 --- /dev/null +++ b/backend/Actions/WpErp/Routes.php @@ -0,0 +1,14 @@ + $group['id'] ?? '', + 'label' => $group['name'] ?? '', + ]; + }, + (array) erp_crm_get_contact_groups(['number' => -1]) + ); + } + + wp_send_json_success(['groups' => $groups], 200); + } + + public function refreshLifeStages() + { + self::isExists(); + + $stages = []; + + if (\function_exists('erp_crm_get_life_stages_dropdown_raw')) { + foreach ((array) erp_crm_get_life_stages_dropdown_raw() as $value => $label) { + $stages[] = (object) ['value' => $value, 'label' => $label]; + } + } + + wp_send_json_success(['stages' => $stages], 200); + } + + public function refreshDepartments() + { + self::isExists(); + + $out = []; + + if (\function_exists('erp_hr_get_departments')) { + foreach ((array) erp_hr_get_departments(['number' => -1, 'no_object' => true]) as $dept) { + $dept = (array) $dept; + $out[] = (object) [ + 'value' => $dept['id'] ?? '', + 'label' => $dept['title'] ?? '', + ]; + } + } + + wp_send_json_success(['departments' => $out], 200); + } + + public function refreshDesignations() + { + self::isExists(); + + $out = []; + + if (\function_exists('erp_hr_get_designations')) { + foreach ((array) erp_hr_get_designations(['number' => -1, 'no_object' => true]) as $designation) { + $designation = (array) $designation; + $out[] = (object) [ + 'value' => $designation['id'] ?? '', + 'label' => $designation['title'] ?? '', + ]; + } + } + + wp_send_json_success(['designations' => $out], 200); + } + + public function execute($integrationData, $fieldValues) + { + $integrationDetails = $integrationData->flow_details; + $integId = $integrationData->id; + $fieldMap = $integrationDetails->field_map; + $utilities = $integrationDetails->utilities ?? []; + + if (empty($fieldMap)) { + return new WP_Error('field_map_empty', __('Field map is empty', 'bit-integrations')); + } + + $recordApiHelper = new RecordApiHelper($integrationDetails, $integId); + $wpErpResponse = $recordApiHelper->execute($fieldValues, $fieldMap, $utilities); + + if (is_wp_error($wpErpResponse)) { + return $wpErpResponse; + } + + return $wpErpResponse; + } +} diff --git a/backend/Core/Util/AllTriggersName.php b/backend/Core/Util/AllTriggersName.php index fce2979b7..11a286fd2 100644 --- a/backend/Core/Util/AllTriggersName.php +++ b/backend/Core/Util/AllTriggersName.php @@ -155,6 +155,7 @@ public static function allTriggersName() 'WSForm' => ['name' => 'WSForm', 'isPro' => true, 'is_active' => false], 'WishlistMember' => ['name' => 'Wishlist Member', 'isPro' => true, 'is_active' => false], 'WpAllImport' => ['name' => 'WP All Import', 'isPro' => true, 'is_active' => false], + 'WpErp' => ['name' => 'WP ERP', 'isPro' => true, 'is_active' => false], 'WPLMS' => ['name' => 'WPLMS', 'isPro' => true, 'is_active' => false], 'WPLoyalty' => ['name' => 'WPLoyalty', 'isPro' => true, 'is_active' => false], 'WPSubscription' => ['name' => 'WPSubscription', 'isPro' => true, 'is_active' => false], diff --git a/backend/Flow/Flow.php b/backend/Flow/Flow.php index 194cc22c6..fe20807aa 100644 --- a/backend/Flow/Flow.php +++ b/backend/Flow/Flow.php @@ -498,6 +498,11 @@ public static function execute($triggered_entity, $triggered_entity_id, $data, $ break; + case 'WPERP': + $integrationName = 'WpErp'; + + break; + case 'Monday.Com': $integrationName = 'MondayCom'; diff --git a/frontend/src/components/AllIntegrations/EditInteg.jsx b/frontend/src/components/AllIntegrations/EditInteg.jsx index a87818398..d84a52ef0 100644 --- a/frontend/src/components/AllIntegrations/EditInteg.jsx +++ b/frontend/src/components/AllIntegrations/EditInteg.jsx @@ -173,6 +173,7 @@ const EditWishlistMember = lazy(() => import('./WishlistMember/EditWishlistMembe const EditCreatorLms = lazy(() => import('./CreatorLms/EditCreatorLms')) const EditUltimateAffiliatePro = lazy(() => import('./UltimateAffiliatePro/EditUltimateAffiliatePro')) const EditFluentCart = lazy(() => import('./FluentCart/EditFluentCart')) +const EditWpErp = lazy(() => import('./WpErp/EditWpErp')) const EditPeepSo = lazy(() => import('./PeepSo/EditPeepSo')) const EditNinjaTables = lazy(() => import('./NinjaTables/EditNinjaTables')) const EditWCAffiliate = lazy(() => import('./WCAffiliate/EditWCAffiliate')) @@ -597,6 +598,8 @@ const IntegType = memo(({ allIntegURL, flow }) => { return case 'FluentCart': return + case 'WP ERP': + return case 'PeepSo': return case 'Ninja Tables': diff --git a/frontend/src/components/AllIntegrations/IntegInfo.jsx b/frontend/src/components/AllIntegrations/IntegInfo.jsx index 0a797372c..63000fed7 100644 --- a/frontend/src/components/AllIntegrations/IntegInfo.jsx +++ b/frontend/src/components/AllIntegrations/IntegInfo.jsx @@ -176,6 +176,7 @@ const UltimateAffiliateProAuthorization = lazy( () => import('./UltimateAffiliatePro/UltimateAffiliateProAuthorization') ) const FluentCartAuthorization = lazy(() => import('./FluentCart/FluentCartAuthorization')) +const WpErpAuthorization = lazy(() => import('./WpErp/WpErpAuthorization')) const PeepSoAuthorization = lazy(() => import('./PeepSo/PeepSoAuthorization')) const NinjaTablesAuthorization = lazy(() => import('./NinjaTables/NinjaTablesAuthorization')) const WCAffiliateAuthorization = lazy(() => import('./WCAffiliate/WCAffiliateAuthorization')) @@ -640,6 +641,8 @@ export default function IntegInfo() { ) case 'FluentCart': return + case 'WP ERP': + return case 'PeepSo': return case 'Ninja Tables': diff --git a/frontend/src/components/AllIntegrations/NewInteg.jsx b/frontend/src/components/AllIntegrations/NewInteg.jsx index 59978c59c..148063469 100644 --- a/frontend/src/components/AllIntegrations/NewInteg.jsx +++ b/frontend/src/components/AllIntegrations/NewInteg.jsx @@ -172,6 +172,7 @@ const WishlistMember = lazy(() => import('./WishlistMember/WishlistMember')) const CreatorLms = lazy(() => import('./CreatorLms/CreatorLms')) const UltimateAffiliatePro = lazy(() => import('./UltimateAffiliatePro/UltimateAffiliatePro')) const FluentCart = lazy(() => import('./FluentCart/FluentCart')) +const WpErp = lazy(() => import('./WpErp/WpErp')) const PeepSo = lazy(() => import('./PeepSo/PeepSo')) const NinjaTables = lazy(() => import('./NinjaTables/NinjaTables')) const WCAffiliate = lazy(() => import('./WCAffiliate/WCAffiliate')) @@ -1679,6 +1680,15 @@ export default function NewInteg({ allIntegURL }) { setFlow={setFlow} /> ) + case 'WP ERP': + return ( + + ) case 'PeepSo': return ( + + +
+ {__('Integration Name:', 'bit-integrations')} + handleInput(e, wpErpConf, setWpErpConf)} + name="name" + value={wpErpConf.name} + type="text" + placeholder={__('Integration Name...', 'bit-integrations')} + /> +
+
+ + + + + + + saveActionConf({ + flow, + setFlow, + allIntegURL, + conf: wpErpConf, + navigate, + id, + edit: 1, + setIsLoading, + setSnackbar + }) + } + disabled={!checkMappedFields(wpErpConf)} + isLoading={isLoading} + dataConf={wpErpConf} + setDataConf={setWpErpConf} + formFields={formFields} + /> +
+ + ) +} diff --git a/frontend/src/components/AllIntegrations/WpErp/WpErp.jsx b/frontend/src/components/AllIntegrations/WpErp/WpErp.jsx new file mode 100644 index 000000000..f7d863c46 --- /dev/null +++ b/frontend/src/components/AllIntegrations/WpErp/WpErp.jsx @@ -0,0 +1,103 @@ +import { useState } from 'react' +import 'react-multiple-select-dropdown-lite/dist/index.css' +import { useNavigate, useParams } from 'react-router' +import BackIcn from '../../../Icons/BackIcn' +import { __ } from '../../../Utils/i18nwrap' +import SnackMsg from '../../Utilities/SnackMsg' +import { saveIntegConfig } from '../IntegrationHelpers/IntegrationHelpers' +import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' +import WpErpAuthorization from './WpErpAuthorization' +import { checkMappedFields } from './WpErpCommonFunc' +import WpErpIntegLayout from './WpErpIntegLayout' + +export default function WpErp({ formFields, setFlow, flow, allIntegURL }) { + const navigate = useNavigate() + const { formID } = useParams() + const [isLoading, setIsLoading] = useState(false) + const [step, setStep] = useState(1) + const [snack, setSnackbar] = useState({ show: false }) + const [wpErpConf, setWpErpConf] = useState({ + name: 'WP ERP', + type: 'WP ERP', + field_map: [{ formField: '', wpErpField: '' }], + actions: {}, + utilities: {}, + mainAction: '' + }) + + const nextPage = val => { + setTimeout(() => { + document.getElementById('btcd-settings-wrp').scrollTop = 0 + }, 300) + + if (val === 3) { + if (!checkMappedFields(wpErpConf)) { + setSnackbar({ + show: true, + msg: __('Please map all required fields to continue.', 'bit-integrations') + }) + return + } + + if (wpErpConf.name !== '' && wpErpConf.field_map.length > 0) { + setStep(val) + } + } else { + setStep(val) + } + } + + return ( +
+ + + + +
+ +
+
+
+ +
+ + + saveIntegConfig(flow, setFlow, allIntegURL, wpErpConf, navigate, '', '', setIsLoading) + } + isLoading={isLoading} + /> +
+ ) +} diff --git a/frontend/src/components/AllIntegrations/WpErp/WpErpAuthorization.jsx b/frontend/src/components/AllIntegrations/WpErp/WpErpAuthorization.jsx new file mode 100644 index 000000000..382e48254 --- /dev/null +++ b/frontend/src/components/AllIntegrations/WpErp/WpErpAuthorization.jsx @@ -0,0 +1,112 @@ +import { useState } from 'react' +import BackIcn from '../../../Icons/BackIcn' +import bitsFetch from '../../../Utils/bitsFetch' +import { __ } from '../../../Utils/i18nwrap' +import LoaderSm from '../../Loaders/LoaderSm' + +export default function WpErpAuthorization({ + wpErpConf, + setWpErpConf, + step, + nextPage, + isLoading, + setIsLoading, + setSnackbar, + isInfo +}) { + const [isAuthorized, setIsAuthorized] = useState(false) + const [showAuthMsg, setShowAuthMsg] = useState(false) + + const authorizeHandler = () => { + setIsLoading('auth') + bitsFetch({}, 'wp_erp_authorize').then(result => { + if (result?.success) { + setIsAuthorized(true) + setSnackbar({ + show: true, + msg: __('Connected with WP ERP Successfully', 'bit-integrations') + }) + } + setIsLoading(false) + setShowAuthMsg(true) + }) + } + + const handleInput = e => { + const newConf = { ...wpErpConf } + newConf[e.target.name] = e.target.value + setWpErpConf(newConf) + } + + return ( +
+
+ {__('Integration Name:', 'bit-integrations')} +
+ + + {isLoading === 'auth' && ( +
+ + {__('Checking if WP ERP is authorized!!!', 'bit-integrations')} +
+ )} + + {showAuthMsg && !isAuthorized && !isLoading && ( +
+
+
+ +
+
+ {__('WP ERP is not activated or not installed', 'bit-integrations')} +
+
+
+ )} + + {showAuthMsg && isAuthorized && !isLoading && ( +
+
+ +
+
{__('WP ERP is activated', 'bit-integrations')}
+
+ )} + + {!isInfo && ( + <> + +
+ + + )} +
+ ) +} diff --git a/frontend/src/components/AllIntegrations/WpErp/WpErpCommonFunc.js b/frontend/src/components/AllIntegrations/WpErp/WpErpCommonFunc.js new file mode 100644 index 000000000..c47f93a73 --- /dev/null +++ b/frontend/src/components/AllIntegrations/WpErp/WpErpCommonFunc.js @@ -0,0 +1,68 @@ +import { create } from 'mutative' +import toast from 'react-hot-toast' +import bitsFetch from '../../../Utils/bitsFetch' +import { __, sprintf } from '../../../Utils/i18nwrap' + +export const handleInput = (e, wpErpConf, setWpErpConf) => { + const { name, value } = e.target + + setWpErpConf(prevConf => + create(prevConf, draftConf => { + draftConf[name] = value + }) + ) +} + +export const checkMappedFields = wpErpConf => { + if (!wpErpConf?.mainAction) return false + + const mappedFields = wpErpConf?.field_map + ? wpErpConf.field_map.filter( + mappedField => + !mappedField.formField || + !mappedField.wpErpField || + (mappedField.formField === 'custom' && !mappedField.customValue) + ) + : [] + + return mappedFields.length === 0 +} + +export const generateMappedField = fields => { + const requiredFlds = fields.filter(fld => fld.required === true) + return requiredFlds.length > 0 + ? requiredFlds.map(field => ({ formField: '', wpErpField: field.key })) + : [{ formField: '', wpErpField: '' }] +} + +const refreshGeneric = (endpoint, dataKey, setWpErpConf, setIsLoading, draftKey, label) => { + setIsLoading(true) + bitsFetch(null, endpoint) + .then(result => { + if (result?.success && result?.data?.[dataKey]) { + setWpErpConf(prevConf => + create(prevConf, draftConf => { + draftConf[draftKey] = result.data[dataKey] + }) + ) + setIsLoading(false) + toast.success(sprintf(__(`%s fetched successfully`, 'bit-integrations'), label)) + return + } + setIsLoading(false) + toast.error(sprintf(__(`%s fetch failed. Please try again`, 'bit-integrations'), label)) + }) + .catch(() => setIsLoading(false)) +} + +export const refreshContactGroups = (setWpErpConf, setIsLoading) => + refreshGeneric('refresh_wp_erp_contact_groups', 'groups', setWpErpConf, setIsLoading, 'allContactGroups', 'Contact groups') + +export const refreshLifeStages = (setWpErpConf, setIsLoading) => + refreshGeneric('refresh_wp_erp_life_stages', 'stages', setWpErpConf, setIsLoading, 'allLifeStages', 'Life stages') + +export const refreshDepartments = (setWpErpConf, setIsLoading) => + refreshGeneric('refresh_wp_erp_departments', 'departments', setWpErpConf, setIsLoading, 'allDepartments', 'Departments') + +export const refreshDesignations = (setWpErpConf, setIsLoading) => + refreshGeneric('refresh_wp_erp_designations', 'designations', setWpErpConf, setIsLoading, 'allDesignations', 'Designations') diff --git a/frontend/src/components/AllIntegrations/WpErp/WpErpFieldMap.jsx b/frontend/src/components/AllIntegrations/WpErp/WpErpFieldMap.jsx new file mode 100644 index 000000000..542773e61 --- /dev/null +++ b/frontend/src/components/AllIntegrations/WpErp/WpErpFieldMap.jsx @@ -0,0 +1,104 @@ +import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' +import { __, sprintf } from '../../../Utils/i18nwrap' +import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' +import TagifyInput from '../../Utilities/TagifyInput' +import { + addFieldMap, + delFieldMap, + handleCustomValue, + handleFieldMapping +} from '../GlobalIntegrationHelper' + +export default function WpErpFieldMap({ i, formFields, field, wpErpConf, setWpErpConf }) { + const btcbi = useRecoilValue($appConfigState) + const { isPro } = btcbi + + const requiredFlds = wpErpConf?.wpErpFields?.filter(fld => fld.required === true) || [] + const nonRequiredFlds = wpErpConf?.wpErpFields?.filter(fld => fld.required === false) || [] + + return ( +
+
+
+ + + {field.formField === 'custom' && ( + handleCustomValue(e, i, wpErpConf, setWpErpConf)} + label={__('Custom Value', 'bit-integrations')} + className="mr-2" + type="text" + value={field.customValue} + placeholder={__('Custom Value', 'bit-integrations')} + formFields={formFields} + /> + )} + + +
+ {i >= requiredFlds.length && ( + <> + + + + )} +
+
+ ) +} diff --git a/frontend/src/components/AllIntegrations/WpErp/WpErpIntegLayout.jsx b/frontend/src/components/AllIntegrations/WpErp/WpErpIntegLayout.jsx new file mode 100644 index 000000000..c0bb57116 --- /dev/null +++ b/frontend/src/components/AllIntegrations/WpErp/WpErpIntegLayout.jsx @@ -0,0 +1,218 @@ +import { create } from 'mutative' +import { useEffect } from 'react' +import MultiSelect from 'react-multiple-select-dropdown-lite' +import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' +import { __ } from '../../../Utils/i18nwrap' +import Loader from '../../Loaders/Loader' +import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' +import { addFieldMap } from '../IntegrationHelpers/IntegrationHelpers' +import { + generateMappedField, + refreshContactGroups, + refreshLifeStages +} from './WpErpCommonFunc' +import WpErpFieldMap from './WpErpFieldMap' +import { + CompanyFields, + CompanyUpdateFields, + ContactFields, + ContactGroupFields, + ContactUpdateFields, + DepartmentFields, + DesignationFields, + ExpenseFields, + GroupSubscriberFields, + HolidayFields, + modules, + NoteFields, + PaymentFields, + TaskFields +} from './staticData' + +const FIELDS_BY_ACTION = { + createContact: ContactFields, + updateContact: ContactUpdateFields, + createCompany: CompanyFields, + updateCompany: CompanyUpdateFields, + createContactGroup: ContactGroupFields, + addContactToGroup: GroupSubscriberFields, + removeContactFromGroup: GroupSubscriberFields, + addNote: NoteFields, + createTask: TaskFields, + createDepartment: DepartmentFields, + createDesignation: DesignationFields, + createHoliday: HolidayFields, + createExpense: ExpenseFields, + createPayment: PaymentFields +} + +const CRM_GROUP_ACTIONS = ['createContact', 'updateContact', 'addContactToGroup', 'removeContactFromGroup'] +const LIFE_STAGE_ACTIONS = ['createContact', 'updateContact'] + +export default function WpErpIntegLayout({ + formFields, + wpErpConf, + setWpErpConf, + isLoading, + setIsLoading +}) { + const btcbi = useRecoilValue($appConfigState) + const { isPro } = btcbi + + const handleMainAction = value => { + setWpErpConf(prevConf => + create(prevConf, draftConf => { + draftConf.mainAction = value + draftConf.wpErpFields = FIELDS_BY_ACTION[value] || [] + draftConf.field_map = generateMappedField(draftConf.wpErpFields) + }) + ) + + if (CRM_GROUP_ACTIONS.includes(value)) refreshContactGroups(setWpErpConf, setIsLoading) + if (LIFE_STAGE_ACTIONS.includes(value)) refreshLifeStages(setWpErpConf, setIsLoading) + } + + useEffect(() => { + if (wpErpConf?.mainAction && !wpErpConf?.wpErpFields) { + setWpErpConf(prev => + create(prev, draft => { + draft.wpErpFields = FIELDS_BY_ACTION[prev.mainAction] || [] + }) + ) + } + }, [wpErpConf?.mainAction]) + + const setUtility = (key, val) => + setWpErpConf(prev => + create(prev, draft => { + draft.utilities = { ...(draft.utilities || {}), [key]: val } + }) + ) + + const groupedOptions = modules.map(action => ({ + label: checkIsPro(isPro, action.is_pro) + ? `${action.group}: ${action.label}` + : getProLabel(`${action.group}: ${action.label}`), + value: action.name, + disabled: !checkIsPro(isPro, action.is_pro) + })) + + return ( + <> +
+
+ {__('Action:', 'bit-integrations')} + handleMainAction(value)} + options={groupedOptions} + singleSelect + closeOnSelect + /> +
+ + {LIFE_STAGE_ACTIONS.includes(wpErpConf?.mainAction) && ( + <> +
+
+ {__('Life Stage:', 'bit-integrations')} + setUtility('lifeStage', val)} + singleSelect + closeOnSelect + /> + +
+ + )} + + {CRM_GROUP_ACTIONS.includes(wpErpConf?.mainAction) && ( + <> +
+
+ {__('Contact Groups:', 'bit-integrations')} + ({ label: group?.label, value: group?.value?.toString() }))} + onChange={val => setUtility('groupId', val)} + /> + +
+ + )} + + {isLoading && ( + + )} + + {wpErpConf?.mainAction && wpErpConf?.wpErpFields && ( +
+ {__('Map Fields', 'bit-integrations')} +
+
+
+ {__('Form Fields', 'bit-integrations')} +
+
+ {__('WP ERP Fields', 'bit-integrations')} +
+
+ + {wpErpConf?.field_map?.map((itm, i) => ( + + ))} +
+ +
+
+
+
+ )} + + ) +} diff --git a/frontend/src/components/AllIntegrations/WpErp/staticData.js b/frontend/src/components/AllIntegrations/WpErp/staticData.js new file mode 100644 index 000000000..138d94710 --- /dev/null +++ b/frontend/src/components/AllIntegrations/WpErp/staticData.js @@ -0,0 +1,141 @@ +import { __ } from '../../../Utils/i18nwrap' + +export const modules = [ + // CRM + { name: 'createContact', label: __('Create Contact', 'bit-integrations'), is_pro: true, group: 'CRM' }, + { name: 'updateContact', label: __('Update Contact', 'bit-integrations'), is_pro: true, group: 'CRM' }, + { name: 'createCompany', label: __('Create Company', 'bit-integrations'), is_pro: true, group: 'CRM' }, + { name: 'updateCompany', label: __('Update Company', 'bit-integrations'), is_pro: true, group: 'CRM' }, + { name: 'createContactGroup', label: __('Create Contact Group', 'bit-integrations'), is_pro: true, group: 'CRM' }, + { name: 'addContactToGroup', label: __('Add Contact To Group', 'bit-integrations'), is_pro: true, group: 'CRM' }, + { name: 'removeContactFromGroup', label: __('Remove Contact From Group', 'bit-integrations'), is_pro: true, group: 'CRM' }, + { name: 'addNote', label: __('Add Note To Contact', 'bit-integrations'), is_pro: true, group: 'CRM' }, + { name: 'createTask', label: __('Create Task', 'bit-integrations'), is_pro: true, group: 'CRM' }, + // HRM + { name: 'createDepartment', label: __('Create Department', 'bit-integrations'), is_pro: true, group: 'HRM' }, + { name: 'createDesignation', label: __('Create Designation', 'bit-integrations'), is_pro: true, group: 'HRM' }, + { name: 'createHoliday', label: __('Create Holiday', 'bit-integrations'), is_pro: true, group: 'HRM' }, + // Accounting + { name: 'createExpense', label: __('Create Expense', 'bit-integrations'), is_pro: true, group: 'Accounting' }, + { name: 'createPayment', label: __('Create Payment', 'bit-integrations'), is_pro: true, group: 'Accounting' } +] + +export const ContactFields = [ + { key: 'first_name', label: __('First Name', 'bit-integrations'), required: true }, + { key: 'email', label: __('Email', 'bit-integrations'), required: true }, + { key: 'last_name', label: __('Last Name', 'bit-integrations'), required: false }, + { key: 'company', label: __('Company', 'bit-integrations'), required: false }, + { key: 'phone', label: __('Phone', 'bit-integrations'), required: false }, + { key: 'mobile', label: __('Mobile', 'bit-integrations'), required: false }, + { key: 'website', label: __('Website', 'bit-integrations'), required: false }, + { key: 'fax', label: __('Fax', 'bit-integrations'), required: false }, + { key: 'notes', label: __('Notes', 'bit-integrations'), required: false }, + { key: 'street_1', label: __('Street 1', 'bit-integrations'), required: false }, + { key: 'street_2', label: __('Street 2', 'bit-integrations'), required: false }, + { key: 'city', label: __('City', 'bit-integrations'), required: false }, + { key: 'state', label: __('State', 'bit-integrations'), required: false }, + { key: 'postal_code', label: __('Postal Code', 'bit-integrations'), required: false }, + { key: 'country', label: __('Country', 'bit-integrations'), required: false }, + { key: 'currency', label: __('Currency', 'bit-integrations'), required: false } +] + +export const ContactUpdateFields = [ + { key: 'id', label: __('Contact ID', 'bit-integrations'), required: true }, + { key: 'first_name', label: __('First Name', 'bit-integrations'), required: false }, + { key: 'last_name', label: __('Last Name', 'bit-integrations'), required: false }, + { key: 'email', label: __('Email', 'bit-integrations'), required: false }, + { key: 'phone', label: __('Phone', 'bit-integrations'), required: false }, + { key: 'mobile', label: __('Mobile', 'bit-integrations'), required: false }, + { key: 'company', label: __('Company', 'bit-integrations'), required: false }, + { key: 'website', label: __('Website', 'bit-integrations'), required: false }, + { key: 'street_1', label: __('Street 1', 'bit-integrations'), required: false }, + { key: 'street_2', label: __('Street 2', 'bit-integrations'), required: false }, + { key: 'city', label: __('City', 'bit-integrations'), required: false }, + { key: 'state', label: __('State', 'bit-integrations'), required: false }, + { key: 'postal_code', label: __('Postal Code', 'bit-integrations'), required: false }, + { key: 'country', label: __('Country', 'bit-integrations'), required: false } +] + +export const CompanyFields = [ + { key: 'company', label: __('Company Name', 'bit-integrations'), required: true }, + { key: 'email', label: __('Email', 'bit-integrations'), required: true }, + { key: 'phone', label: __('Phone', 'bit-integrations'), required: false }, + { key: 'website', label: __('Website', 'bit-integrations'), required: false }, + { key: 'fax', label: __('Fax', 'bit-integrations'), required: false }, + { key: 'street_1', label: __('Street 1', 'bit-integrations'), required: false }, + { key: 'street_2', label: __('Street 2', 'bit-integrations'), required: false }, + { key: 'city', label: __('City', 'bit-integrations'), required: false }, + { key: 'state', label: __('State', 'bit-integrations'), required: false }, + { key: 'postal_code', label: __('Postal Code', 'bit-integrations'), required: false }, + { key: 'country', label: __('Country', 'bit-integrations'), required: false } +] + +export const CompanyUpdateFields = [ + { key: 'id', label: __('Company ID', 'bit-integrations'), required: true }, + ...CompanyFields.map(f => ({ ...f, required: false })).filter(f => f.key !== 'id') +] + +export const ContactGroupFields = [ + { key: 'name', label: __('Group Name', 'bit-integrations'), required: true }, + { key: 'description', label: __('Description', 'bit-integrations'), required: false } +] + +export const GroupSubscriberFields = [ + { key: 'contact_id', label: __('Contact ID', 'bit-integrations'), required: true }, +] + +export const NoteFields = [ + { key: 'user_id', label: __('Contact User ID', 'bit-integrations'), required: true }, + { key: 'message', label: __('Message', 'bit-integrations'), required: true } +] + +export const TaskFields = [ + { key: 'title', label: __('Title', 'bit-integrations'), required: true }, + { key: 'contact_id', label: __('Contact ID', 'bit-integrations'), required: true }, + { key: 'message', label: __('Message', 'bit-integrations'), required: false }, + { key: 'start_date', label: __('Start Date (Y-m-d H:i:s)', 'bit-integrations'), required: false }, + { key: 'end_date', label: __('End Date (Y-m-d H:i:s)', 'bit-integrations'), required: false }, + { key: 'assigned_to', label: __('Assigned To User ID', 'bit-integrations'), required: false } +] + +export const DepartmentFields = [ + { key: 'title', label: __('Department Title', 'bit-integrations'), required: true }, + { key: 'description', label: __('Description', 'bit-integrations'), required: false }, + { key: 'lead', label: __('Lead User ID', 'bit-integrations'), required: false }, + { key: 'parent', label: __('Parent Department ID', 'bit-integrations'), required: false } +] + +export const DesignationFields = [ + { key: 'title', label: __('Designation Title', 'bit-integrations'), required: true }, + { key: 'description', label: __('Description', 'bit-integrations'), required: false } +] + +export const HolidayFields = [ + { key: 'title', label: __('Title', 'bit-integrations'), required: true }, + { key: 'start', label: __('Start Date', 'bit-integrations'), required: true }, + { key: 'end', label: __('End Date', 'bit-integrations'), required: true }, + { key: 'description', label: __('Description', 'bit-integrations'), required: false } +] + +export const ExpenseFields = [ + { key: 'amount', label: __('Amount', 'bit-integrations'), required: true }, + { key: 'people_id', label: __('People ID', 'bit-integrations'), required: false }, + { key: 'voucher_date', label: __('Voucher Date (Y-m-d)', 'bit-integrations'), required: false }, + { key: 'trn_date', label: __('Transaction Date (Y-m-d)', 'bit-integrations'), required: false }, + { key: 'ref', label: __('Reference', 'bit-integrations'), required: false }, + { key: 'check_no', label: __('Check No', 'bit-integrations'), required: false }, + { key: 'name', label: __('Name', 'bit-integrations'), required: false }, + { key: 'particulars', label: __('Particulars', 'bit-integrations'), required: false }, + { key: 'trn_by', label: __('Transaction By (1=Cash)', 'bit-integrations'), required: false }, + { key: 'ledger_id', label: __('Ledger ID', 'bit-integrations'), required: false } +] + +export const PaymentFields = [ + { key: 'amount', label: __('Amount', 'bit-integrations'), required: true }, + { key: 'customer_id', label: __('Customer ID', 'bit-integrations'), required: false }, + { key: 'trn_date', label: __('Transaction Date (Y-m-d)', 'bit-integrations'), required: false }, + { key: 'particulars', label: __('Particulars', 'bit-integrations'), required: false }, + { key: 'ref', label: __('Reference', 'bit-integrations'), required: false }, + { key: 'deposit_to', label: __('Deposit To', 'bit-integrations'), required: false }, + { key: 'trn_by', label: __('Transaction By (1=Cash)', 'bit-integrations'), required: false } +] diff --git a/frontend/src/components/Flow/New/SelectAction.jsx b/frontend/src/components/Flow/New/SelectAction.jsx index 0ffdaa1aa..b511e3663 100644 --- a/frontend/src/components/Flow/New/SelectAction.jsx +++ b/frontend/src/components/Flow/New/SelectAction.jsx @@ -177,6 +177,7 @@ export default function SelectAction() { { type: 'MailerPress' }, { type: 'CreatorLms' }, { type: 'FluentCart' }, + { type: 'WP ERP', logo: 'wpErp' }, { type: 'PeepSo' }, { type: 'Ninja Tables' }, { type: 'WC Affiliate' }, diff --git a/frontend/src/resource/img/integ/wpErp.webp b/frontend/src/resource/img/integ/wpErp.webp new file mode 100644 index 000000000..22ceefcc9 Binary files /dev/null and b/frontend/src/resource/img/integ/wpErp.webp differ